DPU display port driver is not enabled yet so reverting the driver patch. It will be added back when the driver is reworked and enabled for sdm845 SoC. Signed-off-by: Rajesh Yadav <ryadav@xxxxxxxxxxxxxx> --- drivers/gpu/drm/msm/Makefile | 14 - drivers/gpu/drm/msm/dp/dp_audio.c | 806 ------------------ drivers/gpu/drm/msm/dp/dp_audio.h | 81 -- drivers/gpu/drm/msm/dp/dp_aux.c | 570 ------------- drivers/gpu/drm/msm/dp/dp_aux.h | 44 - drivers/gpu/drm/msm/dp/dp_catalog.c | 1320 ----------------------------- drivers/gpu/drm/msm/dp/dp_catalog.h | 163 ---- drivers/gpu/drm/msm/dp/dp_ctrl.c | 1474 --------------------------------- drivers/gpu/drm/msm/dp/dp_ctrl.h | 50 -- drivers/gpu/drm/msm/dp/dp_debug.c | 503 ------------ drivers/gpu/drm/msm/dp/dp_debug.h | 60 -- drivers/gpu/drm/msm/dp/dp_display.c | 1255 ---------------------------- drivers/gpu/drm/msm/dp/dp_display.h | 52 -- drivers/gpu/drm/msm/dp/dp_drm.c | 538 ------------ drivers/gpu/drm/msm/dp/dp_drm.h | 96 --- drivers/gpu/drm/msm/dp/dp_hdcp2p2.c | 927 --------------------- drivers/gpu/drm/msm/dp/dp_link.c | 1548 ----------------------------------- drivers/gpu/drm/msm/dp/dp_link.h | 184 ----- drivers/gpu/drm/msm/dp/dp_panel.c | 526 ------------ drivers/gpu/drm/msm/dp/dp_panel.h | 115 --- drivers/gpu/drm/msm/dp/dp_parser.c | 645 --------------- drivers/gpu/drm/msm/dp/dp_parser.h | 200 ----- drivers/gpu/drm/msm/dp/dp_power.c | 593 -------------- drivers/gpu/drm/msm/dp/dp_power.h | 56 -- drivers/gpu/drm/msm/dp/dp_reg.h | 231 ------ drivers/gpu/drm/msm/dp/dp_usbpd.c | 491 ----------- drivers/gpu/drm/msm/dp/dp_usbpd.h | 101 --- include/drm/drm_dp_helper.h | 23 - 28 files changed, 12666 deletions(-) delete mode 100644 drivers/gpu/drm/msm/dp/dp_audio.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_audio.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_aux.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_aux.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_catalog.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_ctrl.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_debug.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_debug.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_display.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_display.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_drm.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_drm.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_hdcp2p2.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_link.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_link.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_panel.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_panel.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_parser.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_parser.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_power.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_power.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_reg.h delete mode 100644 drivers/gpu/drm/msm/dp/dp_usbpd.c delete mode 100644 drivers/gpu/drm/msm/dp/dp_usbpd.h diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile index 93a0de5..7fc3974 100644 --- a/drivers/gpu/drm/msm/Makefile +++ b/drivers/gpu/drm/msm/Makefile @@ -99,20 +99,6 @@ msm-y := \ msm-$(CONFIG_DEBUG_FS) += adreno/a5xx_debugfs.o -msm-$(CONFIG_DRM_MSM_DP)+= dp/dp_usbpd.o \ - dp/dp_parser.o \ - dp/dp_power.o \ - dp/dp_catalog.o \ - dp/dp_aux.o \ - dp/dp_panel.o \ - dp/dp_link.o \ - dp/dp_ctrl.o \ - dp/dp_audio.o \ - dp/dp_debug.o \ - dp/dp_display.o \ - dp/dp_drm.o \ - dp/dp_hdcp2p2.o - msm_wb-$(CONFIG_DRM_MSM_WRITEBACK) += disp/dpu1/dpu_wb.o \ disp/dpu1/dpu_encoder_phys_wb.o diff --git a/drivers/gpu/drm/msm/dp/dp_audio.c b/drivers/gpu/drm/msm/dp/dp_audio.c deleted file mode 100644 index ce00b8b..0000000 --- a/drivers/gpu/drm/msm/dp/dp_audio.c +++ /dev/null @@ -1,806 +0,0 @@ -/* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/of_platform.h> -#include <linux/msm_ext_display.h> - -#include <drm/drm_dp_helper.h> -#include <drm/drm_edid.h> - -#include "dp_catalog.h" -#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; - struct dp_catalog_audio *catalog; - struct msm_ext_disp_init_data ext_audio_data; - struct dp_panel *panel; - - bool ack_enabled; - bool session_on; - bool engine_on; - - u32 channels; - - struct completion hpd_comp; - - 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) -{ - catalog->sdp_type = sdp; - catalog->sdp_header = header; - catalog->get_header(catalog); - - return catalog->data; -} - -static void dp_audio_set_header(struct dp_catalog_audio *catalog, - u32 data, - enum dp_catalog_audio_sdp_type sdp, - enum dp_catalog_audio_header_type header) -{ - catalog->sdp_type = sdp; - catalog->sdp_header = header; - catalog->data = data; - catalog->set_header(catalog); -} - -static void dp_audio_stream_sdp(struct dp_audio_private *audio) -{ - struct dp_catalog_audio *catalog = audio->catalog; - u32 value, new_value; - u8 parity_byte; - - /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); - - new_value = 0x02; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_1); - - /* Config header and parity byte 2 */ - 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); - 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_audio_set_header(catalog, value, - DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_2); - - /* Config header and parity byte 3 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); - - new_value = audio->channels - 1; - parity_byte = dp_audio_calculate_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", - value, parity_byte); - - dp_audio_set_header(catalog, value, - DP_AUDIO_SDP_STREAM, DP_AUDIO_SDP_HEADER_3); -} - -static void dp_audio_timestamp_sdp(struct dp_audio_private *audio) -{ - struct dp_catalog_audio *catalog = audio->catalog; - u32 value, new_value; - u8 parity_byte; - - /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); - - new_value = 0x1; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_1); - - /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); - - new_value = 0x17; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_2); - - /* Config header and parity byte 3 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); - - new_value = (0x0 | (0x11 << 2)); - parity_byte = dp_audio_calculate_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", - value, parity_byte); - dp_audio_set_header(catalog, value, - DP_AUDIO_SDP_TIMESTAMP, DP_AUDIO_SDP_HEADER_3); -} - -static void dp_audio_infoframe_sdp(struct dp_audio_private *audio) -{ - struct dp_catalog_audio *catalog = audio->catalog; - u32 value, new_value; - u8 parity_byte; - - /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); - - new_value = 0x84; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_1); - - /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); - - new_value = 0x1b; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_2); - - /* Config header and parity byte 3 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); - - new_value = (0x0 | (0x11 << 2)); - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_INFOFRAME, DP_AUDIO_SDP_HEADER_3); -} - -static void dp_audio_copy_management_sdp(struct dp_audio_private *audio) -{ - struct dp_catalog_audio *catalog = audio->catalog; - u32 value, new_value; - u8 parity_byte; - - /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); - - new_value = 0x05; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_1); - - /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); - - new_value = 0x0F; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_2); - - /* Config header and parity byte 3 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); - - new_value = 0x0; - parity_byte = dp_audio_calculate_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", - value, parity_byte); - dp_audio_set_header(catalog, value, - DP_AUDIO_SDP_COPYMANAGEMENT, DP_AUDIO_SDP_HEADER_3); -} - -static void dp_audio_isrc_sdp(struct dp_audio_private *audio) -{ - struct dp_catalog_audio *catalog = audio->catalog; - u32 value, new_value; - u8 parity_byte; - - /* Config header and parity byte 1 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); - - new_value = 0x06; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_1); - - /* Config header and parity byte 2 */ - value = dp_audio_get_header(catalog, - DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); - - new_value = 0x0F; - parity_byte = dp_audio_calculate_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_audio_set_header(catalog, value, - DP_AUDIO_SDP_ISRC, DP_AUDIO_SDP_HEADER_2); -} - -static void dp_audio_setup_sdp(struct dp_audio_private *audio) -{ - audio->catalog->config_sdp(audio->catalog); - - dp_audio_stream_sdp(audio); - dp_audio_timestamp_sdp(audio); - dp_audio_infoframe_sdp(audio); - dp_audio_copy_management_sdp(audio); - dp_audio_isrc_sdp(audio); -} - -static void dp_audio_setup_acr(struct dp_audio_private *audio) -{ - u32 select = 0; - struct dp_catalog_audio *catalog = audio->catalog; - - switch (audio->dp_audio.bw_code) { - case DP_LINK_BW_1_62: - select = 0; - break; - case DP_LINK_BW_2_7: - select = 1; - break; - case DP_LINK_BW_5_4: - select = 2; - break; - case DP_LINK_BW_8_1: - select = 3; - break; - default: - pr_debug("Unknown link rate\n"); - select = 0; - break; - } - - catalog->data = select; - catalog->config_acr(catalog); -} - -static void dp_audio_safe_to_exit_level(struct dp_audio_private *audio) -{ - struct dp_catalog_audio *catalog = audio->catalog; - u32 safe_to_exit_level = 0; - - switch (audio->dp_audio.lane_count) { - case 1: - safe_to_exit_level = 14; - break; - case 2: - safe_to_exit_level = 8; - break; - case 4: - safe_to_exit_level = 5; - break; - default: - pr_debug("setting the default safe_to_exit_level = %u\n", - safe_to_exit_level); - safe_to_exit_level = 14; - break; - } - - catalog->data = safe_to_exit_level; - catalog->safe_to_exit_level(catalog); -} - -static void dp_audio_enable(struct dp_audio_private *audio, bool enable) -{ - struct dp_catalog_audio *catalog = audio->catalog; - - catalog->data = enable; - catalog->enable(catalog); - - audio->engine_on = enable; -} - -static struct dp_audio_private *get_audio_get_data(struct platform_device *pdev) -{ - struct msm_ext_disp_data *ext_data; - struct dp_audio *dp_audio; - - if (!pdev) { - pr_err("invalid input\n"); - return ERR_PTR(-ENODEV); - } - - ext_data = platform_get_drvdata(pdev); - if (!ext_data) { - pr_err("invalid ext disp data\n"); - return ERR_PTR(-EINVAL); - } - - dp_audio = ext_data->intf_data; - if (!ext_data) { - pr_err("invalid intf data\n"); - return ERR_PTR(-EINVAL); - } - - return container_of(dp_audio, struct dp_audio_private, dp_audio); -} - -static int dp_audio_info_setup(struct platform_device *pdev, - struct msm_ext_disp_audio_setup_params *params) -{ - int rc = 0; - struct dp_audio_private *audio; - - audio = get_audio_get_data(pdev); - if (IS_ERR(audio)) { - rc = PTR_ERR(audio); - goto end; - } - - audio->channels = params->num_of_channels; - - dp_audio_setup_sdp(audio); - dp_audio_setup_acr(audio); - dp_audio_safe_to_exit_level(audio); - dp_audio_enable(audio, true); -end: - return rc; -} - -static int dp_audio_get_edid_blk(struct platform_device *pdev, - struct msm_ext_disp_audio_edid_blk *blk) -{ - int rc = 0; - struct dp_audio_private *audio; - - audio = get_audio_get_data(pdev); - if (IS_ERR(audio)) { - rc = PTR_ERR(audio); - goto end; - } - - if (!audio->panel || !audio->panel->edid) { - pr_err("invalid panel data\n"); - rc = -EINVAL; - goto end; - } - -/* - * TODO: - * audio_data_blk should be changed to be a cea_sad array - * audio_data_blk_size should be changed to contain a count of sads - * - * Once this is done, use drm_edid_to_sad() to extract this from - * audio->panel->edid. I'd change this, but I don't have that code :/ - */ -#if 0 - blk->audio_data_blk = edid->audio_data_block; - blk->audio_data_blk_size = edid->adb_size; -#endif - - blk->spk_alloc_data_blk_size = drm_edid_to_speaker_allocation( - audio->panel->edid, - blk->spkr_alloc_data_block); - -end: - return rc; -} - -static int dp_audio_get_cable_status(struct platform_device *pdev, u32 vote) -{ - int rc = 0; - struct dp_audio_private *audio; - - audio = get_audio_get_data(pdev); - if (IS_ERR(audio)) { - rc = PTR_ERR(audio); - goto end; - } - - if (!audio->panel) { - pr_err("invalid panel data\n"); - rc = -EINVAL; - goto end; - } - - return audio->session_on; -end: - return rc; -} - -static int dp_audio_get_intf_id(struct platform_device *pdev) -{ - int rc = 0; - struct dp_audio_private *audio; - - audio = get_audio_get_data(pdev); - if (IS_ERR(audio)) { - rc = PTR_ERR(audio); - goto end; - } - - return EXT_DISPLAY_TYPE_DP; -end: - return rc; -} - -static void dp_audio_teardown_done(struct platform_device *pdev) -{ - struct dp_audio_private *audio; - - audio = get_audio_get_data(pdev); - if (IS_ERR(audio)) - return; - - if (!audio->panel) { - pr_err("invalid panel data\n"); - return; - } - - dp_audio_enable(audio, false); - - complete_all(&audio->hpd_comp); - - pr_debug("audio engine disabled\n"); -} - -static int dp_audio_ack_done(struct platform_device *pdev, u32 ack) -{ - int rc = 0, ack_hpd; - struct dp_audio_private *audio; - - audio = get_audio_get_data(pdev); - if (IS_ERR(audio)) { - rc = PTR_ERR(audio); - goto end; - } - - if (ack & AUDIO_ACK_SET_ENABLE) { - audio->ack_enabled = ack & AUDIO_ACK_ENABLE ? - true : false; - - pr_debug("audio ack feature %s\n", - audio->ack_enabled ? "enabled" : "disabled"); - goto end; - } - - if (!audio->ack_enabled) - goto end; - - ack_hpd = ack & AUDIO_ACK_CONNECT; - - pr_debug("acknowledging audio (%d)\n", ack_hpd); - - if (!audio->engine_on) - complete_all(&audio->hpd_comp); -end: - return rc; -} - -static int dp_audio_init_ext_disp(struct dp_audio_private *audio) -{ - int rc = 0; - struct device_node *pd = NULL; - const char *phandle = "qcom,ext-disp"; - struct msm_ext_disp_init_data *ext; - struct msm_ext_disp_audio_codec_ops *ops; - - ext = &audio->ext_audio_data; - ops = &ext->codec_ops; - - ext->type = EXT_DISPLAY_TYPE_DP; - ext->pdev = audio->pdev; - ext->intf_data = &audio->dp_audio; - - ops->audio_info_setup = dp_audio_info_setup; - ops->get_audio_edid_blk = dp_audio_get_edid_blk; - ops->cable_status = dp_audio_get_cable_status; - ops->get_intf_id = dp_audio_get_intf_id; - ops->teardown_done = dp_audio_teardown_done; - ops->acknowledge = dp_audio_ack_done; - - if (!audio->pdev->dev.of_node) { - pr_err("cannot find audio dev.of_node\n"); - rc = -ENODEV; - goto end; - } - - pd = of_parse_phandle(audio->pdev->dev.of_node, phandle, 0); - if (!pd) { - pr_err("cannot parse %s handle\n", phandle); - rc = -ENODEV; - goto end; - } - - audio->ext_pdev = of_find_device_by_node(pd); - if (!audio->ext_pdev) { - pr_err("cannot find %s pdev\n", phandle); - rc = -ENODEV; - goto end; - } - - rc = msm_ext_disp_register_intf(audio->ext_pdev, ext); - if (rc) - pr_err("failed to register disp\n"); -end: - if (pd) - of_node_put(pd); - - return rc; -} - -static int dp_audio_on(struct dp_audio *dp_audio) -{ - int rc = 0; - struct dp_audio_private *audio; - struct msm_ext_disp_init_data *ext; - - if (!dp_audio) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - audio = container_of(dp_audio, struct dp_audio_private, dp_audio); - - ext = &audio->ext_audio_data; - - audio->session_on = true; - - rc = ext->intf_ops.audio_config(audio->ext_pdev, - EXT_DISPLAY_TYPE_DP, - EXT_DISPLAY_CABLE_CONNECT); - if (rc) { - pr_err("failed to config audio, err=%d\n", rc); - goto end; - } - - rc = ext->intf_ops.audio_notify(audio->ext_pdev, - EXT_DISPLAY_TYPE_DP, - EXT_DISPLAY_CABLE_CONNECT); - if (rc) { - pr_err("failed to notify audio, err=%d\n", rc); - goto end; - } - - reinit_completion(&audio->hpd_comp); - rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5); - if (!rc) { - pr_err("timeout\n"); - rc = -ETIMEDOUT; - goto end; - } - - pr_debug("success\n"); -end: - return rc; -} - -static int dp_audio_off(struct dp_audio *dp_audio) -{ - int rc = 0; - struct dp_audio_private *audio; - struct msm_ext_disp_init_data *ext; - - if (!dp_audio) { - pr_err("invalid input\n"); - return -EINVAL; - } - - audio = container_of(dp_audio, struct dp_audio_private, dp_audio); - ext = &audio->ext_audio_data; - - rc = ext->intf_ops.audio_notify(audio->ext_pdev, - EXT_DISPLAY_TYPE_DP, - EXT_DISPLAY_CABLE_DISCONNECT); - if (rc) { - pr_err("failed to notify audio, err=%d\n", rc); - goto end; - } - - reinit_completion(&audio->hpd_comp); - rc = wait_for_completion_timeout(&audio->hpd_comp, HZ * 5); - if (!rc) { - pr_err("timeout\n"); - rc = -ETIMEDOUT; - goto end; - } - - pr_debug("success\n"); -end: - rc = ext->intf_ops.audio_config(audio->ext_pdev, - EXT_DISPLAY_TYPE_DP, - EXT_DISPLAY_CABLE_DISCONNECT); - if (rc) - pr_err("failed to config audio, err=%d\n", rc); - - audio->session_on = false; - audio->engine_on = false; - - return rc; -} - -struct dp_audio *dp_audio_get(struct platform_device *pdev, - struct dp_panel *panel, - struct dp_catalog_audio *catalog) -{ - int rc = 0; - struct dp_audio_private *audio; - struct dp_audio *dp_audio; - - if (!pdev || !panel || !catalog) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - audio = devm_kzalloc(&pdev->dev, sizeof(*audio), GFP_KERNEL); - if (!audio) { - rc = -ENOMEM; - goto error; - } - - init_completion(&audio->hpd_comp); - - audio->pdev = pdev; - audio->panel = panel; - audio->catalog = catalog; - - dp_audio = &audio->dp_audio; - - dp_audio->on = dp_audio_on; - dp_audio->off = dp_audio_off; - - rc = dp_audio_init_ext_disp(audio); - if (rc) { - devm_kfree(&pdev->dev, audio); - goto error; - } - - catalog->init(catalog); - - return dp_audio; -error: - return ERR_PTR(rc); -} - -void dp_audio_put(struct dp_audio *dp_audio) -{ - struct dp_audio_private *audio; - - if (!dp_audio) - return; - - audio = container_of(dp_audio, struct dp_audio_private, dp_audio); - - devm_kfree(&audio->pdev->dev, audio); -} diff --git a/drivers/gpu/drm/msm/dp/dp_audio.h b/drivers/gpu/drm/msm/dp/dp_audio.h deleted file mode 100644 index 9e7fa16..0000000 --- a/drivers/gpu/drm/msm/dp/dp_audio.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_AUDIO_H_ -#define _DP_AUDIO_H_ - -#include <linux/platform_device.h> - -#include "dp_panel.h" -#include "dp_catalog.h" - -/** - * struct dp_audio - * @lane_count: number of lanes configured in current session - * @bw_code: link rate's bandwidth code for current session - */ -struct dp_audio { - u32 lane_count; - u32 bw_code; - - /** - * on() - * - * Enables the audio by notifying the user module. - * - * @dp_audio: an instance of struct dp_audio. - * - * Returns the error code in case of failure, 0 in success case. - */ - int (*on)(struct dp_audio *dp_audio); - - /** - * off() - * - * Disables the audio by notifying the user module. - * - * @dp_audio: an instance of struct dp_audio. - * - * Returns the error code in case of failure, 0 in success case. - */ - int (*off)(struct dp_audio *dp_audio); -}; - -/** - * dp_audio_get() - * - * Creates and instance of dp audio. - * - * @pdev: caller's platform device instance. - * @panel: an instance of dp_panel module. - * @catalog: an instance of dp_catalog_audio module. - * - * Returns the error code in case of failure, otherwize - * an instance of newly created dp_module. - */ -struct dp_audio *dp_audio_get(struct platform_device *pdev, - struct dp_panel *panel, - struct dp_catalog_audio *catalog); - -/** - * dp_audio_put() - * - * Cleans the dp_audio instance. - * - * @dp_audio: an instance of dp_audio. - */ -void dp_audio_put(struct dp_audio *dp_audio); -#endif /* _DP_AUDIO_H_ */ - - diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c deleted file mode 100644 index 75ac98b..0000000 --- a/drivers/gpu/drm/msm/dp/dp_aux.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/delay.h> - -#include "dp_aux.h" - -#define DP_AUX_ENUM_STR(x) #x - -enum { - DP_AUX_DATA_INDEX_WRITE = BIT(31), -}; - -struct dp_aux_private { - struct device *dev; - struct dp_aux dp_aux; - struct dp_catalog_aux *catalog; - struct dp_aux_cfg *cfg; - - struct mutex mutex; - struct completion comp; - - u32 aux_error_num; - u32 retry_cnt; - bool cmd_busy; - bool native; - bool read; - bool no_send_addr; - bool no_send_stop; - u32 offset; - u32 segment; - - struct drm_dp_aux drm_aux; -}; - -static char *dp_aux_get_error(u32 aux_error) -{ - switch (aux_error) { - case DP_AUX_ERR_NONE: - return DP_AUX_ENUM_STR(DP_AUX_ERR_NONE); - case DP_AUX_ERR_ADDR: - return DP_AUX_ENUM_STR(DP_AUX_ERR_ADDR); - case DP_AUX_ERR_TOUT: - return DP_AUX_ENUM_STR(DP_AUX_ERR_TOUT); - case DP_AUX_ERR_NACK: - return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK); - case DP_AUX_ERR_DEFER: - return DP_AUX_ENUM_STR(DP_AUX_ERR_DEFER); - case DP_AUX_ERR_NACK_DEFER: - return DP_AUX_ENUM_STR(DP_AUX_ERR_NACK_DEFER); - default: - return "unknown"; - } -} - -static u32 dp_aux_write(struct dp_aux_private *aux, - struct drm_dp_aux_msg *msg) -{ - u32 data[4], reg, len; - u8 *msgdata = msg->buffer; - int const aux_cmd_fifo_len = 128; - int i = 0; - - if (aux->read) - len = 4; - else - len = msg->size + 4; - - /* - * cmd fifo only has depth of 144 bytes - * limit buf length to 128 bytes here - */ - if (len > aux_cmd_fifo_len) { - pr_err("buf len error\n"); - return 0; - } - - /* Pack cmd and write to HW */ - data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */ - if (aux->read) - data[0] |= BIT(4); /* R/W */ - - data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */ - data[2] = msg->address & 0xff; /* addr[7:0] */ - data[3] = (msg->size - 1) & 0xff; /* len[7:0] */ - - for (i = 0; i < len; i++) { - reg = (i < 4) ? data[i] : msgdata[i - 4]; - reg = ((reg) << 8) & 0x0000ff00; /* index = 0, write */ - if (i == 0) - reg |= DP_AUX_DATA_INDEX_WRITE; - aux->catalog->data = reg; - aux->catalog->write_data(aux->catalog); - } - - aux->catalog->clear_trans(aux->catalog, false); - - reg = 0; /* Transaction number == 1 */ - if (!aux->native) { /* i2c */ - reg |= BIT(8); - - if (aux->no_send_addr) - reg |= BIT(10); - - if (aux->no_send_stop) - reg |= BIT(11); - } - - reg |= BIT(9); - aux->catalog->data = reg; - aux->catalog->write_trans(aux->catalog); - - return len; -} - -static int dp_aux_cmd_fifo_tx(struct dp_aux_private *aux, - struct drm_dp_aux_msg *msg) -{ - u32 ret = 0, len = 0, timeout; - int const aux_timeout_ms = HZ/4; - - reinit_completion(&aux->comp); - - len = dp_aux_write(aux, msg); - if (len == 0) { - pr_err("DP AUX write failed\n"); - return -EINVAL; - } - - timeout = wait_for_completion_timeout(&aux->comp, aux_timeout_ms); - if (!timeout) { - pr_err("aux %s timeout\n", (aux->read ? "read" : "write")); - return -ETIMEDOUT; - } - - if (aux->aux_error_num == DP_AUX_ERR_NONE) { - ret = len; - } else { - pr_err_ratelimited("aux err: %s\n", - dp_aux_get_error(aux->aux_error_num)); - - ret = -EINVAL; - } - - return ret; -} - -static void dp_aux_cmd_fifo_rx(struct dp_aux_private *aux, - struct drm_dp_aux_msg *msg) -{ - u32 data; - u8 *dp; - u32 i, actual_i; - u32 len = msg->size; - - aux->catalog->clear_trans(aux->catalog, true); - - data = 0; - data |= DP_AUX_DATA_INDEX_WRITE; /* INDEX_WRITE */ - data |= BIT(0); /* read */ - - aux->catalog->data = data; - aux->catalog->write_data(aux->catalog); - - dp = msg->buffer; - - /* discard first byte */ - data = aux->catalog->read_data(aux->catalog); - - for (i = 0; i < len; i++) { - data = aux->catalog->read_data(aux->catalog); - *dp++ = (u8)((data >> 8) & 0xff); - - actual_i = (data >> 16) & 0xFF; - if (i != actual_i) - pr_warn("Index mismatch: expected %d, found %d\n", - i, actual_i); - } -} - -static void dp_aux_native_handler(struct dp_aux_private *aux) -{ - u32 isr = aux->catalog->isr; - - if (isr & DP_INTR_AUX_I2C_DONE) - aux->aux_error_num = DP_AUX_ERR_NONE; - else if (isr & DP_INTR_WRONG_ADDR) - aux->aux_error_num = DP_AUX_ERR_ADDR; - else if (isr & DP_INTR_TIMEOUT) - aux->aux_error_num = DP_AUX_ERR_TOUT; - if (isr & DP_INTR_NACK_DEFER) - aux->aux_error_num = DP_AUX_ERR_NACK; - - complete(&aux->comp); -} - -static void dp_aux_i2c_handler(struct dp_aux_private *aux) -{ - u32 isr = aux->catalog->isr; - - if (isr & DP_INTR_AUX_I2C_DONE) { - if (isr & (DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER)) - aux->aux_error_num = DP_AUX_ERR_NACK; - else - aux->aux_error_num = DP_AUX_ERR_NONE; - } else { - if (isr & DP_INTR_WRONG_ADDR) - aux->aux_error_num = DP_AUX_ERR_ADDR; - else if (isr & DP_INTR_TIMEOUT) - aux->aux_error_num = DP_AUX_ERR_TOUT; - if (isr & DP_INTR_NACK_DEFER) - aux->aux_error_num = DP_AUX_ERR_NACK_DEFER; - if (isr & DP_INTR_I2C_NACK) - aux->aux_error_num = DP_AUX_ERR_NACK; - if (isr & DP_INTR_I2C_DEFER) - aux->aux_error_num = DP_AUX_ERR_DEFER; - } - - complete(&aux->comp); -} - -static void dp_aux_isr(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); - - aux->catalog->get_irq(aux->catalog, aux->cmd_busy); - - if (!aux->cmd_busy) - return; - - if (aux->native) - dp_aux_native_handler(aux); - else - dp_aux_i2c_handler(aux); -} - -static void dp_aux_reconfig(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); - - aux->catalog->update_aux_cfg(aux->catalog, - aux->cfg, PHY_AUX_CFG1); - aux->catalog->reset(aux->catalog); -} - -static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux, - struct drm_dp_aux_msg *input_msg) -{ - u32 const edid_address = 0x50; - u32 const segment_address = 0x30; - bool i2c_read = input_msg->request & - (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); - u8 *data = NULL; - - if (aux->native || i2c_read || ((input_msg->address != edid_address) && - (input_msg->address != segment_address))) - return; - - - data = input_msg->buffer; - if (input_msg->address == segment_address) - aux->segment = *data; - else - aux->offset = *data; -} - -/** - * dp_aux_transfer_helper() - helper function for EDID read transactions - * - * @aux: DP AUX private structure - * @input_msg: input message from DRM upstream APIs - * - * return: void - * - * This helper function is used to fix EDID reads for non-compliant - * sinks that do not handle the i2c middle-of-transaction flag correctly. - */ -static void dp_aux_transfer_helper(struct dp_aux_private *aux, - struct drm_dp_aux_msg *input_msg) -{ - struct drm_dp_aux_msg helper_msg; - u32 const message_size = 0x10; - u32 const segment_address = 0x30; - bool i2c_mot = input_msg->request & DP_AUX_I2C_MOT; - bool i2c_read = input_msg->request & - (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); - - if (!i2c_mot || !i2c_read || (input_msg->size == 0)) - return; - - aux->read = false; - aux->cmd_busy = true; - aux->no_send_addr = true; - aux->no_send_stop = true; - - /* - * Send the segment address for every i2c read in which the - * middle-of-tranaction flag is set. This is required to support EDID - * reads of more than 2 blocks as the segment address is reset to 0 - * since we are overriding the middle-of-transaction flag for read - * transactions. - */ - memset(&helper_msg, 0, sizeof(helper_msg)); - helper_msg.address = segment_address; - helper_msg.buffer = &aux->segment; - helper_msg.size = 1; - dp_aux_cmd_fifo_tx(aux, &helper_msg); - - /* - * Send the offset address for every i2c read in which the - * middle-of-transaction flag is set. This will ensure that the sink - * will update its read pointer and return the correct portion of the - * EDID buffer in the subsequent i2c read trasntion triggered in the - * native AUX transfer function. - */ - memset(&helper_msg, 0, sizeof(helper_msg)); - helper_msg.address = input_msg->address; - helper_msg.buffer = &aux->offset; - helper_msg.size = 1; - dp_aux_cmd_fifo_tx(aux, &helper_msg); - aux->offset += message_size; - - if (aux->offset == 0x80 || aux->offset == 0x100) - aux->segment = 0x0; /* reset segment at end of block */ -} - -/* - * This function does the real job to process an AUX transaction. - * It will call aux_reset() function to reset the AUX channel, - * if the waiting is timeout. - */ -static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux, - struct drm_dp_aux_msg *msg) -{ - ssize_t ret; - int const aux_cmd_native_max = 16; - int const aux_cmd_i2c_max = 128; - int const retry_count = 5; - struct dp_aux_private *aux = container_of(drm_aux, - struct dp_aux_private, drm_aux); - - mutex_lock(&aux->mutex); - - aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ); - - /* Ignore address only message */ - if ((msg->size == 0) || (msg->buffer == NULL)) { - msg->reply = aux->native ? - DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; - ret = msg->size; - goto unlock_exit; - } - - /* msg sanity check */ - if ((aux->native && (msg->size > aux_cmd_native_max)) || - (msg->size > aux_cmd_i2c_max)) { - pr_err("%s: invalid msg: size(%zu), request(%x)\n", - __func__, msg->size, msg->request); - ret = -EINVAL; - goto unlock_exit; - } - - dp_aux_update_offset_and_segment(aux, msg); - dp_aux_transfer_helper(aux, msg); - - aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ); - aux->cmd_busy = true; - - if (aux->read) { - aux->no_send_addr = true; - aux->no_send_stop = false; - } else { - aux->no_send_addr = true; - aux->no_send_stop = true; - } - - ret = dp_aux_cmd_fifo_tx(aux, msg); - if ((ret < 0) && aux->native) { - aux->retry_cnt++; - if (!(aux->retry_cnt % retry_count)) - aux->catalog->update_aux_cfg(aux->catalog, - aux->cfg, PHY_AUX_CFG1); - aux->catalog->reset(aux->catalog); - goto unlock_exit; - } else if (ret < 0) { - goto unlock_exit; - } - - if (aux->aux_error_num == DP_AUX_ERR_NONE) { - if (aux->read) - dp_aux_cmd_fifo_rx(aux, msg); - - msg->reply = aux->native ? - DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK; - } else { - /* Reply defer to retry */ - msg->reply = aux->native ? - DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER; - } - - /* Return requested size for success or retry */ - ret = msg->size; - aux->retry_cnt = 0; - -unlock_exit: - aux->cmd_busy = false; - mutex_unlock(&aux->mutex); - return ret; -} - -static void dp_aux_reset_phy_config_indices(struct dp_aux_cfg *aux_cfg) -{ - int i = 0; - - for (i = 0; i < PHY_AUX_CFG_MAX; i++) - aux_cfg[i].current_index = 0; -} - -static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg) -{ - struct dp_aux_private *aux; - - if (!dp_aux || !aux_cfg) { - pr_err("invalid input\n"); - return; - } - - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); - - aux->catalog->reset(aux->catalog); - aux->catalog->enable(aux->catalog, true); - aux->retry_cnt = 0; - dp_aux_reset_phy_config_indices(aux_cfg); - aux->catalog->setup(aux->catalog, aux_cfg); -} - -static void dp_aux_deinit(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); - - aux->catalog->enable(aux->catalog, false); -} - -static int dp_aux_register(struct dp_aux *dp_aux) -{ - struct dp_aux_private *aux; - int ret = 0; - - if (!dp_aux) { - pr_err("invalid input\n"); - ret = -EINVAL; - goto exit; - } - - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); - - aux->drm_aux.name = "dpu_dp_aux"; - aux->drm_aux.dev = aux->dev; - aux->drm_aux.transfer = dp_aux_transfer; - ret = drm_dp_aux_register(&aux->drm_aux); - if (ret) { - pr_err("%s: failed to register drm aux: %d\n", __func__, ret); - goto exit; - } - dp_aux->drm_aux = &aux->drm_aux; -exit: - return ret; -} - -static void dp_aux_deregister(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); - drm_dp_aux_unregister(&aux->drm_aux); -} - -struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, - struct dp_aux_cfg *aux_cfg) -{ - int rc = 0; - struct dp_aux_private *aux; - struct dp_aux *dp_aux; - - if (!catalog || !aux_cfg) { - pr_err("invalid input\n"); - rc = -ENODEV; - goto error; - } - - aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL); - if (!aux) { - rc = -ENOMEM; - goto error; - } - - init_completion(&aux->comp); - aux->cmd_busy = false; - mutex_init(&aux->mutex); - - aux->dev = dev; - aux->catalog = catalog; - aux->cfg = aux_cfg; - dp_aux = &aux->dp_aux; - aux->retry_cnt = 0; - - dp_aux->isr = dp_aux_isr; - dp_aux->init = dp_aux_init; - dp_aux->deinit = dp_aux_deinit; - dp_aux->drm_aux_register = dp_aux_register; - dp_aux->drm_aux_deregister = dp_aux_deregister; - dp_aux->reconfig = dp_aux_reconfig; - - return dp_aux; -error: - return ERR_PTR(rc); -} - -void dp_aux_put(struct dp_aux *dp_aux) -{ - struct dp_aux_private *aux; - - if (!dp_aux) - return; - - aux = container_of(dp_aux, struct dp_aux_private, dp_aux); - - mutex_destroy(&aux->mutex); - - devm_kfree(aux->dev, aux); -} diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h deleted file mode 100644 index f5277c5..0000000 --- a/drivers/gpu/drm/msm/dp/dp_aux.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_AUX_H_ -#define _DP_AUX_H_ - -#include "dp_catalog.h" -#include <drm/drm_dp_helper.h> - -enum dp_aux_error { - DP_AUX_ERR_NONE = 0, - DP_AUX_ERR_ADDR = -1, - DP_AUX_ERR_TOUT = -2, - DP_AUX_ERR_NACK = -3, - DP_AUX_ERR_DEFER = -4, - DP_AUX_ERR_NACK_DEFER = -5, -}; - -struct dp_aux { - struct drm_dp_aux *drm_aux; - int (*drm_aux_register)(struct dp_aux *aux); - void (*drm_aux_deregister)(struct dp_aux *aux); - void (*isr)(struct dp_aux *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); -}; - -struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, - struct dp_aux_cfg *aux_cfg); -void dp_aux_put(struct dp_aux *aux); - -#endif /*__DP_AUX_H_*/ diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.c b/drivers/gpu/drm/msm/dp/dp_catalog.c deleted file mode 100644 index 8421a12..0000000 --- a/drivers/gpu/drm/msm/dp/dp_catalog.c +++ /dev/null @@ -1,1320 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/delay.h> -#include <drm/drm_dp_helper.h> - -#include "dp_catalog.h" -#include "dp_reg.h" - -#define DP_GET_MSB(x) (x >> 8) -#define DP_GET_LSB(x) (x & 0xff) - -#define dp_read(offset) readl_relaxed((offset)) -#define dp_write(offset, data) writel_relaxed((data), (offset)) - -#define dp_catalog_get_priv(x) { \ - struct dp_catalog *dp_catalog; \ - dp_catalog = container_of(x, struct dp_catalog, x); \ - catalog = container_of(dp_catalog, struct dp_catalog_private, \ - dp_catalog); \ -} - -#define DP_INTERRUPT_STATUS1 \ - (DP_INTR_AUX_I2C_DONE| \ - DP_INTR_WRONG_ADDR | DP_INTR_TIMEOUT | \ - DP_INTR_NACK_DEFER | DP_INTR_WRONG_DATA_CNT | \ - DP_INTR_I2C_NACK | DP_INTR_I2C_DEFER | \ - DP_INTR_PLL_UNLOCKED | DP_INTR_AUX_ERROR) - -#define DP_INTR_MASK1 (DP_INTERRUPT_STATUS1 << 2) - -#define DP_INTERRUPT_STATUS2 \ - (DP_INTR_READY_FOR_VIDEO | DP_INTR_IDLE_PATTERN_SENT | \ - DP_INTR_FRAME_END | DP_INTR_CRC_UPDATED) - -#define DP_INTR_MASK2 (DP_INTERRUPT_STATUS2 << 2) - -static u8 const vm_pre_emphasis[4][4] = { - {0x00, 0x0B, 0x12, 0xFF}, /* pe0, 0 db */ - {0x00, 0x0A, 0x12, 0xFF}, /* pe1, 3.5 db */ - {0x00, 0x0C, 0xFF, 0xFF}, /* pe2, 6.0 db */ - {0xFF, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */ -}; - -/* voltage swing, 0.2v and 1.0v are not support */ -static u8 const vm_voltage_swing[4][4] = { - {0x07, 0x0F, 0x14, 0xFF}, /* sw0, 0.4v */ - {0x11, 0x1D, 0x1F, 0xFF}, /* sw1, 0.6 v */ - {0x18, 0x1F, 0xFF, 0xFF}, /* sw1, 0.8 v */ - {0xFF, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */ -}; - -/* audio related catalog functions */ -struct dp_catalog_private { - struct device *dev; - struct dp_io *io; - - u32 (*audio_map)[DP_AUDIO_SDP_HEADER_MAX]; - struct dp_catalog dp_catalog; -}; - -/* aux related catalog functions */ -static u32 dp_catalog_aux_read_data(struct dp_catalog_aux *aux) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!aux) { - pr_err("invalid input\n"); - goto end; - } - - dp_catalog_get_priv(aux); - base = catalog->io->ctrl_io.base; - - return dp_read(base + DP_AUX_DATA); -end: - return 0; -} - -static int dp_catalog_aux_write_data(struct dp_catalog_aux *aux) -{ - int rc = 0; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!aux) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - dp_catalog_get_priv(aux); - base = catalog->io->ctrl_io.base; - - dp_write(base + DP_AUX_DATA, aux->data); -end: - return rc; -} - -static int dp_catalog_aux_write_trans(struct dp_catalog_aux *aux) -{ - int rc = 0; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!aux) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - dp_catalog_get_priv(aux); - base = catalog->io->ctrl_io.base; - - dp_write(base + DP_AUX_TRANS_CTRL, aux->data); -end: - return rc; -} - -static int dp_catalog_aux_clear_trans(struct dp_catalog_aux *aux, bool read) -{ - int rc = 0; - u32 data = 0; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!aux) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - dp_catalog_get_priv(aux); - base = catalog->io->ctrl_io.base; - - if (read) { - data = dp_read(base + DP_AUX_TRANS_CTRL); - data &= ~BIT(9); - dp_write(base + DP_AUX_TRANS_CTRL, data); - } else { - dp_write(base + DP_AUX_TRANS_CTRL, 0); - } -end: - return rc; -} - -static void dp_catalog_aux_reset(struct dp_catalog_aux *aux) -{ - u32 aux_ctrl; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!aux) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(aux); - base = catalog->io->ctrl_io.base; - - aux_ctrl = dp_read(base + DP_AUX_CTRL); - - aux_ctrl |= BIT(1); - dp_write(base + DP_AUX_CTRL, aux_ctrl); - usleep_range(1000, 1010); /* h/w recommended delay */ - - aux_ctrl &= ~BIT(1); - dp_write(base + DP_AUX_CTRL, aux_ctrl); -} - -static void dp_catalog_aux_enable(struct dp_catalog_aux *aux, bool enable) -{ - u32 aux_ctrl; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!aux) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(aux); - base = catalog->io->ctrl_io.base; - - aux_ctrl = dp_read(base + DP_AUX_CTRL); - - if (enable) { - dp_write(base + DP_TIMEOUT_COUNT, 0xffff); - dp_write(base + DP_AUX_LIMITS, 0xffff); - aux_ctrl |= BIT(0); - } else { - aux_ctrl &= ~BIT(0); - } - - dp_write(base + DP_AUX_CTRL, aux_ctrl); -} - -static void dp_catalog_aux_update_cfg(struct dp_catalog_aux *aux, - struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type) -{ - struct dp_catalog_private *catalog; - u32 new_index = 0, current_index = 0; - - if (!aux || !cfg || (type >= PHY_AUX_CFG_MAX)) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(aux); - - current_index = cfg[type].current_index; - new_index = (current_index + 1) % cfg[type].cfg_cnt; - pr_debug("Updating %s from 0x%08x to 0x%08x\n", - dp_phy_aux_config_type_to_string(type), - cfg[type].lut[current_index], cfg[type].lut[new_index]); - - dp_write(catalog->io->phy_io.base + cfg[type].offset, - cfg[type].lut[new_index]); - cfg[type].current_index = new_index; -} - -static void dp_catalog_aux_setup(struct dp_catalog_aux *aux, - struct dp_aux_cfg *cfg) -{ - struct dp_catalog_private *catalog; - int i = 0; - - if (!aux || !cfg) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(aux); - - dp_write(catalog->io->phy_io.base + DP_PHY_PD_CTL, 0x65); - wmb(); /* make sure PD programming happened */ - - /* Turn on BIAS current for PHY/PLL */ - dp_write(catalog->io->dp_pll_io.base + - QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x1b); - - /* DP AUX CFG register programming */ - for (i = 0; i < PHY_AUX_CFG_MAX; i++) { - pr_debug("%s: offset=0x%08x, value=0x%08x\n", - dp_phy_aux_config_type_to_string(i), - cfg[i].offset, cfg[i].lut[cfg[i].current_index]); - dp_write(catalog->io->phy_io.base + cfg[i].offset, - cfg[i].lut[cfg[i].current_index]); - } - - dp_write(catalog->io->phy_io.base + DP_PHY_AUX_INTERRUPT_MASK, 0x1F); -} - -static void dp_catalog_aux_get_irq(struct dp_catalog_aux *aux, bool cmd_busy) -{ - u32 ack; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!aux) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(aux); - base = catalog->io->ctrl_io.base; - - aux->isr = dp_read(base + DP_INTR_STATUS); - aux->isr &= ~DP_INTR_MASK1; - ack = aux->isr & DP_INTERRUPT_STATUS1; - ack <<= 1; - ack |= DP_INTR_MASK1; - dp_write(base + DP_INTR_STATUS, ack); -} - -/* controller related catalog functions */ -static u32 dp_catalog_ctrl_read_hdcp_status(struct dp_catalog_ctrl *ctrl) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return -EINVAL; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - return dp_read(base + DP_HDCP_STATUS); -} - -static void dp_catalog_ctrl_setup_infoframe_sdp(struct dp_catalog_ctrl *ctrl) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - u32 header, data; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - header = dp_read(base + MMSS_DP_VSCEXT_0); - header |= ctrl->hdr_data.vsc_hdr_byte1; - dp_write(base + MMSS_DP_VSCEXT_0, header); - - header = dp_read(base + MMSS_DP_VSCEXT_1); - header |= ctrl->hdr_data.vsc_hdr_byte1; - dp_write(base + MMSS_DP_VSCEXT_1, header); - - header = dp_read(base + MMSS_DP_VSCEXT_1); - header |= ctrl->hdr_data.vsc_hdr_byte1; - dp_write(base + MMSS_DP_VSCEXT_1, header); - - header = ctrl->hdr_data.version; - header |= ctrl->hdr_data.length << 8; - header |= ctrl->hdr_data.eotf << 16; - header |= (ctrl->hdr_data.descriptor_id << 24); - dp_write(base + MMSS_DP_VSCEXT_2, header); - - data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[0]) | - (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[0]) << 8) | - (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[0]) << 16) | - (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[0]) << 24)); - dp_write(base + MMSS_DP_VSCEXT_3, data); - - data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[1]) | - (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[1]) << 8) | - (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[1]) << 16) | - (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[1]) << 24)); - dp_write(base + MMSS_DP_VSCEXT_4, data); - - data = (DP_GET_LSB(ctrl->hdr_data.display_primaries_x[2]) | - (DP_GET_MSB(ctrl->hdr_data.display_primaries_x[2]) << 8) | - (DP_GET_LSB(ctrl->hdr_data.display_primaries_y[2]) << 16) | - (DP_GET_MSB(ctrl->hdr_data.display_primaries_y[2]) << 24)); - dp_write(base + MMSS_DP_VSCEXT_5, data); - - data = (DP_GET_LSB(ctrl->hdr_data.white_point_x) | - (DP_GET_MSB(ctrl->hdr_data.white_point_x) << 8) | - (DP_GET_LSB(ctrl->hdr_data.white_point_y) << 16) | - (DP_GET_MSB(ctrl->hdr_data.white_point_y) << 24)); - dp_write(base + MMSS_DP_VSCEXT_6, data); - - data = (DP_GET_LSB(ctrl->hdr_data.max_luminance) | - (DP_GET_MSB(ctrl->hdr_data.max_luminance) << 8) | - (DP_GET_LSB(ctrl->hdr_data.min_luminance) << 16) | - (DP_GET_MSB(ctrl->hdr_data.min_luminance) << 24)); - dp_write(base + MMSS_DP_VSCEXT_7, data); - - data = (DP_GET_LSB(ctrl->hdr_data.max_content_light_level) | - (DP_GET_MSB(ctrl->hdr_data.max_content_light_level) << 8) | - (DP_GET_LSB(ctrl->hdr_data.max_average_light_level) << 16) | - (DP_GET_MSB(ctrl->hdr_data.max_average_light_level) << 24)); - dp_write(base + MMSS_DP_VSCEXT_8, data); - - dp_write(base + MMSS_DP_VSCEXT_9, 0x00); -} - -static void dp_catalog_ctrl_setup_vsc_sdp(struct dp_catalog_ctrl *ctrl) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - u32 value; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - value = dp_read(base + MMSS_DP_GENERIC0_0); - value |= ctrl->hdr_data.vsc_hdr_byte1; - dp_write(base + MMSS_DP_GENERIC0_0, value); - - value = dp_read(base + MMSS_DP_GENERIC0_1); - value |= ctrl->hdr_data.vsc_hdr_byte2; - dp_write(base + MMSS_DP_GENERIC0_1, value); - - value = dp_read(base + MMSS_DP_GENERIC0_1); - value |= ctrl->hdr_data.vsc_hdr_byte3; - dp_write(base + MMSS_DP_GENERIC0_1, value); - - 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); - - dp_write(base + MMSS_DP_GENERIC0_6, ctrl->hdr_data.pkt_payload); - dp_write(base + MMSS_DP_GENERIC0_7, 0x00); - dp_write(base + MMSS_DP_GENERIC0_8, 0x00); - dp_write(base + MMSS_DP_GENERIC0_9, 0x00); -} - -static void dp_catalog_ctrl_config_hdr(struct dp_catalog_ctrl *ctrl) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - u32 cfg, cfg2; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - cfg = dp_read(base + MMSS_DP_SDP_CFG); - /* VSCEXT_SDP_EN */ - cfg |= BIT(16); - - /* GEN0_SDP_EN */ - cfg |= BIT(17); - - 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); - dp_write(base + MMSS_DP_SDP_CFG2, cfg2); - - dp_catalog_ctrl_setup_vsc_sdp(ctrl); - dp_catalog_ctrl_setup_infoframe_sdp(ctrl); - - cfg = dp_read(base + DP_MISC1_MISC0); - /* Indicates presence of VSC */ - cfg |= BIT(6) << 8; - - dp_write(base + DP_MISC1_MISC0, cfg); - - cfg = dp_read(base + DP_CONFIGURATION_CTRL); - /* Send VSC */ - cfg |= BIT(7); - - switch (ctrl->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); -} - -static void dp_catalog_ctrl_update_transfer_unit(struct dp_catalog_ctrl *ctrl) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - dp_write(base + DP_VALID_BOUNDARY, ctrl->valid_boundary); - dp_write(base + DP_TU, ctrl->dp_tu); - dp_write(base + DP_VALID_BOUNDARY_2, ctrl->valid_boundary2); -} - -static void dp_catalog_ctrl_state_ctrl(struct dp_catalog_ctrl *ctrl, u32 state) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - dp_write(base + DP_STATE_CTRL, state); -} - -static void dp_catalog_ctrl_config_ctrl(struct dp_catalog_ctrl *ctrl, u32 cfg) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - pr_debug("DP_CONFIGURATION_CTRL=0x%x\n", cfg); - - dp_write(base + DP_CONFIGURATION_CTRL, cfg); - dp_write(base + DP_MAINLINK_LEVELS, 0xa08); - dp_write(base + MMSS_DP_ASYNC_FIFO_CONFIG, 0x1); -} - -static void dp_catalog_ctrl_lane_mapping(struct dp_catalog_ctrl *ctrl) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - dp_write(base + DP_LOGICAL2PHYSCIAL_LANE_MAPPING, 0xe4); -} - -static void dp_catalog_ctrl_mainlink_ctrl(struct dp_catalog_ctrl *ctrl, - bool enable) -{ - u32 mainlink_ctrl; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - if (enable) { - dp_write(base + DP_MAINLINK_CTRL, 0x02000000); - wmb(); /* make sure mainlink is turned off before reset */ - dp_write(base + DP_MAINLINK_CTRL, 0x02000002); - wmb(); /* make sure mainlink entered reset */ - dp_write(base + DP_MAINLINK_CTRL, 0x02000000); - wmb(); /* make sure mainlink reset done */ - dp_write(base + DP_MAINLINK_CTRL, 0x02000001); - wmb(); /* make sure mainlink turned on */ - } else { - mainlink_ctrl = dp_read(base + DP_MAINLINK_CTRL); - mainlink_ctrl &= ~BIT(0); - dp_write(base + DP_MAINLINK_CTRL, mainlink_ctrl); - } -} - -static void dp_catalog_ctrl_config_misc(struct dp_catalog_ctrl *ctrl, - u32 cc, u32 tb) -{ - u32 misc_val; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - misc_val = dp_read(base + DP_MISC1_MISC0); - misc_val |= cc; - misc_val |= (tb << 5); - misc_val |= BIT(0); /* Configure clock to synchronous mode */ - - pr_debug("misc settings = 0x%x\n", misc_val); - dp_write(base + DP_MISC1_MISC0, misc_val); -} - -static void dp_catalog_ctrl_config_msa(struct dp_catalog_ctrl *ctrl, - u32 rate, u32 stream_rate_khz, - bool fixed_nvid) -{ - u32 pixel_m, pixel_n; - u32 mvid, nvid; - u64 mvid_calc; - u32 const nvid_fixed = 0x8000; - u32 const link_rate_hbr2 = 540000; - u32 const link_rate_hbr3 = 810000; - struct dp_catalog_private *catalog; - void __iomem *base_cc, *base_ctrl; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - if (fixed_nvid) { - pr_debug("use fixed NVID=0x%x\n", nvid_fixed); - nvid = nvid_fixed; - - pr_debug("link rate=%dkbps, stream_rate_khz=%uKhz", - rate, stream_rate_khz); - - /* - * For intermediate results, use 64 bit arithmetic to avoid - * loss of precision. - */ - mvid_calc = (u64) stream_rate_khz * nvid; - mvid_calc = div_u64(mvid_calc, rate); - - /* - * truncate back to 32 bits as this final divided value will - * always be within the range of a 32 bit unsigned int. - */ - mvid = (u32) mvid_calc; - } else { - base_cc = catalog->io->dp_cc_io.base; - - pixel_m = dp_read(base_cc + MMSS_DP_PIXEL_M); - pixel_n = dp_read(base_cc + MMSS_DP_PIXEL_N); - pr_debug("pixel_m=0x%x, pixel_n=0x%x\n", pixel_m, pixel_n); - - mvid = (pixel_m & 0xFFFF) * 5; - nvid = (0xFFFF & (~pixel_n)) + (pixel_m & 0xFFFF); - - pr_debug("rate = %d\n", rate); - - if (link_rate_hbr2 == rate) - nvid *= 2; - - if (link_rate_hbr3 == rate) - nvid *= 3; - } - - base_ctrl = catalog->io->ctrl_io.base; - pr_debug("mvid=0x%x, nvid=0x%x\n", mvid, nvid); - dp_write(base_ctrl + DP_SOFTWARE_MVID, mvid); - dp_write(base_ctrl + DP_SOFTWARE_NVID, nvid); -} - -static void dp_catalog_ctrl_set_pattern(struct dp_catalog_ctrl *ctrl, - u32 pattern) -{ - int bit, cnt = 10; - u32 data; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - bit = 1; - bit <<= (pattern - 1); - pr_debug("hw: bit=%d train=%d\n", bit, pattern); - dp_write(base + DP_STATE_CTRL, bit); - - bit = 8; - bit <<= (pattern - 1); - - while (cnt--) { - data = dp_read(base + DP_MAINLINK_READY); - if (data & bit) - break; - } - - if (cnt == 0) - pr_err("set link_train=%d failed\n", pattern); -} - -static void dp_catalog_ctrl_usb_reset(struct dp_catalog_ctrl *ctrl, bool flip) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - - base = catalog->io->usb3_dp_com.base; - - dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x0a); - dp_write(base + USB3_DP_COM_PHY_MODE_CTRL, 0x02); - dp_write(base + USB3_DP_COM_SW_RESET, 0x01); - /* make sure usb3 com phy software reset is done */ - wmb(); - - if (!flip) /* CC1 */ - dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x02); - else /* CC2 */ - dp_write(base + USB3_DP_COM_TYPEC_CTRL, 0x03); - - dp_write(base + USB3_DP_COM_SWI_CTRL, 0x00); - dp_write(base + USB3_DP_COM_SW_RESET, 0x00); - /* make sure the software reset is done */ - wmb(); - - dp_write(base + USB3_DP_COM_POWER_DOWN_CTRL, 0x01); - dp_write(base + USB3_DP_COM_RESET_OVRD_CTRL, 0x00); - /* make sure phy is brought out of reset */ - wmb(); - -} - -static void dp_catalog_ctrl_reset(struct dp_catalog_ctrl *ctrl) -{ - u32 sw_reset; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - sw_reset = dp_read(base + DP_SW_RESET); - - sw_reset |= BIT(0); - dp_write(base + DP_SW_RESET, sw_reset); - usleep_range(1000, 1010); /* h/w recommended delay */ - - sw_reset &= ~BIT(0); - dp_write(base + DP_SW_RESET, sw_reset); -} - -static bool dp_catalog_ctrl_mainlink_ready(struct dp_catalog_ctrl *ctrl) -{ - u32 data; - int cnt = 10; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - goto end; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - while (--cnt) { - /* DP_MAINLINK_READY */ - data = dp_read(base + DP_MAINLINK_READY); - if (data & BIT(0)) - return true; - - usleep_range(1000, 1010); /* 1ms wait before next reg read */ - } - pr_err("mainlink not ready\n"); -end: - return false; -} - -static void dp_catalog_ctrl_enable_irq(struct dp_catalog_ctrl *ctrl, - bool enable) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - if (enable) { - dp_write(base + DP_INTR_STATUS, DP_INTR_MASK1); - dp_write(base + DP_INTR_STATUS2, DP_INTR_MASK2); - } else { - dp_write(base + DP_INTR_STATUS, 0x00); - dp_write(base + DP_INTR_STATUS2, 0x00); - } -} - -static void dp_catalog_ctrl_hpd_config(struct dp_catalog_ctrl *ctrl, bool en) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - if (en) { - u32 reftimer = dp_read(base + DP_DP_HPD_REFTIMER); - - dp_write(base + DP_DP_HPD_INT_ACK, 0xF); - dp_write(base + DP_DP_HPD_INT_MASK, 0xF); - - /* Enabling REFTIMER */ - reftimer |= BIT(16); - dp_write(base + DP_DP_HPD_REFTIMER, 0xF); - /* Enable HPD */ - dp_write(base + DP_DP_HPD_CTRL, 0x1); - } else { - /*Disable HPD */ - dp_write(base + DP_DP_HPD_CTRL, 0x0); - } -} - -static void dp_catalog_ctrl_get_interrupt(struct dp_catalog_ctrl *ctrl) -{ - u32 ack = 0; - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - ctrl->isr = dp_read(base + DP_INTR_STATUS2); - ctrl->isr &= ~DP_INTR_MASK2; - ack = ctrl->isr & DP_INTERRUPT_STATUS2; - ack <<= 1; - ack |= DP_INTR_MASK2; - dp_write(base + DP_INTR_STATUS2, ack); -} - -static void dp_catalog_ctrl_phy_reset(struct dp_catalog_ctrl *ctrl) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base = catalog->io->ctrl_io.base; - - dp_write(base + DP_PHY_CTRL, 0x5); /* bit 0 & 2 */ - usleep_range(1000, 1010); /* h/w recommended delay */ - dp_write(base + DP_PHY_CTRL, 0x0); - wmb(); /* make sure PHY reset done */ -} - -static void dp_catalog_ctrl_phy_lane_cfg(struct dp_catalog_ctrl *ctrl, - bool flipped, u8 ln_cnt) -{ - u32 info = 0x0; - struct dp_catalog_private *catalog; - u8 orientation = BIT(!!flipped); - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - - info |= (ln_cnt & 0x0F); - info |= ((orientation & 0x0F) << 4); - pr_debug("Shared Info = 0x%x\n", info); - - dp_write(catalog->io->phy_io.base + DP_PHY_SPARE0, info); -} - -static void dp_catalog_ctrl_update_vx_px(struct dp_catalog_ctrl *ctrl, - u8 v_level, u8 p_level) -{ - struct dp_catalog_private *catalog; - void __iomem *base0, *base1; - u8 value0, value1; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - base0 = catalog->io->ln_tx0_io.base; - base1 = catalog->io->ln_tx1_io.base; - - pr_debug("hw: v=%d p=%d\n", v_level, p_level); - - value0 = vm_voltage_swing[v_level][p_level]; - value1 = vm_pre_emphasis[v_level][p_level]; - - /* program default setting first */ - dp_write(base0 + TXn_TX_DRV_LVL, 0x2A); - dp_write(base1 + TXn_TX_DRV_LVL, 0x2A); - dp_write(base0 + TXn_TX_EMP_POST1_LVL, 0x20); - dp_write(base1 + TXn_TX_EMP_POST1_LVL, 0x20); - - /* Enable MUX to use Cursor values from these registers */ - value0 |= BIT(5); - value1 |= BIT(5); - - /* Configure host and panel only if both values are allowed */ - if (value0 != 0xFF && value1 != 0xFF) { - dp_write(base0 + TXn_TX_DRV_LVL, value0); - dp_write(base1 + TXn_TX_DRV_LVL, value0); - dp_write(base0 + TXn_TX_EMP_POST1_LVL, value1); - dp_write(base1 + TXn_TX_EMP_POST1_LVL, value1); - - pr_debug("hw: vx_value=0x%x px_value=0x%x\n", - value0, value1); - } else { - pr_err("invalid vx (0x%x=0x%x), px (0x%x=0x%x\n", - v_level, value0, p_level, value1); - } -} - -static void dp_catalog_ctrl_send_phy_pattern(struct dp_catalog_ctrl *ctrl, - u32 pattern) -{ - struct dp_catalog_private *catalog; - u32 value = 0x0; - void __iomem *base = NULL; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_catalog_get_priv(ctrl); - - base = catalog->io->ctrl_io.base; - - dp_write(base + DP_STATE_CTRL, 0x0); - - switch (pattern) { - case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: - dp_write(base + DP_STATE_CTRL, 0x1); - break; - case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: - value &= ~(1 << 16); - dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); - value |= 0xFC; - dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); - dp_write(base + DP_MAINLINK_LEVELS, 0x2); - dp_write(base + DP_STATE_CTRL, 0x10); - break; - case DP_TEST_PHY_PATTERN_PRBS7: - dp_write(base + DP_STATE_CTRL, 0x20); - break; - case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: - dp_write(base + DP_STATE_CTRL, 0x40); - /* 00111110000011111000001111100000 */ - dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG0, 0x3E0F83E0); - /* 00001111100000111110000011111000 */ - dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG1, 0x0F83E0F8); - /* 1111100000111110 */ - dp_write(base + DP_TEST_80BIT_CUSTOM_PATTERN_REG2, 0x0000F83E); - break; - case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN: - value = BIT(16); - dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); - value |= 0xFC; - dp_write(base + DP_HBR2_COMPLIANCE_SCRAMBLER_RESET, value); - dp_write(base + DP_MAINLINK_LEVELS, 0x2); - dp_write(base + DP_STATE_CTRL, 0x10); - break; - default: - pr_debug("No valid test pattern requested: 0x%x\n", pattern); - return; - } - - /* Make sure the test pattern is programmed in the hardware */ - wmb(); -} - -static u32 dp_catalog_ctrl_read_phy_pattern(struct dp_catalog_ctrl *ctrl) -{ - struct dp_catalog_private *catalog; - void __iomem *base = NULL; - - if (!ctrl) { - pr_err("invalid input\n"); - return 0; - } - - dp_catalog_get_priv(ctrl); - - base = catalog->io->ctrl_io.base; - - return dp_read(base + DP_MAINLINK_READY); -} - -/* panel related catalog functions */ -static int dp_catalog_panel_timing_cfg(struct dp_catalog_panel *panel) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - - if (!panel) { - pr_err("invalid input\n"); - goto end; - } - - dp_catalog_get_priv(panel); - base = catalog->io->ctrl_io.base; - - dp_write(base + DP_TOTAL_HOR_VER, panel->total); - dp_write(base + DP_START_HOR_VER_FROM_SYNC, panel->sync_start); - dp_write(base + DP_HSYNC_VSYNC_WIDTH_POLARITY, panel->width_blanking); - dp_write(base + DP_ACTIVE_HOR_VER, panel->dp_active); -end: - return 0; -} - -static void dp_catalog_audio_init(struct dp_catalog_audio *audio) -{ - struct dp_catalog_private *catalog; - static u32 sdp_map[][DP_AUDIO_SDP_HEADER_MAX] = { - { - MMSS_DP_AUDIO_STREAM_0, - MMSS_DP_AUDIO_STREAM_1, - MMSS_DP_AUDIO_STREAM_1, - }, - { - MMSS_DP_AUDIO_TIMESTAMP_0, - MMSS_DP_AUDIO_TIMESTAMP_1, - MMSS_DP_AUDIO_TIMESTAMP_1, - }, - { - MMSS_DP_AUDIO_INFOFRAME_0, - MMSS_DP_AUDIO_INFOFRAME_1, - MMSS_DP_AUDIO_INFOFRAME_1, - }, - { - MMSS_DP_AUDIO_COPYMANAGEMENT_0, - MMSS_DP_AUDIO_COPYMANAGEMENT_1, - MMSS_DP_AUDIO_COPYMANAGEMENT_1, - }, - { - MMSS_DP_AUDIO_ISRC_0, - MMSS_DP_AUDIO_ISRC_1, - MMSS_DP_AUDIO_ISRC_1, - }, - }; - - if (!audio) - return; - - dp_catalog_get_priv(audio); - - catalog->audio_map = sdp_map; -} - -static void dp_catalog_audio_config_sdp(struct dp_catalog_audio *audio) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - u32 sdp_cfg = 0; - u32 sdp_cfg2 = 0; - - if (!audio) - return; - - dp_catalog_get_priv(audio); - base = catalog->io->ctrl_io.base; - - /* AUDIO_TIMESTAMP_SDP_EN */ - sdp_cfg |= BIT(1); - /* AUDIO_STREAM_SDP_EN */ - sdp_cfg |= BIT(2); - /* AUDIO_COPY_MANAGEMENT_SDP_EN */ - sdp_cfg |= BIT(5); - /* AUDIO_ISRC_SDP_EN */ - sdp_cfg |= BIT(6); - /* AUDIO_INFOFRAME_SDP_EN */ - sdp_cfg |= BIT(20); - - pr_debug("sdp_cfg = 0x%x\n", sdp_cfg); - dp_write(base + MMSS_DP_SDP_CFG, sdp_cfg); - - sdp_cfg2 = dp_read(base + MMSS_DP_SDP_CFG2); - /* IFRM_REGSRC -> Do not use reg values */ - sdp_cfg2 &= ~BIT(0); - /* AUDIO_STREAM_HB3_REGSRC-> Do not use reg values */ - sdp_cfg2 &= ~BIT(1); - - pr_debug("sdp_cfg2 = 0x%x\n", sdp_cfg2); - dp_write(base + MMSS_DP_SDP_CFG2, sdp_cfg2); -} - -static void dp_catalog_audio_get_header(struct dp_catalog_audio *audio) -{ - struct dp_catalog_private *catalog; - u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX]; - void __iomem *base; - enum dp_catalog_audio_sdp_type sdp; - enum dp_catalog_audio_header_type header; - - if (!audio) - return; - - dp_catalog_get_priv(audio); - - base = catalog->io->ctrl_io.base; - sdp_map = catalog->audio_map; - sdp = audio->sdp_type; - header = audio->sdp_header; - - audio->data = dp_read(base + sdp_map[sdp][header]); -} - -static void dp_catalog_audio_set_header(struct dp_catalog_audio *audio) -{ - struct dp_catalog_private *catalog; - u32 (*sdp_map)[DP_AUDIO_SDP_HEADER_MAX]; - void __iomem *base; - enum dp_catalog_audio_sdp_type sdp; - enum dp_catalog_audio_header_type header; - u32 data; - - if (!audio) - return; - - dp_catalog_get_priv(audio); - - base = catalog->io->ctrl_io.base; - sdp_map = catalog->audio_map; - sdp = audio->sdp_type; - header = audio->sdp_header; - data = audio->data; - - dp_write(base + sdp_map[sdp][header], data); -} - -static void dp_catalog_audio_config_acr(struct dp_catalog_audio *audio) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - u32 acr_ctrl, select; - - dp_catalog_get_priv(audio); - - select = audio->data; - base = catalog->io->ctrl_io.base; - - acr_ctrl = select << 4 | BIT(31) | BIT(8) | BIT(14); - - pr_debug("select = 0x%x, acr_ctrl = 0x%x\n", select, acr_ctrl); - - dp_write(base + MMSS_DP_AUDIO_ACR_CTRL, acr_ctrl); -} - -static void dp_catalog_audio_safe_to_exit_level(struct dp_catalog_audio *audio) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - u32 mainlink_levels, safe_to_exit_level; - - dp_catalog_get_priv(audio); - - base = catalog->io->ctrl_io.base; - safe_to_exit_level = audio->data; - - mainlink_levels = dp_read(base + DP_MAINLINK_LEVELS); - mainlink_levels &= 0xFE0; - mainlink_levels |= safe_to_exit_level; - - pr_debug("mainlink_level = 0x%x, safe_to_exit_level = 0x%x\n", - mainlink_levels, safe_to_exit_level); - - dp_write(base + DP_MAINLINK_LEVELS, mainlink_levels); -} - -static void dp_catalog_audio_enable(struct dp_catalog_audio *audio) -{ - struct dp_catalog_private *catalog; - void __iomem *base; - bool enable; - u32 audio_ctrl; - - dp_catalog_get_priv(audio); - - base = catalog->io->ctrl_io.base; - enable = !!audio->data; - - audio_ctrl = dp_read(base + MMSS_DP_AUDIO_CFG); - - if (enable) - audio_ctrl |= BIT(0); - else - audio_ctrl &= ~BIT(0); - - pr_debug("dp_audio_cfg = 0x%x\n", audio_ctrl); - dp_write(base + MMSS_DP_AUDIO_CFG, audio_ctrl); - - /* make sure audio engine is disabled */ - wmb(); -} - -struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io) -{ - int rc = 0; - struct dp_catalog *dp_catalog; - struct dp_catalog_private *catalog; - struct dp_catalog_aux aux = { - .read_data = dp_catalog_aux_read_data, - .write_data = dp_catalog_aux_write_data, - .write_trans = dp_catalog_aux_write_trans, - .clear_trans = dp_catalog_aux_clear_trans, - .reset = dp_catalog_aux_reset, - .update_aux_cfg = dp_catalog_aux_update_cfg, - .enable = dp_catalog_aux_enable, - .setup = dp_catalog_aux_setup, - .get_irq = dp_catalog_aux_get_irq, - }; - struct dp_catalog_ctrl ctrl = { - .state_ctrl = dp_catalog_ctrl_state_ctrl, - .config_ctrl = dp_catalog_ctrl_config_ctrl, - .lane_mapping = dp_catalog_ctrl_lane_mapping, - .mainlink_ctrl = dp_catalog_ctrl_mainlink_ctrl, - .config_misc = dp_catalog_ctrl_config_misc, - .config_msa = dp_catalog_ctrl_config_msa, - .set_pattern = dp_catalog_ctrl_set_pattern, - .reset = dp_catalog_ctrl_reset, - .usb_reset = dp_catalog_ctrl_usb_reset, - .mainlink_ready = dp_catalog_ctrl_mainlink_ready, - .enable_irq = dp_catalog_ctrl_enable_irq, - .hpd_config = dp_catalog_ctrl_hpd_config, - .phy_reset = dp_catalog_ctrl_phy_reset, - .phy_lane_cfg = dp_catalog_ctrl_phy_lane_cfg, - .update_vx_px = dp_catalog_ctrl_update_vx_px, - .get_interrupt = dp_catalog_ctrl_get_interrupt, - .config_hdr = dp_catalog_ctrl_config_hdr, - .update_transfer_unit = dp_catalog_ctrl_update_transfer_unit, - .read_hdcp_status = dp_catalog_ctrl_read_hdcp_status, - .send_phy_pattern = dp_catalog_ctrl_send_phy_pattern, - .read_phy_pattern = dp_catalog_ctrl_read_phy_pattern, - }; - struct dp_catalog_audio audio = { - .init = dp_catalog_audio_init, - .config_acr = dp_catalog_audio_config_acr, - .enable = dp_catalog_audio_enable, - .config_sdp = dp_catalog_audio_config_sdp, - .set_header = dp_catalog_audio_set_header, - .get_header = dp_catalog_audio_get_header, - .safe_to_exit_level = dp_catalog_audio_safe_to_exit_level, - }; - struct dp_catalog_panel panel = { - .timing_cfg = dp_catalog_panel_timing_cfg, - }; - - if (!io) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - catalog = devm_kzalloc(dev, sizeof(*catalog), GFP_KERNEL); - if (!catalog) { - rc = -ENOMEM; - goto error; - } - - catalog->dev = dev; - catalog->io = io; - - dp_catalog = &catalog->dp_catalog; - - dp_catalog->aux = aux; - dp_catalog->ctrl = ctrl; - dp_catalog->audio = audio; - dp_catalog->panel = panel; - - return dp_catalog; -error: - return ERR_PTR(rc); -} - -void dp_catalog_put(struct dp_catalog *dp_catalog) -{ - struct dp_catalog_private *catalog; - - if (!dp_catalog) - return; - - catalog = container_of(dp_catalog, struct dp_catalog_private, - dp_catalog); - - devm_kfree(catalog->dev, catalog); -} diff --git a/drivers/gpu/drm/msm/dp/dp_catalog.h b/drivers/gpu/drm/msm/dp/dp_catalog.h deleted file mode 100644 index 12b5ad9..0000000 --- a/drivers/gpu/drm/msm/dp/dp_catalog.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_CATALOG_H_ -#define _DP_CATALOG_H_ - -#include "dp_parser.h" - -/* interrupts */ -#define DP_INTR_HPD BIT(0) -#define DP_INTR_AUX_I2C_DONE BIT(3) -#define DP_INTR_WRONG_ADDR BIT(6) -#define DP_INTR_TIMEOUT BIT(9) -#define DP_INTR_NACK_DEFER BIT(12) -#define DP_INTR_WRONG_DATA_CNT BIT(15) -#define DP_INTR_I2C_NACK BIT(18) -#define DP_INTR_I2C_DEFER BIT(21) -#define DP_INTR_PLL_UNLOCKED BIT(24) -#define DP_INTR_AUX_ERROR BIT(27) - -#define DP_INTR_READY_FOR_VIDEO BIT(0) -#define DP_INTR_IDLE_PATTERN_SENT BIT(3) -#define DP_INTR_FRAME_END BIT(6) -#define DP_INTR_CRC_UPDATED BIT(9) - -#define HDR_PRIMARIES_COUNT 3 - -struct dp_catalog_hdr_data { - u32 vsc_hdr_byte0; - u32 vsc_hdr_byte1; - u32 vsc_hdr_byte2; - u32 vsc_hdr_byte3; - u32 pkt_payload; - - u32 bpc; - - u32 version; - u32 length; - u32 eotf; - u32 descriptor_id; - - u32 display_primaries_x[HDR_PRIMARIES_COUNT]; - u32 display_primaries_y[HDR_PRIMARIES_COUNT]; - u32 white_point_x; - u32 white_point_y; - u32 max_luminance; - u32 min_luminance; - u32 max_content_light_level; - u32 max_average_light_level; -}; - -struct dp_catalog_aux { - u32 data; - u32 isr; - - u32 (*read_data)(struct dp_catalog_aux *aux); - int (*write_data)(struct dp_catalog_aux *aux); - int (*write_trans)(struct dp_catalog_aux *aux); - int (*clear_trans)(struct dp_catalog_aux *aux, bool read); - void (*reset)(struct dp_catalog_aux *aux); - void (*enable)(struct dp_catalog_aux *aux, bool enable); - void (*update_aux_cfg)(struct dp_catalog_aux *aux, - struct dp_aux_cfg *cfg, enum dp_phy_aux_config_type type); - void (*setup)(struct dp_catalog_aux *aux, - struct dp_aux_cfg *aux_cfg); - void (*get_irq)(struct dp_catalog_aux *aux, bool cmd_busy); -}; - -struct dp_catalog_ctrl { - u32 dp_tu; - u32 valid_boundary; - u32 valid_boundary2; - u32 isr; - struct dp_catalog_hdr_data hdr_data; - - void (*state_ctrl)(struct dp_catalog_ctrl *ctrl, u32 state); - void (*config_ctrl)(struct dp_catalog_ctrl *ctrl, u32 config); - void (*lane_mapping)(struct dp_catalog_ctrl *ctrl); - void (*mainlink_ctrl)(struct dp_catalog_ctrl *ctrl, bool enable); - void (*config_misc)(struct dp_catalog_ctrl *ctrl, u32 cc, u32 tb); - void (*config_msa)(struct dp_catalog_ctrl *ctrl, u32 rate, - u32 stream_rate_khz, bool fixed_nvid); - void (*set_pattern)(struct dp_catalog_ctrl *ctrl, u32 pattern); - void (*reset)(struct dp_catalog_ctrl *ctrl); - void (*usb_reset)(struct dp_catalog_ctrl *ctrl, bool flip); - bool (*mainlink_ready)(struct dp_catalog_ctrl *ctrl); - void (*enable_irq)(struct dp_catalog_ctrl *ctrl, bool enable); - void (*hpd_config)(struct dp_catalog_ctrl *ctrl, bool enable); - void (*phy_reset)(struct dp_catalog_ctrl *ctrl); - void (*phy_lane_cfg)(struct dp_catalog_ctrl *ctrl, bool flipped, - u8 lane_cnt); - void (*update_vx_px)(struct dp_catalog_ctrl *ctrl, u8 v_level, - u8 p_level); - void (*get_interrupt)(struct dp_catalog_ctrl *ctrl); - void (*config_hdr)(struct dp_catalog_ctrl *ctrl); - void (*update_transfer_unit)(struct dp_catalog_ctrl *ctrl); - u32 (*read_hdcp_status)(struct dp_catalog_ctrl *ctrl); - void (*send_phy_pattern)(struct dp_catalog_ctrl *ctrl, - u32 pattern); - u32 (*read_phy_pattern)(struct dp_catalog_ctrl *ctrl); -}; - -enum dp_catalog_audio_sdp_type { - DP_AUDIO_SDP_STREAM, - DP_AUDIO_SDP_TIMESTAMP, - DP_AUDIO_SDP_INFOFRAME, - DP_AUDIO_SDP_COPYMANAGEMENT, - DP_AUDIO_SDP_ISRC, - DP_AUDIO_SDP_MAX, -}; - -enum dp_catalog_audio_header_type { - DP_AUDIO_SDP_HEADER_1, - DP_AUDIO_SDP_HEADER_2, - DP_AUDIO_SDP_HEADER_3, - DP_AUDIO_SDP_HEADER_MAX, -}; - -struct dp_catalog_audio { - enum dp_catalog_audio_sdp_type sdp_type; - enum dp_catalog_audio_header_type sdp_header; - u32 data; - - void (*init)(struct dp_catalog_audio *audio); - void (*enable)(struct dp_catalog_audio *audio); - void (*config_acr)(struct dp_catalog_audio *audio); - void (*config_sdp)(struct dp_catalog_audio *audio); - void (*set_header)(struct dp_catalog_audio *audio); - void (*get_header)(struct dp_catalog_audio *audio); - void (*safe_to_exit_level)(struct dp_catalog_audio *audio); -}; - -struct dp_catalog_panel { - u32 total; - u32 sync_start; - u32 width_blanking; - u32 dp_active; - - int (*timing_cfg)(struct dp_catalog_panel *panel); -}; - -struct dp_catalog { - struct dp_catalog_aux aux; - struct dp_catalog_ctrl ctrl; - struct dp_catalog_audio audio; - struct dp_catalog_panel panel; -}; - -struct dp_catalog *dp_catalog_get(struct device *dev, struct dp_io *io); -void dp_catalog_put(struct dp_catalog *catalog); - -#endif /* _DP_CATALOG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c deleted file mode 100644 index c8039fe..0000000 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c +++ /dev/null @@ -1,1474 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/types.h> -#include <linux/completion.h> -#include <linux/delay.h> - -#include "dp_ctrl.h" - -#define DP_KHZ_TO_HZ 1000 - -#define DP_CTRL_INTR_READY_FOR_VIDEO BIT(0) -#define DP_CTRL_INTR_IDLE_PATTERN_SENT BIT(3) - -/* dp state ctrl */ -#define ST_TRAIN_PATTERN_1 BIT(0) -#define ST_TRAIN_PATTERN_2 BIT(1) -#define ST_TRAIN_PATTERN_3 BIT(2) -#define ST_TRAIN_PATTERN_4 BIT(3) -#define ST_SYMBOL_ERR_RATE_MEASUREMENT BIT(4) -#define ST_PRBS7 BIT(5) -#define ST_CUSTOM_80_BIT_PATTERN BIT(6) -#define ST_SEND_VIDEO BIT(7) -#define ST_PUSH_IDLE BIT(8) - -#define MR_LINK_TRAINING1 0x8 -#define MR_LINK_SYMBOL_ERM 0x80 -#define MR_LINK_PRBS7 0x100 -#define MR_LINK_CUSTOM80 0x200 - -struct dp_vc_tu_mapping_table { - u32 vic; - u8 lanes; - u8 lrate; /* DP_LINK_RATE -> 162(6), 270(10), 540(20), 810 (30) */ - u8 bpp; - u8 valid_boundary_link; - u16 delay_start_link; - bool boundary_moderation_en; - u8 valid_lower_boundary_link; - u8 upper_boundary_count; - u8 lower_boundary_count; - u8 tu_size_minus1; -}; - -struct dp_ctrl_private { - struct dp_ctrl dp_ctrl; - - struct device *dev; - struct dp_aux *aux; - struct dp_panel *panel; - struct dp_link *link; - struct dp_power *power; - struct dp_parser *parser; - struct dp_catalog_ctrl *catalog; - - struct completion idle_comp; - struct completion video_comp; - - bool orientation; - atomic_t aborted; - - u32 pixel_rate; - u32 vic; -}; - -enum notification_status { - NOTIFY_UNKNOWN, - NOTIFY_CONNECT, - NOTIFY_DISCONNECT, - NOTIFY_CONNECT_IRQ_HPD, - NOTIFY_DISCONNECT_IRQ_HPD, -}; - -static void dp_ctrl_idle_patterns_sent(struct dp_ctrl_private *ctrl) -{ - pr_debug("idle_patterns_sent\n"); - complete(&ctrl->idle_comp); -} - -static void dp_ctrl_video_ready(struct dp_ctrl_private *ctrl) -{ - pr_debug("dp_video_ready\n"); - complete(&ctrl->video_comp); -} - -static void dp_ctrl_abort(struct dp_ctrl *dp_ctrl) -{ - struct dp_ctrl_private *ctrl; - - if (!dp_ctrl) { - pr_err("Invalid input data\n"); - return; - } - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - atomic_set(&ctrl->aborted, 1); -} - -static void dp_ctrl_state_ctrl(struct dp_ctrl_private *ctrl, u32 state) -{ - ctrl->catalog->state_ctrl(ctrl->catalog, state); -} - -static void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl) -{ - int const idle_pattern_completion_timeout_ms = 3 * HZ / 100; - struct dp_ctrl_private *ctrl; - - if (!dp_ctrl) { - pr_err("Invalid input data\n"); - return; - } - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - reinit_completion(&ctrl->idle_comp); - dp_ctrl_state_ctrl(ctrl, ST_PUSH_IDLE); - - if (!wait_for_completion_timeout(&ctrl->idle_comp, - idle_pattern_completion_timeout_ms)) - pr_warn("PUSH_IDLE pattern timedout\n"); - - pr_debug("mainlink off done\n"); -} - -static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl) -{ - u32 config = 0, tbd; - u8 *dpcd = ctrl->panel->dpcd; - - config |= (2 << 13); /* Default-> LSCLK DIV: 1/4 LCLK */ - config |= (0 << 11); /* RGB */ - - /* Scrambler reset enable */ - if (dpcd[DP_EDP_CONFIGURATION_CAP] & DP_ALTERNATE_SCRAMBLER_RESET_CAP) - config |= (1 << 10); - - tbd = ctrl->link->get_test_bits_depth(ctrl->link, - ctrl->panel->pinfo.bpp); - - if (tbd == DP_TEST_BIT_DEPTH_UNKNOWN) - tbd = DP_TEST_BIT_DEPTH_8; - - config |= tbd << 8; - - /* Num of Lanes */ - config |= ((ctrl->link->link_params.lane_count - 1) << 4); - - if (drm_dp_enhanced_frame_cap(dpcd)) - config |= 0x40; - - config |= 0x04; /* progressive video */ - - config |= 0x03; /* sycn clock & static Mvid */ - - ctrl->catalog->config_ctrl(ctrl->catalog, config); -} - -/** - * dp_ctrl_configure_source_params() - configures DP transmitter source params - * @ctrl: Display Port Driver data - * - * Configures the DP transmitter source params including details such as lane - * configuration, output format and sink/panel timing information. - */ -static void dp_ctrl_configure_source_params(struct dp_ctrl_private *ctrl) -{ - u32 cc, tb; - - ctrl->catalog->lane_mapping(ctrl->catalog); - ctrl->catalog->mainlink_ctrl(ctrl->catalog, true); - - dp_ctrl_config_ctrl(ctrl); - - tb = ctrl->link->get_test_bits_depth(ctrl->link, - ctrl->panel->pinfo.bpp); - cc = ctrl->link->get_colorimetry_config(ctrl->link); - ctrl->catalog->config_misc(ctrl->catalog, cc, tb); - ctrl->panel->timing_cfg(ctrl->panel); -} - -static void dp_ctrl_get_extra_req_bytes(u64 result_valid, - int valid_bdary_link, - u64 value1, u64 value2, - bool *negative, u64 *result, - u64 compare) -{ - *negative = false; - if (result_valid >= compare) { - if (valid_bdary_link - >= compare) - *result = value1 + value2; - else { - if (value1 < value2) - *negative = true; - *result = (value1 >= value2) ? - (value1 - value2) : (value2 - value1); - } - } else { - if (valid_bdary_link - >= compare) { - if (value1 >= value2) - *negative = true; - *result = (value1 >= value2) ? - (value1 - value2) : (value2 - value1); - } else { - *result = value1 + value2; - *negative = true; - } - } -} - -static u64 roundup_u64(u64 x, u64 y) -{ - x += (y - 1); - return (div64_ul(x, y) * y); -} - -static u64 rounddown_u64(u64 x, u64 y) -{ - u64 rem; - - div64_u64_rem(x, y, &rem); - return (x - rem); -} - -static void dp_ctrl_calc_tu_parameters(struct dp_ctrl_private *ctrl, - struct dp_vc_tu_mapping_table *tu_table) -{ - u32 multiplier = 1000000; - u64 pclk, lclk; - u8 bpp, ln_cnt; - int run_idx = 0; - u32 lwidth, h_blank; - u32 fifo_empty = 0; - u32 ratio_scale = 1001; - u64 temp, ratio, original_ratio; - u64 temp2, reminder; - u64 temp3, temp4, result = 0; - - u64 err = multiplier; - u64 n_err = 0, n_n_err = 0; - bool n_err_neg, nn_err_neg; - u8 hblank_margin = 16; - - u8 tu_size, tu_size_desired = 0, tu_size_minus1; - int valid_boundary_link; - u64 resulting_valid; - u64 total_valid; - u64 effective_valid; - u64 effective_valid_recorded; - int n_tus; - int n_tus_per_lane; - int paired_tus; - int remainder_tus; - int remainder_tus_upper, remainder_tus_lower; - int extra_bytes; - int filler_size; - int delay_start_link; - int boundary_moderation_en = 0; - int upper_bdry_cnt = 0; - int lower_bdry_cnt = 0; - int i_upper_bdry_cnt = 0; - int i_lower_bdry_cnt = 0; - int valid_lower_boundary_link = 0; - int even_distribution_bf = 0; - int even_distribution_legacy = 0; - int even_distribution = 0; - int min_hblank = 0; - int extra_pclk_cycles; - u8 extra_pclk_cycle_delay = 4; - int extra_pclk_cycles_in_link_clk; - u64 ratio_by_tu; - u64 average_valid2; - u64 extra_buffer_margin; - int new_valid_boundary_link; - - u64 resulting_valid_tmp; - u64 ratio_by_tu_tmp; - int n_tus_tmp; - int extra_pclk_cycles_tmp; - int extra_pclk_cycles_in_lclk_tmp; - int extra_req_bytes_new_tmp; - int filler_size_tmp; - int lower_filler_size_tmp; - int delay_start_link_tmp; - int min_hblank_tmp = 0; - bool extra_req_bytes_is_neg = false; - struct dp_panel_info *pinfo = &ctrl->panel->pinfo; - - u8 dp_brute_force = 1; - u64 brute_force_threshold = 10; - u64 diff_abs; - - ln_cnt = ctrl->link->link_params.lane_count; - - bpp = pinfo->bpp; - lwidth = pinfo->h_active; - h_blank = pinfo->h_back_porch + pinfo->h_front_porch + - pinfo->h_sync_width; - pclk = pinfo->pixel_clk_khz * 1000; - - boundary_moderation_en = 0; - upper_bdry_cnt = 0; - lower_bdry_cnt = 0; - i_upper_bdry_cnt = 0; - i_lower_bdry_cnt = 0; - valid_lower_boundary_link = 0; - even_distribution_bf = 0; - even_distribution_legacy = 0; - even_distribution = 0; - min_hblank = 0; - - lclk = drm_dp_bw_code_to_link_rate( - ctrl->link->link_params.bw_code) * DP_KHZ_TO_HZ; - - pr_debug("pclk=%lld, active_width=%d, h_blank=%d\n", - pclk, lwidth, h_blank); - pr_debug("lclk = %lld, ln_cnt = %d\n", lclk, ln_cnt); - ratio = div64_u64_rem(pclk * bpp * multiplier, - 8 * ln_cnt * lclk, &reminder); - ratio = div64_u64((pclk * bpp * multiplier), (8 * ln_cnt * lclk)); - original_ratio = ratio; - - extra_buffer_margin = roundup_u64(div64_u64(extra_pclk_cycle_delay - * lclk * multiplier, pclk), multiplier); - extra_buffer_margin = div64_u64(extra_buffer_margin, multiplier); - - /* To deal with cases where lines are not distributable */ - if (((lwidth % ln_cnt) != 0) && ratio < multiplier) { - ratio = ratio * ratio_scale; - ratio = ratio < (1000 * multiplier) - ? ratio : (1000 * multiplier); - } - pr_debug("ratio = %lld\n", ratio); - - for (tu_size = 32; tu_size <= 64; tu_size++) { - temp = ratio * tu_size; - temp2 = (div_u64(temp / multiplier) + 1) * multiplier; - n_err = roundup_u64(temp, multiplier) - temp; - - if (n_err < err) { - err = n_err; - tu_size_desired = tu_size; - } - } - pr_debug("Info: tu_size_desired = %d\n", tu_size_desired); - - tu_size_minus1 = tu_size_desired - 1; - - valid_boundary_link = roundup_u64(ratio * tu_size_desired, multiplier); - valid_boundary_link /= multiplier; - n_tus = rounddown((lwidth * bpp * multiplier) - / (8 * valid_boundary_link), multiplier) / multiplier; - even_distribution_legacy = n_tus % ln_cnt == 0 ? 1 : 0; - pr_debug("Info: n_symbol_per_tu=%d, number_of_tus=%d\n", - valid_boundary_link, n_tus); - - extra_bytes = roundup_u64((n_tus + 1) - * ((valid_boundary_link * multiplier) - - (original_ratio * tu_size_desired)), multiplier); - extra_bytes /= multiplier; - extra_pclk_cycles = roundup(extra_bytes * 8 * multiplier / bpp, - multiplier); - extra_pclk_cycles /= multiplier; - extra_pclk_cycles_in_link_clk = roundup_u64(div64_u64(extra_pclk_cycles - * lclk * multiplier, pclk), multiplier); - extra_pclk_cycles_in_link_clk /= multiplier; - filler_size = roundup_u64((tu_size_desired - valid_boundary_link) - * multiplier, multiplier); - filler_size /= multiplier; - ratio_by_tu = div64_u64(ratio * tu_size_desired, multiplier); - - pr_debug("extra_pclk_cycles_in_link_clk=%d, extra_bytes=%d\n", - extra_pclk_cycles_in_link_clk, extra_bytes); - pr_debug("extra_pclk_cycles_in_link_clk=%d\n", - extra_pclk_cycles_in_link_clk); - pr_debug("filler_size=%d, extra_buffer_margin=%lld\n", - filler_size, extra_buffer_margin); - - delay_start_link = ((extra_bytes > extra_pclk_cycles_in_link_clk) - ? extra_bytes - : extra_pclk_cycles_in_link_clk) - + filler_size + extra_buffer_margin; - resulting_valid = valid_boundary_link; - pr_debug("Info: delay_start_link=%d, filler_size=%d\n", - delay_start_link, filler_size); - pr_debug("valid_boundary_link=%d ratio_by_tu=%lld\n", - valid_boundary_link, ratio_by_tu); - - diff_abs = (resulting_valid >= ratio_by_tu) - ? (resulting_valid - ratio_by_tu) - : (ratio_by_tu - resulting_valid); - - if (err != 0 && ((diff_abs > brute_force_threshold) - || (even_distribution_legacy == 0) - || (dp_brute_force == 1))) { - err = multiplier; - for (tu_size = 32; tu_size <= 64; tu_size++) { - for (i_upper_bdry_cnt = 1; i_upper_bdry_cnt <= 15; - i_upper_bdry_cnt++) { - for (i_lower_bdry_cnt = 1; - i_lower_bdry_cnt <= 15; - i_lower_bdry_cnt++) { - new_valid_boundary_link = - roundup_u64(ratio - * tu_size, multiplier); - average_valid2 = (i_upper_bdry_cnt - * new_valid_boundary_link - + i_lower_bdry_cnt - * (new_valid_boundary_link - - multiplier)) - / (i_upper_bdry_cnt - + i_lower_bdry_cnt); - n_tus = rounddown_u64(div64_u64(lwidth - * multiplier * multiplier - * (bpp / 8), average_valid2), - multiplier); - n_tus /= multiplier; - n_tus_per_lane - = rounddown(n_tus - * multiplier - / ln_cnt, multiplier); - n_tus_per_lane /= multiplier; - paired_tus = - rounddown((n_tus_per_lane) - * multiplier - / (i_upper_bdry_cnt - + i_lower_bdry_cnt), - multiplier); - paired_tus /= multiplier; - remainder_tus = n_tus_per_lane - - paired_tus - * (i_upper_bdry_cnt - + i_lower_bdry_cnt); - if ((remainder_tus - - i_upper_bdry_cnt) > 0) { - remainder_tus_upper - = i_upper_bdry_cnt; - remainder_tus_lower = - remainder_tus - - i_upper_bdry_cnt; - } else { - remainder_tus_upper - = remainder_tus; - remainder_tus_lower = 0; - } - total_valid = paired_tus - * (i_upper_bdry_cnt - * new_valid_boundary_link - + i_lower_bdry_cnt - * (new_valid_boundary_link - - multiplier)) - + (remainder_tus_upper - * new_valid_boundary_link) - + (remainder_tus_lower - * (new_valid_boundary_link - - multiplier)); - n_err_neg = nn_err_neg = false; - effective_valid - = div_u64(total_valid, - n_tus_per_lane); - n_n_err = (effective_valid - >= (ratio * tu_size)) - ? (effective_valid - - (ratio * tu_size)) - : ((ratio * tu_size) - - effective_valid); - if (effective_valid < (ratio * tu_size)) - nn_err_neg = true; - n_err = (average_valid2 - >= (ratio * tu_size)) - ? (average_valid2 - - (ratio * tu_size)) - : ((ratio * tu_size) - - average_valid2); - if (average_valid2 < (ratio * tu_size)) - n_err_neg = true; - even_distribution = - n_tus % ln_cnt == 0 ? 1 : 0; - diff_abs = - resulting_valid >= ratio_by_tu - ? (resulting_valid - - ratio_by_tu) - : (ratio_by_tu - - resulting_valid); - - resulting_valid_tmp = div64_u64( - (i_upper_bdry_cnt - * new_valid_boundary_link - + i_lower_bdry_cnt - * (new_valid_boundary_link - - multiplier)), - (i_upper_bdry_cnt - + i_lower_bdry_cnt)); - ratio_by_tu_tmp = - original_ratio * tu_size; - ratio_by_tu_tmp /= multiplier; - n_tus_tmp = rounddown_u64( - div64_u64(lwidth - * multiplier * multiplier - * bpp / 8, - resulting_valid_tmp), - multiplier); - n_tus_tmp /= multiplier; - - temp3 = (resulting_valid_tmp - >= (original_ratio * tu_size)) - ? (resulting_valid_tmp - - original_ratio * tu_size) - : (original_ratio * tu_size) - - resulting_valid_tmp; - temp3 = (n_tus_tmp + 1) * temp3; - temp4 = (new_valid_boundary_link - >= (original_ratio * tu_size)) - ? (new_valid_boundary_link - - original_ratio - * tu_size) - : (original_ratio * tu_size) - - new_valid_boundary_link; - temp4 = (i_upper_bdry_cnt - * ln_cnt * temp4); - - temp3 = roundup_u64(temp3, multiplier); - temp4 = roundup_u64(temp4, multiplier); - dp_ctrl_get_extra_req_bytes - (resulting_valid_tmp, - new_valid_boundary_link, - temp3, temp4, - &extra_req_bytes_is_neg, - &result, - (original_ratio * tu_size)); - extra_req_bytes_new_tmp - = div64_ul(result, multiplier); - if ((extra_req_bytes_is_neg) - && (extra_req_bytes_new_tmp - > 1)) - extra_req_bytes_new_tmp - = extra_req_bytes_new_tmp - 1; - if (extra_req_bytes_new_tmp == 0) - extra_req_bytes_new_tmp = 1; - extra_pclk_cycles_tmp = - (u64)(extra_req_bytes_new_tmp - * 8 * multiplier) / bpp; - extra_pclk_cycles_tmp /= multiplier; - - if (extra_pclk_cycles_tmp <= 0) - extra_pclk_cycles_tmp = 1; - extra_pclk_cycles_in_lclk_tmp = - roundup_u64(div64_u64( - extra_pclk_cycles_tmp - * lclk * multiplier, - pclk), multiplier); - extra_pclk_cycles_in_lclk_tmp - /= multiplier; - filler_size_tmp = roundup_u64( - (tu_size * multiplier * - new_valid_boundary_link), - multiplier); - filler_size_tmp /= multiplier; - lower_filler_size_tmp = - filler_size_tmp + 1; - if (extra_req_bytes_is_neg) - temp3 = (extra_req_bytes_new_tmp - > extra_pclk_cycles_in_lclk_tmp - ? extra_pclk_cycles_in_lclk_tmp - : extra_req_bytes_new_tmp); - else - temp3 = (extra_req_bytes_new_tmp - > extra_pclk_cycles_in_lclk_tmp - ? extra_req_bytes_new_tmp : - extra_pclk_cycles_in_lclk_tmp); - - temp4 = lower_filler_size_tmp - + extra_buffer_margin; - if (extra_req_bytes_is_neg) - delay_start_link_tmp - = (temp3 >= temp4) - ? (temp3 - temp4) - : (temp4 - temp3); - else - delay_start_link_tmp - = temp3 + temp4; - - min_hblank_tmp = (int)div64_u64( - roundup_u64( - div64_u64(delay_start_link_tmp - * pclk * multiplier, lclk), - multiplier), multiplier) - + hblank_margin; - - if (((even_distribution == 1) - || ((even_distribution_bf == 0) - && (even_distribution_legacy - == 0))) - && !n_err_neg && !nn_err_neg - && n_n_err < err - && (n_n_err < diff_abs - || (dp_brute_force == 1)) - && (new_valid_boundary_link - - 1) > 0 - && (h_blank >= - (u32)min_hblank_tmp)) { - upper_bdry_cnt = - i_upper_bdry_cnt; - lower_bdry_cnt = - i_lower_bdry_cnt; - err = n_n_err; - boundary_moderation_en = 1; - tu_size_desired = tu_size; - valid_boundary_link = - new_valid_boundary_link; - effective_valid_recorded - = effective_valid; - delay_start_link - = delay_start_link_tmp; - filler_size = filler_size_tmp; - min_hblank = min_hblank_tmp; - n_tus = n_tus_tmp; - even_distribution_bf = 1; - - pr_debug("upper_bdry_cnt=%d, lower_boundary_cnt=%d, err=%lld, tu_size_desired=%d, valid_boundary_link=%d, effective_valid=%lld\n", - upper_bdry_cnt, - lower_bdry_cnt, err, - tu_size_desired, - valid_boundary_link, - effective_valid); - } - } - } - } - - if (boundary_moderation_en == 1) { - resulting_valid = (u64)(upper_bdry_cnt - *valid_boundary_link + lower_bdry_cnt - * (valid_boundary_link - 1)) - / (upper_bdry_cnt + lower_bdry_cnt); - ratio_by_tu = original_ratio * tu_size_desired; - valid_lower_boundary_link = - (valid_boundary_link / multiplier) - 1; - - tu_size_minus1 = tu_size_desired - 1; - even_distribution_bf = 1; - valid_boundary_link /= multiplier; - pr_debug("Info: Boundary_moderation enabled\n"); - } - } - - min_hblank = ((int) roundup_u64(div64_u64(delay_start_link * pclk - * multiplier, lclk), multiplier)) - / multiplier + hblank_margin; - if (h_blank < (u32)min_hblank) { - pr_debug(" WARNING: run_idx=%d Programmed h_blank %d is smaller than the min_hblank %d supported.\n", - run_idx, h_blank, min_hblank); - } - - if (fifo_empty) { - tu_size_minus1 = 31; - valid_boundary_link = 32; - delay_start_link = 0; - boundary_moderation_en = 0; - } - - pr_debug("tu_size_minus1=%d valid_boundary_link=%d delay_start_link=%d boundary_moderation_en=%d\n upper_boundary_cnt=%d lower_boundary_cnt=%d valid_lower_boundary_link=%d min_hblank=%d\n", - tu_size_minus1, valid_boundary_link, delay_start_link, - boundary_moderation_en, upper_bdry_cnt, lower_bdry_cnt, - valid_lower_boundary_link, min_hblank); - - tu_table->valid_boundary_link = valid_boundary_link; - tu_table->delay_start_link = delay_start_link; - tu_table->boundary_moderation_en = boundary_moderation_en; - tu_table->valid_lower_boundary_link = valid_lower_boundary_link; - tu_table->upper_boundary_count = upper_bdry_cnt; - tu_table->lower_boundary_count = lower_bdry_cnt; - tu_table->tu_size_minus1 = tu_size_minus1; -} - -static void dp_ctrl_setup_tr_unit(struct dp_ctrl_private *ctrl) -{ - u32 dp_tu = 0x0; - u32 valid_boundary = 0x0; - u32 valid_boundary2 = 0x0; - struct dp_vc_tu_mapping_table tu_calc_table; - - dp_ctrl_calc_tu_parameters(ctrl, &tu_calc_table); - - dp_tu |= tu_calc_table.tu_size_minus1; - valid_boundary |= tu_calc_table.valid_boundary_link; - valid_boundary |= (tu_calc_table.delay_start_link << 16); - - valid_boundary2 |= (tu_calc_table.valid_lower_boundary_link << 1); - valid_boundary2 |= (tu_calc_table.upper_boundary_count << 16); - valid_boundary2 |= (tu_calc_table.lower_boundary_count << 20); - - if (tu_calc_table.boundary_moderation_en) - valid_boundary2 |= BIT(0); - - pr_debug("dp_tu=0x%x, valid_boundary=0x%x, valid_boundary2=0x%x\n", - dp_tu, valid_boundary, valid_boundary2); - - ctrl->catalog->dp_tu = dp_tu; - ctrl->catalog->valid_boundary = valid_boundary; - ctrl->catalog->valid_boundary2 = valid_boundary2; - - ctrl->catalog->update_transfer_unit(ctrl->catalog); -} - -static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl) -{ - int ret = 0; - - ret = wait_for_completion_timeout(&ctrl->video_comp, HZ / 2); - if (ret <= 0) { - pr_err("Link Train timedout\n"); - ret = -EINVAL; - } - - return ret; -} - -static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl, - u32 voltage_level, u32 pre_emphasis_level) -{ - int i; - u8 buf[4]; - u32 max_level_reached = 0; - - if (voltage_level == DP_LINK_VOLTAGE_MAX) { - pr_debug("max. voltage swing level reached %d\n", - voltage_level); - max_level_reached |= BIT(2); - } - - if (pre_emphasis_level == DP_LINK_PRE_EMPHASIS_MAX) { - pr_debug("max. pre-emphasis level reached %d\n", - pre_emphasis_level); - max_level_reached |= BIT(5); - } - - pre_emphasis_level <<= 3; - - for (i = 0; i < 4; i++) - buf[i] = voltage_level | pre_emphasis_level | max_level_reached; - - pr_debug("sink: p|v=0x%x\n", voltage_level | pre_emphasis_level); - return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4); -} - -static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl) -{ - struct dp_link *link = ctrl->link; - - ctrl->catalog->update_vx_px(ctrl->catalog, - link->phy_params.v_level, link->phy_params.p_level); - - dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level, - link->phy_params.p_level); -} - -static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl, - u8 pattern) -{ - u8 buf[4]; - - pr_debug("sink: pattern=%x\n", pattern); - - buf[0] = pattern; - drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1); -} - -static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl, - u8 *link_status) -{ - int ret = 0, len; - u32 const offset = DP_LANE_ALIGN_STATUS_UPDATED - DP_LANE0_1_STATUS; - u32 link_status_read_max_retries = 100; - - while (--link_status_read_max_retries) { - len = drm_dp_dpcd_read_link_status(ctrl->aux->drm_aux, - link_status); - if (len != DP_LINK_STATUS_SIZE) { - pr_err("DP link status read failed, err: %d\n", len); - ret = len; - break; - } - - if (!(link_status[offset] & DP_LINK_STATUS_UPDATED)) - break; - } - - return ret; -} - -static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl) -{ - int tries, old_v_level, ret = 0; - u8 link_status[DP_LINK_STATUS_SIZE]; - int const maximum_retries = 5; - - dp_ctrl_state_ctrl(ctrl, 0); - /* Make sure to clear the current pattern before starting a new one */ - wmb(); - - ctrl->catalog->set_pattern(ctrl->catalog, 0x01); - dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 | - DP_LINK_SCRAMBLING_DISABLE); /* train_1 */ - dp_ctrl_update_vx_px(ctrl); - - tries = 0; - old_v_level = ctrl->link->phy_params.v_level; - while (1) { - drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd); - - ret = dp_ctrl_read_link_status(ctrl, link_status); - if (ret) - break; - - if (drm_dp_clock_recovery_ok(link_status, - ctrl->link->link_params.lane_count)) { - break; - } - - if (ctrl->link->phy_params.v_level == DP_LINK_VOLTAGE_MAX) { - pr_err_ratelimited("max v_level reached\n"); - ret = -EAGAIN; - break; - } - - if (old_v_level == ctrl->link->phy_params.v_level) { - tries++; - if (tries >= maximum_retries) { - pr_err("max tries reached\n"); - ret = -ETIMEDOUT; - break; - } - } else { - tries = 0; - old_v_level = ctrl->link->phy_params.v_level; - } - - pr_debug("clock recovery not done, adjusting vx px\n"); - - ctrl->link->adjust_levels(ctrl->link, link_status); - dp_ctrl_update_vx_px(ctrl); - } - - return ret; -} - -static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl) -{ - int ret = 0; - - if (!ctrl) - return -EINVAL; - - switch (ctrl->link->link_params.bw_code) { - case DP_LINK_BW_8_1: - ctrl->link->link_params.bw_code = DP_LINK_BW_5_4; - break; - case DP_LINK_BW_5_4: - ctrl->link->link_params.bw_code = DP_LINK_BW_2_7; - break; - case DP_LINK_BW_2_7: - case DP_LINK_BW_1_62: - default: - ctrl->link->link_params.bw_code = DP_LINK_BW_1_62; - break; - }; - - pr_debug("new bw code=0x%x\n", ctrl->link->link_params.bw_code); - - return ret; -} - -static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl) -{ - dp_ctrl_train_pattern_set(ctrl, 0); - drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); -} - -static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl) -{ - int tries = 0, ret = 0; - char pattern; - int const maximum_retries = 5; - u8 link_status[DP_LINK_STATUS_SIZE]; - - dp_ctrl_state_ctrl(ctrl, 0); - /* Make sure to clear the current pattern before starting a new one */ - wmb(); - - if (drm_dp_tps3_supported(ctrl->panel->dpcd)) - pattern = DP_TRAINING_PATTERN_3; - else - pattern = DP_TRAINING_PATTERN_2; - - dp_ctrl_update_vx_px(ctrl); - ctrl->catalog->set_pattern(ctrl->catalog, pattern); - dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN); - - do { - drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd); - - ret = dp_ctrl_read_link_status(ctrl, link_status); - if (ret) - break; - - if (drm_dp_channel_eq_ok(link_status, - ctrl->link->link_params.lane_count)) - break; - - if (tries > maximum_retries) { - ret = -ETIMEDOUT; - break; - } - tries++; - - ctrl->link->adjust_levels(ctrl->link, link_status); - dp_ctrl_update_vx_px(ctrl); - } while (1); - - return ret; -} - -static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl) -{ - int ret = 0; - u8 encoding = 0x1; - struct drm_dp_link link_info = {0}; - - ctrl->link->phy_params.p_level = 0; - ctrl->link->phy_params.v_level = 0; - - dp_ctrl_config_ctrl(ctrl); - - link_info.num_lanes = ctrl->link->link_params.lane_count; - link_info.rate = drm_dp_bw_code_to_link_rate( - ctrl->link->link_params.bw_code); - link_info.capabilities = ctrl->panel->link_info.capabilities; - - drm_dp_link_configure(ctrl->aux->drm_aux, &link_info); - drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_MAIN_LINK_CHANNEL_CODING_SET, - &encoding, 1); - - ret = dp_ctrl_link_train_1(ctrl); - if (ret) { - pr_err("link training #1 failed\n"); - goto end; - } - - /* print success info as this is a result of user initiated action */ - pr_info("link training #1 successful\n"); - - ret = dp_ctrl_link_training_2(ctrl); - if (ret) { - pr_err("link training #2 failed\n"); - goto end; - } - - /* print success info as this is a result of user initiated action */ - pr_debug("link training #2 successful\n"); - -end: - dp_ctrl_state_ctrl(ctrl, 0); - /* Make sure to clear the current pattern before starting a new one */ - wmb(); - - dp_ctrl_clear_training_pattern(ctrl); - return ret; -} - -static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl, bool train) -{ - bool mainlink_ready = false; - int ret = 0; - - ctrl->catalog->mainlink_ctrl(ctrl->catalog, true); - - ret = ctrl->link->psm_config(ctrl->link, - &ctrl->panel->link_info, false); - if (ret) - goto end; - - if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) - goto end; - - if (!train) - goto send_video; - - /* - * As part of previous calls, DP controller state might have - * transitioned to PUSH_IDLE. In order to start transmitting a link - * training pattern, we have to first to a DP software reset. - */ - ctrl->catalog->reset(ctrl->catalog); - - ret = dp_ctrl_link_train(ctrl); - if (ret) - goto end; - -send_video: - /* - * Set up transfer unit values and set controller state to send - * video. - */ - dp_ctrl_setup_tr_unit(ctrl); - ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO); - - dp_ctrl_wait4video_ready(ctrl); - mainlink_ready = ctrl->catalog->mainlink_ready(ctrl->catalog); - pr_debug("mainlink %s\n", mainlink_ready ? "READY" : "NOT READY"); -end: - return ret; -} - -static void dp_ctrl_set_clock_rate(struct dp_ctrl_private *ctrl, - char *name, u32 rate) -{ - u32 num = ctrl->parser->mp[DP_CTRL_PM].num_clk; - struct dss_clk *cfg = ctrl->parser->mp[DP_CTRL_PM].clk_config; - - while (num && strcmp(cfg->clk_name, name)) { - num--; - cfg++; - } - - pr_debug("setting rate=%d on clk=%s\n", rate, name); - - if (num) - cfg->rate = rate; - else - pr_err("%s clock could not be set with rate %d\n", name, rate); -} - -static int dp_ctrl_enable_mainlink_clocks(struct dp_ctrl_private *ctrl) -{ - int ret = 0; - - ctrl->power->set_pixel_clk_parent(ctrl->power); - - dp_ctrl_set_clock_rate(ctrl, "ctrl_link_clk", - drm_dp_bw_code_to_link_rate(ctrl->link->link_params.bw_code)); - - dp_ctrl_set_clock_rate(ctrl, "ctrl_pixel_clk", ctrl->pixel_rate); - - ret = ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, true); - if (ret) { - pr_err("Unabled to start link clocks\n"); - ret = -EINVAL; - } - - return ret; -} - -static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl) -{ - return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false); -} - -static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip) -{ - struct dp_ctrl_private *ctrl; - struct dp_catalog_ctrl *catalog; - - if (!dp_ctrl) { - pr_err("Invalid input data\n"); - return -EINVAL; - } - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - ctrl->orientation = flip; - catalog = ctrl->catalog; - - catalog->usb_reset(ctrl->catalog, flip); - catalog->phy_reset(ctrl->catalog); - catalog->enable_irq(ctrl->catalog, true); - - return 0; -} - -/** - * dp_ctrl_host_deinit() - Uninitialize DP controller - * @ctrl: Display Port Driver data - * - * Perform required steps to uninitialize DP controller - * and its resources. - */ -static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl) -{ - struct dp_ctrl_private *ctrl; - - if (!dp_ctrl) { - pr_err("Invalid input data\n"); - return; - } - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - ctrl->catalog->enable_irq(ctrl->catalog, false); - - pr_debug("Host deinitialized successfully\n"); -} - -static bool dp_ctrl_use_fixed_nvid(struct dp_ctrl_private *ctrl) -{ - u8 *dpcd = ctrl->panel->dpcd; - - /* - * For better interop experience, used a fixed NVID=0x8000 - * whenever connected to a VGA dongle downstream. - */ - if (dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) { - u8 type = dpcd[DP_DOWNSTREAMPORT_PRESENT] & - DP_DWN_STRM_PORT_TYPE_MASK; - if (type == DP_DWN_STRM_PORT_TYPE_ANALOG) - return true; - } - - return false; -} - -static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl) -{ - int ret = 0; - - ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); - ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); - - ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; - - do { - if (ret == -EAGAIN) { - /* try with lower link rate */ - dp_ctrl_link_rate_down_shift(ctrl); - - ctrl->catalog->mainlink_ctrl(ctrl->catalog, false); - } - - ctrl->catalog->phy_lane_cfg(ctrl->catalog, - ctrl->orientation, ctrl->link->link_params.lane_count); - - /* - * Disable and re-enable the mainlink clock since the - * link clock might have been adjusted as part of the - * link maintenance. - */ - dp_ctrl_disable_mainlink_clocks(ctrl); - - ret = dp_ctrl_enable_mainlink_clocks(ctrl); - if (ret) - continue; - - dp_ctrl_configure_source_params(ctrl); - - ctrl->catalog->config_msa(ctrl->catalog, - drm_dp_bw_code_to_link_rate( - ctrl->link->link_params.bw_code), - ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl)); - - reinit_completion(&ctrl->idle_comp); - - ret = dp_ctrl_setup_main_link(ctrl, true); - } while (ret == -EAGAIN); - - return ret; -} - -static void dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl) -{ - int ret = 0; - - if (!ctrl->link->phy_params.phy_test_pattern_sel) { - pr_debug("no test pattern selected by sink\n"); - return; - } - - pr_debug("start\n"); - - ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl); - /* - * The global reset will need DP link ralated clocks to be - * running. Add the global reset just before disabling the - * link clocks and core clocks. - */ - ctrl->dp_ctrl.reset(&ctrl->dp_ctrl); - ctrl->dp_ctrl.off(&ctrl->dp_ctrl); - - ret = ctrl->dp_ctrl.on(&ctrl->dp_ctrl); - if (ret) - pr_err("failed to enable DP controller\n"); - - pr_debug("end\n"); -} - -static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl) -{ - bool success = false; - u32 pattern_sent = 0x0; - u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel; - - pr_debug("request: %s\n", - dp_link_get_phy_test_pattern(pattern_requested)); - - ctrl->catalog->update_vx_px(ctrl->catalog, - ctrl->link->phy_params.v_level, - ctrl->link->phy_params.p_level); - ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested); - ctrl->link->send_test_response(ctrl->link); - - pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog); - - switch (pattern_sent) { - case MR_LINK_TRAINING1: - if (pattern_requested == - DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING) - success = true; - break; - case MR_LINK_SYMBOL_ERM: - if ((pattern_requested == - DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT) - || (pattern_requested == - DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN)) - success = true; - break; - case MR_LINK_PRBS7: - if (pattern_requested == DP_TEST_PHY_PATTERN_PRBS7) - success = true; - break; - case MR_LINK_CUSTOM80: - if (pattern_requested == - DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN) - success = true; - break; - default: - success = false; - return; - } - - pr_debug("%s: %s\n", success ? "success" : "failed", - dp_link_get_phy_test_pattern(pattern_requested)); -} - -static void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl) -{ - struct dp_ctrl_private *ctrl; - u32 sink_request = 0x0; - - if (!dp_ctrl) { - pr_err("invalid input\n"); - return; - } - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - sink_request = ctrl->link->sink_request; - - if (sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { - pr_info("PHY_TEST_PATTERN request\n"); - dp_ctrl_process_phy_test_request(ctrl); - } - - if (sink_request & DP_LINK_STATUS_UPDATED) - dp_ctrl_link_maintenance(ctrl); - - if (sink_request & DP_TEST_LINK_TRAINING) { - ctrl->link->send_test_response(ctrl->link); - dp_ctrl_link_maintenance(ctrl); - } -} - -static void dp_ctrl_reset(struct dp_ctrl *dp_ctrl) -{ - struct dp_ctrl_private *ctrl; - - if (!dp_ctrl) { - pr_err("invalid params\n"); - return; - } - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - ctrl->catalog->reset(ctrl->catalog); -} - -static int dp_ctrl_on(struct dp_ctrl *dp_ctrl) -{ - int rc = 0; - struct dp_ctrl_private *ctrl; - u32 rate = 0; - u32 link_train_max_retries = 100; - u32 const phy_cts_pixel_clk_khz = 148500; - - if (!dp_ctrl) { - rc = -EINVAL; - goto end; - } - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - atomic_set(&ctrl->aborted, 0); - rate = ctrl->panel->link_info.rate; - - ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true); - ctrl->catalog->hpd_config(ctrl->catalog, true); - - if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) { - pr_debug("using phy test link parameters\n"); - if (!ctrl->panel->pinfo.pixel_clk_khz) - ctrl->pixel_rate = phy_cts_pixel_clk_khz; - } else { - ctrl->link->link_params.bw_code = - drm_dp_link_rate_to_bw_code(rate); - ctrl->link->link_params.lane_count = - ctrl->panel->link_info.num_lanes; - ctrl->pixel_rate = ctrl->panel->pinfo.pixel_clk_khz; - } - - pr_debug("bw_code=%d, lane_count=%d, pixel_rate=%d\n", - ctrl->link->link_params.bw_code, - ctrl->link->link_params.lane_count, ctrl->pixel_rate); - - ctrl->catalog->phy_lane_cfg(ctrl->catalog, - ctrl->orientation, ctrl->link->link_params.lane_count); - - rc = dp_ctrl_enable_mainlink_clocks(ctrl); - if (rc) - goto end; - - reinit_completion(&ctrl->idle_comp); - - dp_ctrl_configure_source_params(ctrl); - - while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) { - ctrl->catalog->config_msa(ctrl->catalog, - drm_dp_bw_code_to_link_rate( - ctrl->link->link_params.bw_code), - ctrl->pixel_rate, dp_ctrl_use_fixed_nvid(ctrl)); - - rc = dp_ctrl_setup_main_link(ctrl, true); - if (!rc) - break; - - /* try with lower link rate */ - dp_ctrl_link_rate_down_shift(ctrl); - - ctrl->catalog->mainlink_ctrl(ctrl->catalog, false); - - dp_ctrl_disable_mainlink_clocks(ctrl); - /* hw recommended delay before re-enabling clocks */ - msleep(20); - - dp_ctrl_enable_mainlink_clocks(ctrl); - } - - if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN) - dp_ctrl_send_phy_test_pattern(ctrl); - - pr_debug("End-\n"); - -end: - return rc; -} - -static void dp_ctrl_off(struct dp_ctrl *dp_ctrl) -{ - struct dp_ctrl_private *ctrl; - - if (!dp_ctrl) - return; - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - ctrl->catalog->mainlink_ctrl(ctrl->catalog, false); - ctrl->catalog->reset(ctrl->catalog); - - /* Make sure DP is disabled before clk disable */ - wmb(); - - dp_ctrl_disable_mainlink_clocks(ctrl); - - pr_debug("DP off done\n"); -} - -static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl) -{ - struct dp_ctrl_private *ctrl; - - if (!dp_ctrl) - return; - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - ctrl->catalog->get_interrupt(ctrl->catalog); - - if (ctrl->catalog->isr & DP_CTRL_INTR_READY_FOR_VIDEO) - dp_ctrl_video_ready(ctrl); - - if (ctrl->catalog->isr & DP_CTRL_INTR_IDLE_PATTERN_SENT) - dp_ctrl_idle_patterns_sent(ctrl); -} - -struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in) -{ - int rc = 0; - struct dp_ctrl_private *ctrl; - struct dp_ctrl *dp_ctrl; - - if (!in->dev || !in->panel || !in->aux || - !in->link || !in->catalog) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - ctrl = devm_kzalloc(in->dev, sizeof(*ctrl), GFP_KERNEL); - if (!ctrl) { - rc = -ENOMEM; - goto error; - } - - init_completion(&ctrl->idle_comp); - init_completion(&ctrl->video_comp); - - /* in parameters */ - ctrl->parser = in->parser; - ctrl->panel = in->panel; - ctrl->power = in->power; - ctrl->aux = in->aux; - ctrl->link = in->link; - ctrl->catalog = in->catalog; - - dp_ctrl = &ctrl->dp_ctrl; - - /* out parameters */ - dp_ctrl->init = dp_ctrl_host_init; - dp_ctrl->deinit = dp_ctrl_host_deinit; - dp_ctrl->on = dp_ctrl_on; - dp_ctrl->off = dp_ctrl_off; - dp_ctrl->push_idle = dp_ctrl_push_idle; - dp_ctrl->abort = dp_ctrl_abort; - dp_ctrl->isr = dp_ctrl_isr; - dp_ctrl->reset = dp_ctrl_reset; - dp_ctrl->handle_sink_request = dp_ctrl_handle_sink_request; - - return dp_ctrl; -error: - return ERR_PTR(rc); -} - -void dp_ctrl_put(struct dp_ctrl *dp_ctrl) -{ - struct dp_ctrl_private *ctrl; - - if (!dp_ctrl) - return; - - ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl); - - devm_kfree(ctrl->dev, ctrl); -} diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h deleted file mode 100644 index 6ab221a..0000000 --- a/drivers/gpu/drm/msm/dp/dp_ctrl.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_CTRL_H_ -#define _DP_CTRL_H_ - -#include "dp_aux.h" -#include "dp_panel.h" -#include "dp_link.h" -#include "dp_parser.h" -#include "dp_power.h" -#include "dp_catalog.h" - -struct dp_ctrl { - int (*init)(struct dp_ctrl *dp_ctrl, bool flip); - void (*deinit)(struct dp_ctrl *dp_ctrl); - int (*on)(struct dp_ctrl *dp_ctrl); - void (*off)(struct dp_ctrl *dp_ctrl); - void (*reset)(struct dp_ctrl *dp_ctrl); - void (*push_idle)(struct dp_ctrl *dp_ctrl); - void (*abort)(struct dp_ctrl *dp_ctrl); - void (*isr)(struct dp_ctrl *dp_ctrl); - void (*handle_sink_request)(struct dp_ctrl *dp_ctrl); -}; - -struct dp_ctrl_in { - struct device *dev; - struct dp_panel *panel; - struct dp_aux *aux; - struct dp_link *link; - struct dp_parser *parser; - struct dp_power *power; - struct dp_catalog_ctrl *catalog; -}; - -struct dp_ctrl *dp_ctrl_get(struct dp_ctrl_in *in); -void dp_ctrl_put(struct dp_ctrl *dp_ctrl); - -#endif /* _DP_CTRL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c deleted file mode 100644 index a48f82e..0000000 --- a/drivers/gpu/drm/msm/dp/dp_debug.c +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/debugfs.h> - -#include "dp_parser.h" -#include "dp_power.h" -#include "dp_catalog.h" -#include "dp_aux.h" -#include "dp_ctrl.h" -#include "dp_debug.h" -#include "drm_connector.h" -#include "dp_display.h" - -#define DEBUG_NAME "drm_dp" - -struct dp_debug_private { - struct dentry *root; - - struct dp_usbpd *usbpd; - struct dp_link *link; - struct dp_panel *panel; - struct drm_connector **connector; - struct device *dev; - - struct dp_debug dp_debug; -}; - -static ssize_t dp_debug_write_hpd(struct file *file, - const char __user *user_buff, size_t count, loff_t *ppos) -{ - struct dp_debug_private *debug = file->private_data; - char buf[SZ_8]; - size_t len = 0; - int hpd; - - if (!debug) - return -ENODEV; - - if (*ppos) - return 0; - - /* Leave room for termination char */ - len = min_t(size_t, count, SZ_8 - 1); - if (copy_from_user(buf, user_buff, len)) - goto end; - - buf[len] = '\0'; - - if (kstrtoint(buf, 10, &hpd) != 0) - goto end; - - debug->usbpd->connect(debug->usbpd, hpd); -end: - return -len; -} - -static ssize_t dp_debug_write_edid_modes(struct file *file, - const char __user *user_buff, size_t count, loff_t *ppos) -{ - struct dp_debug_private *debug = file->private_data; - char buf[SZ_32]; - size_t len = 0; - int hdisplay = 0, vdisplay = 0, vrefresh = 0; - - if (!debug) - return -ENODEV; - - if (*ppos) - goto end; - - /* Leave room for termination char */ - len = min_t(size_t, count, SZ_32 - 1); - if (copy_from_user(buf, user_buff, len)) - goto clear; - - buf[len] = '\0'; - - if (sscanf(buf, "%d %d %d", &hdisplay, &vdisplay, &vrefresh) != 3) - goto clear; - - if (!hdisplay || !vdisplay || !vrefresh) - goto clear; - - debug->dp_debug.debug_en = true; - debug->dp_debug.hdisplay = hdisplay; - debug->dp_debug.vdisplay = vdisplay; - debug->dp_debug.vrefresh = vrefresh; - goto end; -clear: - pr_debug("clearing debug modes\n"); - debug->dp_debug.debug_en = false; -end: - return len; -} - -static ssize_t dp_debug_read_connected(struct file *file, - char __user *user_buff, size_t count, loff_t *ppos) -{ - struct dp_debug_private *debug = file->private_data; - char buf[SZ_8]; - u32 len = 0; - - if (!debug) - return -ENODEV; - - if (*ppos) - return 0; - - len += snprintf(buf, SZ_8, "%d\n", debug->usbpd->hpd_high); - - if (copy_to_user(user_buff, buf, len)) - return -EFAULT; - - *ppos += len; - return len; -} - -static ssize_t dp_debug_read_edid_modes(struct file *file, - char __user *user_buff, size_t count, loff_t *ppos) -{ - struct dp_debug_private *debug = file->private_data; - char *buf; - u32 len = 0; - int rc = 0; - struct drm_connector *connector; - struct drm_display_mode *mode; - - if (!debug) { - pr_err("invalid data\n"); - rc = -ENODEV; - goto error; - } - - connector = *debug->connector; - - if (!connector) { - pr_err("connector is NULL\n"); - rc = -EINVAL; - goto error; - } - - if (*ppos) - goto error; - - buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) { - rc = -ENOMEM; - goto error; - } - - list_for_each_entry(mode, &connector->modes, head) { - len += snprintf(buf + len, SZ_4K - len, - "%s %d %d %d %d %d %d %d %d %d 0x%x\n", - mode->name, mode->vrefresh, mode->hdisplay, - mode->hsync_start, mode->hsync_end, mode->htotal, - mode->vdisplay, mode->vsync_start, mode->vsync_end, - mode->vtotal, mode->flags); - } - - if (copy_to_user(user_buff, buf, len)) { - kfree(buf); - rc = -EFAULT; - goto error; - } - - *ppos += len; - kfree(buf); - - return len; -error: - return rc; -} - -static int dp_debug_check_buffer_overflow(int rc, int *max_size, int *len) -{ - if (rc >= *max_size) { - pr_err("buffer overflow\n"); - return -EINVAL; - } - *len += rc; - *max_size = SZ_4K - *len; - - return 0; -} - -static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff, - size_t count, loff_t *ppos) -{ - struct dp_debug_private *debug = file->private_data; - char *buf; - u32 len = 0, rc = 0; - u64 lclk = 0; - u32 max_size = SZ_4K; - - if (!debug) - return -ENODEV; - - if (*ppos) - return 0; - - buf = kzalloc(SZ_4K, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\tdp_panel\n\t\tmax_pclk_khz = %d\n", - debug->panel->max_pclk_khz); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\tdrm_dp_link\n\t\trate = %u\n", - debug->panel->link_info.rate); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tnum_lanes = %u\n", - debug->panel->link_info.num_lanes); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tcapabilities = %lu\n", - debug->panel->link_info.capabilities); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\tdp_panel_info:\n\t\tactive = %dx%d\n", - debug->panel->pinfo.h_active, - debug->panel->pinfo.v_active); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tback_porch = %dx%d\n", - debug->panel->pinfo.h_back_porch, - debug->panel->pinfo.v_back_porch); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tfront_porch = %dx%d\n", - debug->panel->pinfo.h_front_porch, - debug->panel->pinfo.v_front_porch); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tsync_width = %dx%d\n", - debug->panel->pinfo.h_sync_width, - debug->panel->pinfo.v_sync_width); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tactive_low = %dx%d\n", - debug->panel->pinfo.h_active_low, - debug->panel->pinfo.v_active_low); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\th_skew = %d\n", - debug->panel->pinfo.h_skew); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\trefresh rate = %d\n", - debug->panel->pinfo.refresh_rate); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tpixel clock khz = %d\n", - debug->panel->pinfo.pixel_clk_khz); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tbpp = %d\n", - debug->panel->pinfo.bpp); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - /* Link Information */ - rc = snprintf(buf + len, max_size, - "\tdp_link:\n\t\ttest_requested = %d\n", - debug->link->sink_request); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tlane_count = %d\n", debug->link->link_params.lane_count); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tbw_code = %d\n", debug->link->link_params.bw_code); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - lclk = drm_dp_bw_code_to_link_rate( - debug->link->link_params.bw_code) * 1000; - rc = snprintf(buf + len, max_size, - "\t\tlclk = %lld\n", lclk); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tv_level = %d\n", debug->link->phy_params.v_level); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - rc = snprintf(buf + len, max_size, - "\t\tp_level = %d\n", debug->link->phy_params.p_level); - if (dp_debug_check_buffer_overflow(rc, &max_size, &len)) - goto error; - - if (copy_to_user(user_buff, buf, len)) - goto error; - - *ppos += len; - - kfree(buf); - return len; -error: - kfree(buf); - return -EINVAL; -} - -static const struct file_operations dp_debug_fops = { - .open = simple_open, - .read = dp_debug_read_info, -}; - -static const struct file_operations edid_modes_fops = { - .open = simple_open, - .read = dp_debug_read_edid_modes, - .write = dp_debug_write_edid_modes, -}; - -static const struct file_operations hpd_fops = { - .open = simple_open, - .write = dp_debug_write_hpd, -}; - -static const struct file_operations connected_fops = { - .open = simple_open, - .read = dp_debug_read_connected, -}; - -static int dp_debug_init(struct dp_debug *dp_debug) -{ - int rc = 0; - struct dp_debug_private *debug = container_of(dp_debug, - struct dp_debug_private, dp_debug); - struct dentry *dir, *file, *edid_modes; - struct dentry *hpd, *connected; - struct dentry *root = debug->root; - - dir = debugfs_create_dir(DEBUG_NAME, NULL); - if (IS_ERR_OR_NULL(dir)) { - rc = PTR_ERR(dir); - pr_err("[%s] debugfs create dir failed, rc = %d\n", - DEBUG_NAME, rc); - goto error; - } - - file = debugfs_create_file("dp_debug", 0444, dir, - debug, &dp_debug_fops); - if (IS_ERR_OR_NULL(file)) { - rc = PTR_ERR(file); - pr_err("[%s] debugfs create file failed, rc=%d\n", - DEBUG_NAME, rc); - goto error_remove_dir; - } - - edid_modes = debugfs_create_file("edid_modes", 0644, dir, - debug, &edid_modes_fops); - if (IS_ERR_OR_NULL(edid_modes)) { - rc = PTR_ERR(edid_modes); - pr_err("[%s] debugfs create edid_modes failed, rc=%d\n", - DEBUG_NAME, rc); - goto error_remove_dir; - } - - hpd = debugfs_create_file("hpd", 0644, dir, - debug, &hpd_fops); - if (IS_ERR_OR_NULL(hpd)) { - rc = PTR_ERR(hpd); - pr_err("[%s] debugfs hpd failed, rc=%d\n", - DEBUG_NAME, rc); - goto error_remove_dir; - } - - connected = debugfs_create_file("connected", 0444, dir, - debug, &connected_fops); - if (IS_ERR_OR_NULL(connected)) { - rc = PTR_ERR(connected); - pr_err("[%s] debugfs connected failed, rc=%d\n", - DEBUG_NAME, rc); - goto error_remove_dir; - } - - root = dir; - return rc; -error_remove_dir: - debugfs_remove(dir); -error: - return rc; -} - -struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, - struct dp_usbpd *usbpd, struct dp_link *link, - struct drm_connector **connector) -{ - int rc = 0; - struct dp_debug_private *debug; - struct dp_debug *dp_debug; - - if (!dev || !panel || !usbpd || !link) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - debug = devm_kzalloc(dev, sizeof(*debug), GFP_KERNEL); - if (!debug) { - rc = -ENOMEM; - goto error; - } - - debug->dp_debug.debug_en = false; - debug->usbpd = usbpd; - debug->link = link; - debug->panel = panel; - debug->dev = dev; - debug->connector = connector; - - dp_debug = &debug->dp_debug; - dp_debug->vdisplay = 0; - dp_debug->hdisplay = 0; - dp_debug->vrefresh = 0; - - rc = dp_debug_init(dp_debug); - if (rc) { - devm_kfree(dev, debug); - goto error; - } - - return dp_debug; -error: - return ERR_PTR(rc); -} - -static int dp_debug_deinit(struct dp_debug *dp_debug) -{ - struct dp_debug_private *debug; - - if (!dp_debug) - return -EINVAL; - - debug = container_of(dp_debug, struct dp_debug_private, dp_debug); - - debugfs_remove(debug->root); - - return 0; -} - -void dp_debug_put(struct dp_debug *dp_debug) -{ - struct dp_debug_private *debug; - - if (!dp_debug) - return; - - debug = container_of(dp_debug, struct dp_debug_private, dp_debug); - - dp_debug_deinit(dp_debug); - - devm_kfree(debug->dev, debug); -} diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h deleted file mode 100644 index 06b7acb..0000000 --- a/drivers/gpu/drm/msm/dp/dp_debug.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_DEBUG_H_ -#define _DP_DEBUG_H_ - -#include "dp_panel.h" -#include "dp_link.h" -#include "dp_usbpd.h" - -/** - * struct dp_debug - * @debug_en: specifies whether debug mode enabled - * @vdisplay: used to filter out vdisplay value - * @hdisplay: used to filter out hdisplay value - * @vrefresh: used to filter out vrefresh value - */ -struct dp_debug { - bool debug_en; - int vdisplay; - int hdisplay; - int vrefresh; -}; - -/** - * dp_debug_get() - configure and get the DisplayPlot debug module data - * - * @dev: device instance of the caller - * @panel: instance of panel module - * @usbpd: instance of usbpd module - * @link: instance of link module - * @connector: double pointer to display connector - * return: pointer to allocated debug module data - * - * This function sets up the debug module and provides a way - * for debugfs input to be communicated with existing modules - */ -struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel, - struct dp_usbpd *usbpd, struct dp_link *link, - struct drm_connector **connector); -/** - * dp_debug_put() - * - * Cleans up dp_debug instance - * - * @dp_debug: instance of dp_debug - */ -void dp_debug_put(struct dp_debug *dp_debug); -#endif /* _DP_DEBUG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c deleted file mode 100644 index 846ef33..0000000 --- a/drivers/gpu/drm/msm/dp/dp_display.c +++ /dev/null @@ -1,1255 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/debugfs.h> -#include <linux/component.h> -#include <linux/of_irq.h> -#include <linux/hdcp_qseecom.h> - -#include "msm_drv.h" -#include "dp_usbpd.h" -#include "dp_parser.h" -#include "dp_power.h" -#include "dp_catalog.h" -#include "dp_aux.h" -#include "dp_link.h" -#include "dp_panel.h" -#include "dp_ctrl.h" -#include "dp_audio.h" -#include "dp_display.h" -#include "dpu_hdcp.h" -#include "dp_debug.h" - -static struct dp_display *g_dp_display; -#define HPD_STRING_SIZE 30 - -struct dp_hdcp { - void *data; - struct dpu_hdcp_ops *ops; - - void *hdcp1; - void *hdcp2; - - int enc_lvl; - - bool auth_state; - bool hdcp1_present; - bool hdcp2_present; - bool feature_enabled; -}; - -struct dp_display_private { - char *name; - int irq; - - /* state variables */ - bool core_initialized; - bool power_on; - bool hpd_irq_on; - bool audio_supported; - - struct platform_device *pdev; - struct dentry *root; - struct completion notification_comp; - - struct dp_usbpd *usbpd; - struct dp_parser *parser; - struct dp_power *power; - struct dp_catalog *catalog; - struct dp_aux *aux; - struct dp_link *link; - struct dp_panel *panel; - struct dp_ctrl *ctrl; - struct dp_audio *audio; - struct dp_debug *debug; - - struct dp_hdcp hdcp; - - struct dp_usbpd_cb usbpd_cb; - struct dp_display_mode mode; - struct dp_display dp_display; - - struct workqueue_struct *hdcp_workqueue; - struct delayed_work hdcp_cb_work; - struct mutex hdcp_mutex; - int hdcp_status; -}; - -static const struct of_device_id dp_dt_match[] = { - {.compatible = "qcom,dp-display"}, - {} -}; - -static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp) -{ - return dp->hdcp.feature_enabled && - (dp->hdcp.hdcp1_present || dp->hdcp.hdcp2_present) && - dp->hdcp.ops; -} - -static irqreturn_t dp_display_irq(int irq, void *dev_id) -{ - struct dp_display_private *dp = dev_id; - - if (!dp) { - pr_err("invalid data\n"); - return IRQ_NONE; - } - - /* DP controller isr */ - dp->ctrl->isr(dp->ctrl); - - /* DP aux isr */ - dp->aux->isr(dp->aux); - - /* HDCP isr */ - if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->isr) { - if (dp->hdcp.ops->isr(dp->hdcp.data)) - pr_err("dp_hdcp_isr failed\n"); - } - - return IRQ_HANDLED; -} - -static void dp_display_hdcp_cb_work(struct work_struct *work) -{ - struct dp_display_private *dp; - struct delayed_work *dw = to_delayed_work(work); - struct dpu_hdcp_ops *ops; - int rc = 0; - u32 hdcp_auth_state; - - dp = container_of(dw, struct dp_display_private, hdcp_cb_work); - - rc = dp->catalog->ctrl.read_hdcp_status(&dp->catalog->ctrl); - if (rc >= 0) { - hdcp_auth_state = (rc >> 20) & 0x3; - pr_debug("hdcp auth state %d\n", hdcp_auth_state); - } - - ops = dp->hdcp.ops; - - switch (dp->hdcp_status) { - case HDCP_STATE_AUTHENTICATING: - pr_debug("start authenticaton\n"); - - if (dp->hdcp.ops && dp->hdcp.ops->authenticate) - rc = dp->hdcp.ops->authenticate(dp->hdcp.data); - - break; - case HDCP_STATE_AUTHENTICATED: - pr_debug("hdcp authenticated\n"); - dp->hdcp.auth_state = true; - break; - case HDCP_STATE_AUTH_FAIL: - dp->hdcp.auth_state = false; - - if (dp->power_on) { - pr_debug("Reauthenticating\n"); - if (ops && ops->reauthenticate) { - rc = ops->reauthenticate(dp->hdcp.data); - if (rc) - pr_err("reauth failed rc=%d\n", rc); - } - } else { - pr_debug("not reauthenticating, cable disconnected\n"); - } - - break; - default: - break; - } -} - -static void dp_display_notify_hdcp_status_cb(void *ptr, - enum dpu_hdcp_states status) -{ - struct dp_display_private *dp = ptr; - - if (!dp) { - pr_err("invalid input\n"); - return; - } - - dp->hdcp_status = status; - - if (dp->dp_display.is_connected) - queue_delayed_work(dp->hdcp_workqueue, &dp->hdcp_cb_work, HZ/4); -} - -static int dp_display_create_hdcp_workqueue(struct dp_display_private *dp) -{ - dp->hdcp_workqueue = create_workqueue("sdm_dp_hdcp"); - if (IS_ERR_OR_NULL(dp->hdcp_workqueue)) { - pr_err("Error creating hdcp_workqueue\n"); - return -EPERM; - } - - INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work); - - return 0; -} - -static void dp_display_destroy_hdcp_workqueue(struct dp_display_private *dp) -{ - if (dp->hdcp_workqueue) - destroy_workqueue(dp->hdcp_workqueue); -} - -static void dp_display_update_hdcp_info(struct dp_display_private *dp) -{ - void *fd = NULL; - struct dpu_hdcp_ops *ops = NULL; - - if (!dp) { - pr_err("invalid input\n"); - return; - } - - if (!dp->hdcp.feature_enabled) { - pr_debug("feature not enabled\n"); - return; - } - - fd = dp->hdcp.hdcp2; - if (fd) - ops = dpu_dp_hdcp2p2_start(fd); - - if (ops && ops->feature_supported) - dp->hdcp.hdcp2_present = ops->feature_supported(fd); - else - dp->hdcp.hdcp2_present = false; - - pr_debug("hdcp2p2: %s\n", - dp->hdcp.hdcp2_present ? "supported" : "not supported"); - - if (!dp->hdcp.hdcp2_present) { - dp->hdcp.hdcp1_present = hdcp1_check_if_supported_load_app(); - - if (dp->hdcp.hdcp1_present) { - fd = dp->hdcp.hdcp1; - ops = dpu_hdcp_1x_start(fd); - } - } - - pr_debug("hdcp1x: %s\n", - dp->hdcp.hdcp1_present ? "supported" : "not supported"); - - if (dp->hdcp.hdcp2_present || dp->hdcp.hdcp1_present) { - dp->hdcp.data = fd; - dp->hdcp.ops = ops; - } else { - dp->hdcp.data = NULL; - dp->hdcp.ops = NULL; - } -} - -static void dp_display_deinitialize_hdcp(struct dp_display_private *dp) -{ - if (!dp) { - pr_err("invalid input\n"); - return; - } - - dpu_dp_hdcp2p2_deinit(dp->hdcp.data); - dp_display_destroy_hdcp_workqueue(dp); - mutex_destroy(&dp->hdcp_mutex); -} - -static int dp_display_initialize_hdcp(struct dp_display_private *dp) -{ - struct dpu_hdcp_init_data hdcp_init_data; - struct resource *res; - int rc = 0; - - if (!dp) { - pr_err("invalid input\n"); - return -EINVAL; - } - - mutex_init(&dp->hdcp_mutex); - - rc = dp_display_create_hdcp_workqueue(dp); - if (rc) { - pr_err("Failed to create HDCP workqueue\n"); - goto error; - } - - res = platform_get_resource_byname(dp->pdev, - IORESOURCE_MEM, "dp_ctrl"); - if (!res) { - pr_err("Error getting dp ctrl resource\n"); - rc = -EINVAL; - goto error; - } - - hdcp_init_data.phy_addr = res->start; - hdcp_init_data.client_id = HDCP_CLIENT_DP; - hdcp_init_data.drm_aux = dp->aux->drm_aux; - hdcp_init_data.cb_data = (void *)dp; - hdcp_init_data.workq = dp->hdcp_workqueue; - hdcp_init_data.mutex = &dp->hdcp_mutex; - hdcp_init_data.sec_access = true; - hdcp_init_data.notify_status = dp_display_notify_hdcp_status_cb; - hdcp_init_data.core_io = &dp->parser->io.ctrl_io; - hdcp_init_data.qfprom_io = &dp->parser->io.qfprom_io; - hdcp_init_data.hdcp_io = &dp->parser->io.hdcp_io; - hdcp_init_data.revision = &dp->panel->link_info.revision; - - dp->hdcp.hdcp1 = dpu_hdcp_1x_init(&hdcp_init_data); - if (IS_ERR_OR_NULL(dp->hdcp.hdcp1)) { - pr_err("Error initializing HDCP 1.x\n"); - rc = -EINVAL; - goto error; - } - - pr_debug("HDCP 1.3 initialized\n"); - - dp->hdcp.hdcp2 = dpu_dp_hdcp2p2_init(&hdcp_init_data); - if (!IS_ERR_OR_NULL(dp->hdcp.hdcp2)) - pr_debug("HDCP 2.2 initialized\n"); - - dp->hdcp.feature_enabled = true; - - return 0; -error: - dp_display_deinitialize_hdcp(dp); - return rc; -} - -static int dp_display_bind(struct device *dev, struct device *master, - void *data) -{ - int rc = 0; - struct dp_display_private *dp; - struct drm_device *drm; - struct msm_drm_private *priv; - struct platform_device *pdev = to_platform_device(dev); - - if (!dev || !pdev || !master) { - pr_err("invalid param(s), dev %pK, pdev %pK, master %pK\n", - dev, pdev, master); - rc = -EINVAL; - goto end; - } - - drm = dev_get_drvdata(master); - dp = platform_get_drvdata(pdev); - if (!drm || !dp) { - pr_err("invalid param(s), drm %pK, dp %pK\n", - drm, dp); - rc = -EINVAL; - goto end; - } - - dp->dp_display.drm_dev = drm; - priv = drm->dev_private; - - rc = dp->parser->parse(dp->parser); - if (rc) { - pr_err("device tree parsing failed\n"); - goto end; - } - - rc = dp->aux->drm_aux_register(dp->aux); - if (rc) { - pr_err("DRM DP AUX register failed\n"); - goto end; - } - - rc = dp->power->power_client_init(dp->power, &priv->phandle); - if (rc) { - pr_err("Power client create failed\n"); - goto end; - } - - rc = dp_display_initialize_hdcp(dp); - if (rc) { - pr_err("HDCP initialization failed\n"); - goto end; - } -end: - return rc; -} - -static void dp_display_unbind(struct device *dev, struct device *master, - void *data) -{ - struct dp_display_private *dp; - struct platform_device *pdev = to_platform_device(dev); - - if (!dev || !pdev) { - pr_err("invalid param(s)\n"); - return; - } - - dp = platform_get_drvdata(pdev); - if (!dp) { - pr_err("Invalid params\n"); - return; - } - - (void)dp->power->power_client_deinit(dp->power); - (void)dp->aux->drm_aux_deregister(dp->aux); - dp_display_deinitialize_hdcp(dp); -} - -static const struct component_ops dp_display_comp_ops = { - .bind = dp_display_bind, - .unbind = dp_display_unbind, -}; - -static bool dp_display_is_ds_bridge(struct dp_panel *panel) -{ - return (panel->dpcd[DP_DOWNSTREAMPORT_PRESENT] & - DP_DWN_STRM_PORT_PRESENT); -} - -static bool dp_display_is_sink_count_zero(struct dp_display_private *dp) -{ - return dp_display_is_ds_bridge(dp->panel) && - (dp->link->sink_count.count == 0); -} - -static void dp_display_send_hpd_event(struct dp_display *dp_display) -{ - struct drm_device *dev = NULL; - struct dp_display_private *dp; - struct drm_connector *connector; - char name[HPD_STRING_SIZE], status[HPD_STRING_SIZE], - bpp[HPD_STRING_SIZE], pattern[HPD_STRING_SIZE]; - char *envp[5]; - - if (!dp_display) { - pr_err("invalid input\n"); - return; - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - if (!dp) { - pr_err("invalid params\n"); - return; - } - connector = dp->dp_display.connector; - dev = dp_display->connector->dev; - - connector->status = connector->funcs->detect(connector, false); - pr_debug("[%s] status updated to %s\n", - connector->name, - drm_get_connector_status_name(connector->status)); - snprintf(name, HPD_STRING_SIZE, "name=%s", connector->name); - snprintf(status, HPD_STRING_SIZE, "status=%s", - drm_get_connector_status_name(connector->status)); - snprintf(bpp, HPD_STRING_SIZE, "bpp=%d", - dp_link_bit_depth_to_bpp( - dp->link->test_video.test_bit_depth)); - snprintf(pattern, HPD_STRING_SIZE, "pattern=%d", - dp->link->test_video.test_video_pattern); - - pr_debug("generating hotplug event [%s]:[%s] [%s] [%s]\n", - name, status, bpp, pattern); - envp[0] = name; - envp[1] = status; - envp[2] = bpp; - envp[3] = pattern; - envp[4] = NULL; - kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, - envp); -} - -static int dp_display_send_hpd_notification(struct dp_display_private *dp, - bool hpd) -{ - if ((hpd && dp->dp_display.is_connected) || - (!hpd && !dp->dp_display.is_connected)) { - pr_info("HPD already %s\n", (hpd ? "on" : "off")); - return 0; - } - - /* reset video pattern flag on disconnect */ - if (!hpd) - dp->panel->video_test = false; - - dp->dp_display.is_connected = hpd; - reinit_completion(&dp->notification_comp); - dp_display_send_hpd_event(&dp->dp_display); - - if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 2)) { - pr_warn("%s timeout\n", hpd ? "connect" : "disconnect"); - return -EINVAL; - } - - return 0; -} - -static int dp_display_process_hpd_high(struct dp_display_private *dp) -{ - int rc = 0; - u32 max_pclk_from_edid = 0; - struct edid *edid; - - dp->aux->init(dp->aux, dp->parser->aux_cfg); - - if (dp->link->psm_enabled) - goto notify; - - rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector); - if (rc) - goto notify; - - dp->link->process_request(dp->link); - - if (dp_display_is_sink_count_zero(dp)) { - pr_debug("no downstream devices connected\n"); - rc = -EINVAL; - goto end; - } - - edid = dp->panel->edid_ctrl->edid; - - dp->audio_supported = drm_detect_monitor_audio(edid); - - dp->panel->handle_sink_request(dp->panel); - - max_pclk_from_edid = dp->panel->get_max_pclk(dp->panel); - - dp->dp_display.max_pclk_khz = min(max_pclk_from_edid, - dp->parser->max_pclk_khz); - -notify: - dp_display_send_hpd_notification(dp, true); - -end: - return rc; -} - -static void dp_display_host_init(struct dp_display_private *dp) -{ - bool flip = false; - - if (dp->core_initialized) { - pr_debug("DP core already initialized\n"); - return; - } - - if (dp->usbpd->orientation == ORIENTATION_CC2) - flip = true; - - dp->power->init(dp->power, flip); - dp->ctrl->init(dp->ctrl, flip); - enable_irq(dp->irq); - dp->core_initialized = true; -} - -static void dp_display_host_deinit(struct dp_display_private *dp) -{ - if (!dp->core_initialized) { - pr_debug("DP core already off\n"); - return; - } - - dp->ctrl->deinit(dp->ctrl); - dp->power->deinit(dp->power); - disable_irq(dp->irq); - dp->core_initialized = false; -} - -static void dp_display_process_hpd_low(struct dp_display_private *dp) -{ - /* cancel any pending request */ - dp->ctrl->abort(dp->ctrl); - - if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->off) { - cancel_delayed_work_sync(&dp->hdcp_cb_work); - dp->hdcp.ops->off(dp->hdcp.data); - } - - if (dp->audio_supported) - dp->audio->off(dp->audio); - - dp_display_send_hpd_notification(dp, false); - - dp->aux->deinit(dp->aux); -} - -static int dp_display_usbpd_configure_cb(struct device *dev) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dev) { - pr_err("invalid dev\n"); - rc = -EINVAL; - goto end; - } - - dp = dev_get_drvdata(dev); - if (!dp) { - pr_err("no driver data found\n"); - rc = -ENODEV; - goto end; - } - - dp_display_host_init(dp); - - if (dp->usbpd->hpd_high) - dp_display_process_hpd_high(dp); -end: - return rc; -} - -static void dp_display_clean(struct dp_display_private *dp) -{ - if (dp_display_is_hdcp_enabled(dp)) { - dp->hdcp_status = HDCP_STATE_INACTIVE; - - cancel_delayed_work_sync(&dp->hdcp_cb_work); - if (dp->hdcp.ops->off) - dp->hdcp.ops->off(dp->hdcp.data); - } - - dp->ctrl->push_idle(dp->ctrl); - dp->ctrl->off(dp->ctrl); -} - -static int dp_display_usbpd_disconnect_cb(struct device *dev) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dev) { - pr_err("invalid dev\n"); - rc = -EINVAL; - goto end; - } - - dp = dev_get_drvdata(dev); - if (!dp) { - pr_err("no driver data found\n"); - rc = -ENODEV; - goto end; - } - - /* cancel any pending request */ - dp->ctrl->abort(dp->ctrl); - - if (dp->audio_supported) - dp->audio->off(dp->audio); - - rc = dp_display_send_hpd_notification(dp, false); - - /* if cable is disconnected, reset psm_enabled flag */ - if (!dp->usbpd->alt_mode_cfg_done) - dp->link->psm_enabled = false; - - if ((rc < 0) && dp->power_on) - dp_display_clean(dp); - - dp_display_host_deinit(dp); -end: - return rc; -} - -static void dp_display_handle_video_request(struct dp_display_private *dp) -{ - if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) { - /* force disconnect followed by connect */ - dp->usbpd->connect(dp->usbpd, false); - dp->panel->video_test = true; - dp->usbpd->connect(dp->usbpd, true); - dp->link->send_test_response(dp->link); - } -} - -static int dp_display_handle_hpd_irq(struct dp_display_private *dp) -{ - if (dp->link->sink_request & DS_PORT_STATUS_CHANGED) { - dp_display_send_hpd_notification(dp, false); - - if (dp_display_is_sink_count_zero(dp)) { - pr_debug("sink count is zero, nothing to do\n"); - return 0; - } - - return dp_display_process_hpd_high(dp); - } - - dp->ctrl->handle_sink_request(dp->ctrl); - - dp_display_handle_video_request(dp); - - return 0; -} - -static int dp_display_usbpd_attention_cb(struct device *dev) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dev) { - pr_err("invalid dev\n"); - return -EINVAL; - } - - dp = dev_get_drvdata(dev); - if (!dp) { - pr_err("no driver data found\n"); - return -ENODEV; - } - - if (dp->usbpd->hpd_irq) { - dp->hpd_irq_on = true; - - if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq) { - if (!dp->hdcp.ops->cp_irq(dp->hdcp.data)) - goto end; - } - - rc = dp->link->process_request(dp->link); - /* check for any test request issued by sink */ - if (!rc) - dp_display_handle_hpd_irq(dp); - - dp->hpd_irq_on = false; - goto end; - } - - if (!dp->usbpd->hpd_high) { - dp_display_process_hpd_low(dp); - goto end; - } - - if (dp->usbpd->alt_mode_cfg_done) - dp_display_process_hpd_high(dp); -end: - return rc; -} - -static void dp_display_deinit_sub_modules(struct dp_display_private *dp) -{ - dp_audio_put(dp->audio); - dp_ctrl_put(dp->ctrl); - dp_link_put(dp->link); - dp_panel_put(dp->panel); - dp_aux_put(dp->aux); - dp_power_put(dp->power); - dp_catalog_put(dp->catalog); - dp_parser_put(dp->parser); - dp_usbpd_put(dp->usbpd); - dp_debug_put(dp->debug); -} - -static int dp_init_sub_modules(struct dp_display_private *dp) -{ - int rc = 0; - struct device *dev = &dp->pdev->dev; - struct dp_usbpd_cb *cb = &dp->usbpd_cb; - struct dp_ctrl_in ctrl_in = { - .dev = dev, - }; - struct dp_panel_in panel_in = { - .dev = dev, - }; - - cb->configure = dp_display_usbpd_configure_cb; - cb->disconnect = dp_display_usbpd_disconnect_cb; - cb->attention = dp_display_usbpd_attention_cb; - - dp->usbpd = dp_usbpd_get(dev, cb); - if (IS_ERR(dp->usbpd)) { - rc = PTR_ERR(dp->usbpd); - pr_err("failed to initialize usbpd, rc = %d\n", rc); - dp->usbpd = NULL; - goto error; - } - - dp->parser = dp_parser_get(dp->pdev); - if (IS_ERR(dp->parser)) { - rc = PTR_ERR(dp->parser); - pr_err("failed to initialize parser, rc = %d\n", rc); - dp->parser = NULL; - goto error_parser; - } - - dp->catalog = dp_catalog_get(dev, &dp->parser->io); - if (IS_ERR(dp->catalog)) { - rc = PTR_ERR(dp->catalog); - pr_err("failed to initialize catalog, rc = %d\n", rc); - dp->catalog = NULL; - goto error_catalog; - } - - dp->power = dp_power_get(dp->parser); - if (IS_ERR(dp->power)) { - rc = PTR_ERR(dp->power); - pr_err("failed to initialize power, rc = %d\n", rc); - dp->power = NULL; - goto error_power; - } - - dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser->aux_cfg); - if (IS_ERR(dp->aux)) { - rc = PTR_ERR(dp->aux); - pr_err("failed to initialize aux, rc = %d\n", rc); - dp->aux = NULL; - goto error_aux; - } - - dp->link = dp_link_get(dev, dp->aux); - if (IS_ERR(dp->link)) { - rc = PTR_ERR(dp->link); - pr_err("failed to initialize link, rc = %d\n", rc); - dp->link = NULL; - goto error_link; - } - - panel_in.aux = dp->aux; - panel_in.catalog = &dp->catalog->panel; - panel_in.link = dp->link; - - dp->panel = dp_panel_get(&panel_in); - if (IS_ERR(dp->panel)) { - rc = PTR_ERR(dp->panel); - pr_err("failed to initialize panel, rc = %d\n", rc); - dp->panel = NULL; - goto error_panel; - } - - ctrl_in.link = dp->link; - ctrl_in.panel = dp->panel; - ctrl_in.aux = dp->aux; - ctrl_in.power = dp->power; - ctrl_in.catalog = &dp->catalog->ctrl; - ctrl_in.parser = dp->parser; - - dp->ctrl = dp_ctrl_get(&ctrl_in); - if (IS_ERR(dp->ctrl)) { - rc = PTR_ERR(dp->ctrl); - pr_err("failed to initialize ctrl, rc = %d\n", rc); - dp->ctrl = NULL; - goto error_ctrl; - } - - dp->audio = dp_audio_get(dp->pdev, dp->panel, &dp->catalog->audio); - if (IS_ERR(dp->audio)) { - rc = PTR_ERR(dp->audio); - pr_err("failed to initialize audio, rc = %d\n", rc); - dp->audio = NULL; - goto error_audio; - } - - dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd, - dp->link, &dp->dp_display.connector); - if (IS_ERR(dp->debug)) { - rc = PTR_ERR(dp->debug); - pr_err("failed to initialize debug, rc = %d\n", rc); - dp->debug = NULL; - goto error_debug; - } - - return rc; -error_debug: - dp_audio_put(dp->audio); -error_audio: - dp_ctrl_put(dp->ctrl); -error_ctrl: - dp_panel_put(dp->panel); -error_panel: - dp_link_put(dp->link); -error_link: - dp_aux_put(dp->aux); -error_aux: - dp_power_put(dp->power); -error_power: - dp_catalog_put(dp->catalog); -error_catalog: - dp_parser_put(dp->parser); -error_parser: - dp_usbpd_put(dp->usbpd); -error: - return rc; -} - -static int dp_display_set_mode(struct dp_display *dp_display, - struct dp_display_mode *mode) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dp_display) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - dp = container_of(dp_display, struct dp_display_private, dp_display); - - dp->panel->pinfo = mode->timing; - dp->panel->init_info(dp->panel); -error: - return rc; -} - -static int dp_display_prepare(struct dp_display *dp) -{ - return 0; -} - -static int dp_display_enable(struct dp_display *dp_display) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dp_display) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - if (dp->power_on) { - pr_debug("Link already setup, return\n"); - return 0; - } - - rc = dp->ctrl->on(dp->ctrl); - if (!rc) - dp->power_on = true; -error: - return rc; -} - -static int dp_display_post_enable(struct dp_display *dp_display) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dp_display) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - if (dp->audio_supported) { - dp->audio->bw_code = dp->link->link_params.bw_code; - dp->audio->lane_count = dp->link->link_params.lane_count; - dp->audio->on(dp->audio); - } - - complete_all(&dp->notification_comp); - - dp_display_update_hdcp_info(dp); - - if (dp_display_is_hdcp_enabled(dp)) { - cancel_delayed_work_sync(&dp->hdcp_cb_work); - - dp->hdcp_status = HDCP_STATE_AUTHENTICATING; - queue_delayed_work(dp->hdcp_workqueue, - &dp->hdcp_cb_work, HZ / 2); - } -end: - return rc; -} - -static int dp_display_pre_disable(struct dp_display *dp_display) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dp_display) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - if (dp_display_is_hdcp_enabled(dp)) { - dp->hdcp_status = HDCP_STATE_INACTIVE; - - cancel_delayed_work_sync(&dp->hdcp_cb_work); - if (dp->hdcp.ops->off) - dp->hdcp.ops->off(dp->hdcp.data); - } - - if (dp->usbpd->alt_mode_cfg_done && (dp->usbpd->hpd_high || - dp->usbpd->forced_disconnect)) - dp->link->psm_config(dp->link, &dp->panel->link_info, true); - - dp->ctrl->push_idle(dp->ctrl); -error: - return rc; -} - -static int dp_display_disable(struct dp_display *dp_display) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dp_display) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - if (!dp->power_on || !dp->core_initialized) - goto error; - - dp->ctrl->off(dp->ctrl); - - dp->power_on = false; - - complete_all(&dp->notification_comp); -error: - return rc; -} - -static int dp_request_irq(struct dp_display *dp_display) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!dp_display) { - pr_err("invalid input\n"); - return -EINVAL; - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - dp->irq = irq_of_parse_and_map(dp->pdev->dev.of_node, 0); - if (dp->irq < 0) { - rc = dp->irq; - pr_err("failed to get irq: %d\n", rc); - return rc; - } - - rc = devm_request_irq(&dp->pdev->dev, dp->irq, dp_display_irq, - IRQF_TRIGGER_HIGH, "dp_display_isr", dp); - if (rc < 0) { - pr_err("failed to request IRQ%u: %d\n", - dp->irq, rc); - return rc; - } - disable_irq(dp->irq); - - return 0; -} - -static struct dp_debug *dp_get_debug(struct dp_display *dp_display) -{ - struct dp_display_private *dp; - - if (!dp_display) { - pr_err("invalid input\n"); - return ERR_PTR(-EINVAL); - } - - dp = container_of(dp_display, struct dp_display_private, dp_display); - - return dp->debug; -} - -static int dp_display_unprepare(struct dp_display *dp) -{ - return 0; -} - -static int dp_display_validate_mode(struct dp_display *dp, - struct dp_display_mode *mode) -{ - return 0; -} - -static int dp_display_get_modes(struct dp_display *dp, - struct dp_display_mode *dp_mode) -{ - struct dp_display_private *dp_display; - int ret = 0; - - if (!dp) { - pr_err("invalid params\n"); - return 0; - } - - dp_display = container_of(dp, struct dp_display_private, dp_display); - - ret = dp_display->panel->get_modes(dp_display->panel, - dp->connector, dp_mode); - if (dp_mode->timing.pixel_clk_khz) - dp->max_pclk_khz = dp_mode->timing.pixel_clk_khz; - return ret; -} - -static bool dp_display_check_video_test(struct dp_display *dp) -{ - struct dp_display_private *dp_display; - - if (!dp) { - pr_err("invalid params\n"); - return false; - } - - dp_display = container_of(dp, struct dp_display_private, dp_display); - - if (dp_display->panel->video_test) - return true; - - return false; -} - -static int dp_display_get_test_bpp(struct dp_display *dp) -{ - struct dp_display_private *dp_display; - - if (!dp) { - pr_err("invalid params\n"); - return 0; - } - - dp_display = container_of(dp, struct dp_display_private, dp_display); - - return dp_link_bit_depth_to_bpp( - dp_display->link->test_video.test_bit_depth); -} - -static int dp_display_probe(struct platform_device *pdev) -{ - int rc = 0; - struct dp_display_private *dp; - - if (!pdev || !pdev->dev.of_node) { - pr_err("pdev not found\n"); - return -ENODEV; - } - - dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL); - if (!dp) - return -ENOMEM; - - init_completion(&dp->notification_comp); - - dp->pdev = pdev; - dp->name = "drm_dp"; - - rc = dp_init_sub_modules(dp); - if (rc) { - devm_kfree(&pdev->dev, dp); - return -EPROBE_DEFER; - } - - platform_set_drvdata(pdev, dp); - - g_dp_display = &dp->dp_display; - - g_dp_display->enable = dp_display_enable; - g_dp_display->post_enable = dp_display_post_enable; - g_dp_display->pre_disable = dp_display_pre_disable; - g_dp_display->disable = dp_display_disable; - g_dp_display->set_mode = dp_display_set_mode; - g_dp_display->validate_mode = dp_display_validate_mode; - g_dp_display->get_modes = dp_display_get_modes; - g_dp_display->prepare = dp_display_prepare; - g_dp_display->unprepare = dp_display_unprepare; - g_dp_display->request_irq = dp_request_irq; - g_dp_display->get_debug = dp_get_debug; - g_dp_display->send_hpd_event = dp_display_send_hpd_event; - g_dp_display->is_video_test = dp_display_check_video_test; - g_dp_display->get_test_bpp = dp_display_get_test_bpp; - - rc = component_add(&pdev->dev, &dp_display_comp_ops); - if (rc) { - pr_err("component add failed, rc=%d\n", rc); - dp_display_deinit_sub_modules(dp); - devm_kfree(&pdev->dev, dp); - } - - return rc; -} - -int dp_display_get_displays(void **displays, int count) -{ - if (!displays) { - pr_err("invalid data\n"); - return -EINVAL; - } - - if (count != 1) { - pr_err("invalid number of displays\n"); - return -EINVAL; - } - - displays[0] = g_dp_display; - return count; -} - -int dp_display_get_num_of_displays(void) -{ - return 1; -} - -static int dp_display_remove(struct platform_device *pdev) -{ - struct dp_display_private *dp; - - if (!pdev) - return -EINVAL; - - dp = platform_get_drvdata(pdev); - - dp_display_deinit_sub_modules(dp); - - platform_set_drvdata(pdev, NULL); - devm_kfree(&pdev->dev, dp); - - return 0; -} - -static struct platform_driver dp_display_driver = { - .probe = dp_display_probe, - .remove = dp_display_remove, - .driver = { - .name = "msm-dp-display", - .of_match_table = dp_dt_match, - }, -}; - -static int __init dp_display_init(void) -{ - int ret; - - ret = platform_driver_register(&dp_display_driver); - if (ret) { - pr_err("driver register failed"); - return ret; - } - - return ret; -} -module_init(dp_display_init); - -static void __exit dp_display_cleanup(void) -{ - platform_driver_unregister(&dp_display_driver); -} -module_exit(dp_display_cleanup); - diff --git a/drivers/gpu/drm/msm/dp/dp_display.h b/drivers/gpu/drm/msm/dp/dp_display.h deleted file mode 100644 index 092a0eb..0000000 --- a/drivers/gpu/drm/msm/dp/dp_display.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_DISPLAY_H_ -#define _DP_DISPLAY_H_ - -#include <drm/drmP.h> - -#include "dp_panel.h" - -struct dp_display { - struct drm_device *drm_dev; - struct dp_bridge *bridge; - struct drm_connector *connector; - bool is_connected; - u32 max_pclk_khz; - - int (*enable)(struct dp_display *dp_display); - int (*post_enable)(struct dp_display *dp_display); - - int (*pre_disable)(struct dp_display *dp_display); - int (*disable)(struct dp_display *dp_display); - - int (*set_mode)(struct dp_display *dp_display, - struct dp_display_mode *mode); - int (*validate_mode)(struct dp_display *dp_display, - struct dp_display_mode *mode); - int (*get_modes)(struct dp_display *dp_display, - struct dp_display_mode *dp_mode); - int (*prepare)(struct dp_display *dp_display); - int (*unprepare)(struct dp_display *dp_display); - int (*request_irq)(struct dp_display *dp_display); - struct dp_debug *(*get_debug)(struct dp_display *dp_display); - void (*send_hpd_event)(struct dp_display *dp_display); - bool (*is_video_test)(struct dp_display *dp_display); - int (*get_test_bpp)(struct dp_display *dp_display); -}; - -int dp_display_get_num_of_displays(void); -int dp_display_get_displays(void **displays, int count); -#endif /* _DP_DISPLAY_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_drm.c b/drivers/gpu/drm/msm/dp/dp_drm.c deleted file mode 100644 index a35452f..0000000 --- a/drivers/gpu/drm/msm/dp/dp_drm.c +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp]: %s: " fmt, __func__ - -#include <drm/drm_atomic_helper.h> -#include <drm/drm_atomic.h> -#include <drm/drm_crtc.h> - -#include "msm_drv.h" -#include "msm_kms.h" -#include "dpu_connector.h" -#include "dp_drm.h" -#include "dp_debug.h" - -#define to_dp_bridge(x) container_of((x), struct dp_bridge, base) - -static void convert_to_dp_mode(const struct drm_display_mode *drm_mode, - struct dp_display_mode *dp_mode, struct dp_display *dp) -{ - const u32 num_components = 3; - - memset(dp_mode, 0, sizeof(*dp_mode)); - - dp_mode->timing.h_active = drm_mode->hdisplay; - dp_mode->timing.h_back_porch = drm_mode->htotal - drm_mode->hsync_end; - dp_mode->timing.h_sync_width = drm_mode->htotal - - (drm_mode->hsync_start + dp_mode->timing.h_back_porch); - dp_mode->timing.h_front_porch = drm_mode->hsync_start - - drm_mode->hdisplay; - dp_mode->timing.h_skew = drm_mode->hskew; - - dp_mode->timing.v_active = drm_mode->vdisplay; - dp_mode->timing.v_back_porch = drm_mode->vtotal - drm_mode->vsync_end; - dp_mode->timing.v_sync_width = drm_mode->vtotal - - (drm_mode->vsync_start + dp_mode->timing.v_back_porch); - - dp_mode->timing.v_front_porch = drm_mode->vsync_start - - drm_mode->vdisplay; - - if (dp->is_video_test(dp)) - dp_mode->timing.bpp = dp->get_test_bpp(dp); - else - dp_mode->timing.bpp = dp->connector->display_info.bpc * - num_components; - - if (!dp_mode->timing.bpp) - dp_mode->timing.bpp = 24; - - dp_mode->timing.refresh_rate = drm_mode->vrefresh; - - dp_mode->timing.pixel_clk_khz = drm_mode->clock; - - dp_mode->timing.v_active_low = - !!(drm_mode->flags & DRM_MODE_FLAG_NVSYNC); - - dp_mode->timing.h_active_low = - !!(drm_mode->flags & DRM_MODE_FLAG_NHSYNC); -} - -static void convert_to_drm_mode(const struct dp_display_mode *dp_mode, - struct drm_display_mode *drm_mode) -{ - u32 flags = 0; - - memset(drm_mode, 0, sizeof(*drm_mode)); - - drm_mode->hdisplay = dp_mode->timing.h_active; - drm_mode->hsync_start = drm_mode->hdisplay + - dp_mode->timing.h_front_porch; - drm_mode->hsync_end = drm_mode->hsync_start + - dp_mode->timing.h_sync_width; - drm_mode->htotal = drm_mode->hsync_end + dp_mode->timing.h_back_porch; - drm_mode->hskew = dp_mode->timing.h_skew; - - drm_mode->vdisplay = dp_mode->timing.v_active; - drm_mode->vsync_start = drm_mode->vdisplay + - dp_mode->timing.v_front_porch; - drm_mode->vsync_end = drm_mode->vsync_start + - dp_mode->timing.v_sync_width; - drm_mode->vtotal = drm_mode->vsync_end + dp_mode->timing.v_back_porch; - - drm_mode->vrefresh = dp_mode->timing.refresh_rate; - drm_mode->clock = dp_mode->timing.pixel_clk_khz; - - if (dp_mode->timing.h_active_low) - flags |= DRM_MODE_FLAG_NHSYNC; - else - flags |= DRM_MODE_FLAG_PHSYNC; - - if (dp_mode->timing.v_active_low) - flags |= DRM_MODE_FLAG_NVSYNC; - else - flags |= DRM_MODE_FLAG_PVSYNC; - - drm_mode->flags = flags; - - drm_mode->type = 0x48; - drm_mode_set_name(drm_mode); -} - -static int dp_bridge_attach(struct drm_bridge *dp_bridge) -{ - struct dp_bridge *bridge = to_dp_bridge(dp_bridge); - - if (!dp_bridge) { - pr_err("Invalid params\n"); - return -EINVAL; - } - - pr_debug("[%d] attached\n", bridge->id); - - return 0; -} - -static void dp_bridge_pre_enable(struct drm_bridge *drm_bridge) -{ - int rc = 0; - struct dp_bridge *bridge; - struct dp_display *dp; - - if (!drm_bridge) { - pr_err("Invalid params\n"); - return; - } - - bridge = to_dp_bridge(drm_bridge); - dp = bridge->display; - - /* By this point mode should have been validated through mode_fixup */ - rc = dp->set_mode(dp, &bridge->dp_mode); - if (rc) { - pr_err("[%d] failed to perform a mode set, rc=%d\n", - bridge->id, rc); - return; - } - - rc = dp->prepare(dp); - if (rc) { - pr_err("[%d] DP display prepare failed, rc=%d\n", - bridge->id, rc); - return; - } - - rc = dp->enable(dp); - if (rc) { - pr_err("[%d] DP display enable failed, rc=%d\n", - bridge->id, rc); - dp->unprepare(dp); - } -} - -static void dp_bridge_enable(struct drm_bridge *drm_bridge) -{ - int rc = 0; - struct dp_bridge *bridge; - struct dp_display *dp; - - if (!drm_bridge) { - pr_err("Invalid params\n"); - return; - } - - bridge = to_dp_bridge(drm_bridge); - dp = bridge->display; - - rc = dp->post_enable(dp); - if (rc) - pr_err("[%d] DP display post enable failed, rc=%d\n", - bridge->id, rc); -} - -static void dp_bridge_disable(struct drm_bridge *drm_bridge) -{ - int rc = 0; - struct dp_bridge *bridge; - struct dp_display *dp; - - if (!drm_bridge) { - pr_err("Invalid params\n"); - return; - } - - bridge = to_dp_bridge(drm_bridge); - dp = bridge->display; - - rc = dp->pre_disable(dp); - if (rc) { - pr_err("[%d] DP display pre disable failed, rc=%d\n", - bridge->id, rc); - } -} - -static void dp_bridge_post_disable(struct drm_bridge *drm_bridge) -{ - int rc = 0; - struct dp_bridge *bridge; - struct dp_display *dp; - - if (!drm_bridge) { - pr_err("Invalid params\n"); - return; - } - - bridge = to_dp_bridge(drm_bridge); - dp = bridge->display; - - rc = dp->disable(dp); - if (rc) { - pr_err("[%d] DP display disable failed, rc=%d\n", - bridge->id, rc); - return; - } - - rc = dp->unprepare(dp); - if (rc) { - pr_err("[%d] DP display unprepare failed, rc=%d\n", - bridge->id, rc); - return; - } -} - -static void dp_bridge_mode_set(struct drm_bridge *drm_bridge, - struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - struct dp_bridge *bridge; - struct dp_display *dp; - - if (!drm_bridge || !mode || !adjusted_mode) { - pr_err("Invalid params\n"); - return; - } - - bridge = to_dp_bridge(drm_bridge); - dp = bridge->display; - - memset(&bridge->dp_mode, 0x0, sizeof(struct dp_display_mode)); - convert_to_dp_mode(adjusted_mode, &bridge->dp_mode, dp); -} - -static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge, - const struct drm_display_mode *mode, - struct drm_display_mode *adjusted_mode) -{ - int rc = 0; - bool ret = true; - struct dp_display_mode dp_mode; - struct dp_bridge *bridge; - struct dp_display *dp; - - if (!drm_bridge || !mode || !adjusted_mode) { - pr_err("Invalid params\n"); - ret = false; - goto end; - } - - bridge = to_dp_bridge(drm_bridge); - dp = bridge->display; - - convert_to_dp_mode(mode, &dp_mode, dp); - - rc = dp->validate_mode(dp, &dp_mode); - if (rc) { - pr_err("[%d] mode is not valid, rc=%d\n", bridge->id, rc); - ret = false; - } else { - convert_to_drm_mode(&dp_mode, adjusted_mode); - } -end: - return ret; -} - -static const struct drm_bridge_funcs dp_bridge_ops = { - .attach = dp_bridge_attach, - .mode_fixup = dp_bridge_mode_fixup, - .pre_enable = dp_bridge_pre_enable, - .enable = dp_bridge_enable, - .disable = dp_bridge_disable, - .post_disable = dp_bridge_post_disable, - .mode_set = dp_bridge_mode_set, -}; - -int dp_connector_post_init(struct drm_connector *connector, - void *info, - void *display) -{ - struct dp_display *dp_display = display; - - if (!info || !dp_display) - return -EINVAL; - - dp_display->connector = connector; - return 0; -} - -int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode, - struct msm_mode_info *mode_info, u32 max_mixer_width) -{ - const u32 dual_lm = 2; - const u32 single_lm = 1; - const u32 single_intf = 1; - const u32 no_enc = 0; - struct msm_display_topology *topology; - - if (!drm_mode || !mode_info || !max_mixer_width) { - pr_err("invalid params\n"); - return -EINVAL; - } - - topology = &mode_info->topology; - topology->num_lm = (max_mixer_width <= drm_mode->hdisplay) ? - dual_lm : single_lm; - topology->num_enc = no_enc; - topology->num_intf = single_intf; - - mode_info->frame_rate = drm_mode->vrefresh; - mode_info->vtotal = drm_mode->vtotal; - mode_info->comp_info.comp_type = MSM_DISPLAY_COMPRESSION_NONE; - - return 0; -} - -int dp_connector_get_info(struct msm_display_info *info, void *data) -{ - struct dp_display *display = data; - - if (!info || !display) { - pr_err("invalid params\n"); - return -EINVAL; - } - - info->intf_type = DRM_MODE_CONNECTOR_DisplayPort; - - info->num_of_h_tiles = 1; - info->h_tile_instance[0] = 0; - info->is_connected = display->is_connected; - info->capabilities = MSM_DISPLAY_CAP_VID_MODE | MSM_DISPLAY_CAP_EDID | - MSM_DISPLAY_CAP_HOT_PLUG; - - return 0; -} - -enum drm_connector_status dp_connector_detect(struct drm_connector *conn, - bool force, - void *display) -{ - enum drm_connector_status status = connector_status_unknown; - struct msm_display_info info; - int rc; - - if (!conn || !display) - return status; - - /* get display dp_info */ - memset(&info, 0x0, sizeof(info)); - rc = dp_connector_get_info(&info, display); - if (rc) { - pr_err("failed to get display info, rc=%d\n", rc); - return connector_status_disconnected; - } - - if (info.capabilities & MSM_DISPLAY_CAP_HOT_PLUG) - status = (info.is_connected ? connector_status_connected : - connector_status_disconnected); - else - status = connector_status_connected; - - conn->display_info.width_mm = info.width_mm; - conn->display_info.height_mm = info.height_mm; - - return status; -} - -void dp_connector_send_hpd_event(void *display) -{ - struct dp_display *dp; - - if (!display) { - pr_err("invalid input\n"); - return; - } - - dp = display; - - if (dp->send_hpd_event) - dp->send_hpd_event(dp); -} - -int dp_connector_get_modes(struct drm_connector *connector, - void *display) -{ - int rc = 0; - struct dp_display *dp; - struct dp_display_mode *dp_mode = NULL; - struct drm_display_mode *m, drm_mode; - - if (!connector || !display) - return 0; - - dp = display; - - dp_mode = kzalloc(sizeof(*dp_mode), GFP_KERNEL); - if (!dp_mode) - return 0; - - /* pluggable case assumes EDID is read when HPD */ - if (dp->is_connected) { - rc = dp->get_modes(dp, dp_mode); - if (!rc) - pr_err("failed to get DP sink modes, rc=%d\n", rc); - - if (dp_mode->timing.pixel_clk_khz) { /* valid DP mode */ - memset(&drm_mode, 0x0, sizeof(drm_mode)); - convert_to_drm_mode(dp_mode, &drm_mode); - m = drm_mode_duplicate(connector->dev, &drm_mode); - if (!m) { - pr_err("failed to add mode %ux%u\n", - drm_mode.hdisplay, - drm_mode.vdisplay); - kfree(dp_mode); - return 0; - } - m->width_mm = connector->display_info.width_mm; - m->height_mm = connector->display_info.height_mm; - drm_mode_probed_add(connector, m); - } - } else { - pr_err("No sink connected\n"); - } - kfree(dp_mode); - - return rc; -} - -int dp_drm_bridge_init(void *data, struct drm_encoder *encoder) -{ - int rc = 0; - struct dp_bridge *bridge; - struct drm_device *dev; - struct dp_display *display = data; - struct msm_drm_private *priv = NULL; - - bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); - if (!bridge) { - rc = -ENOMEM; - goto error; - } - - dev = display->drm_dev; - bridge->display = display; - bridge->base.funcs = &dp_bridge_ops; - bridge->base.encoder = encoder; - - priv = dev->dev_private; - - rc = drm_bridge_attach(encoder, &bridge->base, NULL); - if (rc) { - pr_err("failed to attach bridge, rc=%d\n", rc); - goto error_free_bridge; - } - - rc = display->request_irq(display); - if (rc) { - pr_err("request_irq failed, rc=%d\n", rc); - goto error_free_bridge; - } - - encoder->bridge = &bridge->base; - priv->bridges[priv->num_bridges++] = &bridge->base; - display->bridge = bridge; - - return 0; -error_free_bridge: - kfree(bridge); -error: - return rc; -} - -void dp_drm_bridge_deinit(void *data) -{ - struct dp_display *display = data; - struct dp_bridge *bridge = display->bridge; - - if (bridge && bridge->base.encoder) - bridge->base.encoder->bridge = NULL; - - kfree(bridge); -} - -enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode, - void *display) -{ - struct dp_display *dp_disp; - struct dp_debug *debug; - - if (!mode || !display) { - pr_err("invalid params\n"); - return MODE_ERROR; - } - - dp_disp = display; - debug = dp_disp->get_debug(dp_disp); - - if (debug->debug_en) { - if (mode->hdisplay == debug->hdisplay && - mode->vdisplay == debug->vdisplay && - mode->vrefresh == debug->vrefresh && - mode->clock <= dp_disp->max_pclk_khz) - return MODE_OK; - else - return MODE_ERROR; - } else { - if (mode->vrefresh == 0) { - int vrefresh = (mode->clock * 1000) / - (mode->vtotal * mode->htotal); - if (vrefresh > 60) - return MODE_BAD; - } - - if (mode->clock > dp_disp->max_pclk_khz) - return MODE_BAD; - else - return MODE_OK; - } -} diff --git a/drivers/gpu/drm/msm/dp/dp_drm.h b/drivers/gpu/drm/msm/dp/dp_drm.h deleted file mode 100644 index 08d1f2d..0000000 --- a/drivers/gpu/drm/msm/dp/dp_drm.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_DRM_H_ -#define _DP_DRM_H_ - -#include <linux/types.h> -#include <drm/drmP.h> -#include <drm/drm_crtc.h> -#include <drm/drm_crtc_helper.h> - -#include "msm_drv.h" -#include "dp_display.h" - -struct dp_bridge { - struct drm_bridge base; - u32 id; - - struct dp_display *display; - struct dp_display_mode dp_mode; -}; - -/** - * dp_connector_post_init - callback to perform additional initialization steps - * @connector: Pointer to drm connector structure - * @info: Pointer to dpu connector info structure - * @display: Pointer to private display handle - * Returns: Zero on success - */ -int dp_connector_post_init(struct drm_connector *connector, - void *info, - void *display); - -/** - * dp_connector_detect - callback to determine if connector is connected - * @connector: Pointer to drm connector structure - * @force: Force detect setting from drm framework - * @display: Pointer to private display handle - * Returns: Connector 'is connected' status - */ -enum drm_connector_status dp_connector_detect(struct drm_connector *conn, - bool force, - void *display); - -/** - * dp_connector_get_modes - callback to add drm modes via drm_mode_probed_add() - * @connector: Pointer to drm connector structure - * @display: Pointer to private display handle - * Returns: Number of modes added - */ -int dp_connector_get_modes(struct drm_connector *connector, - void *display); - -/** - * dp_connector_mode_valid - callback to determine if specified mode is valid - * @connector: Pointer to drm connector structure - * @mode: Pointer to drm mode structure - * @display: Pointer to private display handle - * Returns: Validity status for specified mode - */ -enum drm_mode_status dp_connector_mode_valid(struct drm_connector *connector, - struct drm_display_mode *mode, - void *display); - -/** - * dp_connector_get_mode_info - retrieve information of the mode selected - * @drm_mode: Display mode set for the display - * @mode_info: Out parameter. Information of the mode - * @max_mixer_width: max width supported by HW layer mixer - * Returns: zero on success - */ -int dp_connector_get_mode_info(const struct drm_display_mode *drm_mode, - struct msm_mode_info *mode_info, - u32 max_mixer_width); - -int dp_connector_get_info(struct msm_display_info *info, void *display); - -void dp_connector_send_hpd_event(void *display); - -int dp_drm_bridge_init(void *display, - struct drm_encoder *encoder); - -void dp_drm_bridge_deinit(void *display); -#endif /* _DP_DRM_H_ */ - diff --git a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c b/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c deleted file mode 100644 index 2366469..0000000 --- a/drivers/gpu/drm/msm/dp/dp_hdcp2p2.c +++ /dev/null @@ -1,927 +0,0 @@ -/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#define pr_fmt(fmt) "[dp-hdcp2p2] %s: " fmt, __func__ - -#include <linux/delay.h> -#include <linux/io.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/types.h> -#include <linux/kthread.h> -#include <linux/hdcp_qseecom.h> -#include <drm/drm_dp_helper.h> - -#include "dpu_hdcp.h" - -#define DP_INTR_STATUS2 (0x00000024) -#define DP_INTR_STATUS3 (0x00000028) -#define dp_read(offset) readl_relaxed((offset)) -#define dp_write(offset, data) writel_relaxed((data), (offset)) -#define DP_HDCP_RXCAPS_LENGTH 3 - -enum dp_hdcp2p2_sink_status { - SINK_DISCONNECTED, - SINK_CONNECTED -}; - -enum dp_auth_status { - DP_HDCP_AUTH_STATUS_FAILURE, - DP_HDCP_AUTH_STATUS_SUCCESS -}; - -struct dp_hdcp2p2_ctrl { - atomic_t auth_state; - enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */ - struct dp_hdcp2p2_interrupts *intr; - struct dpu_hdcp_init_data init_data; - struct mutex mutex; /* mutex to protect access to ctrl */ - struct mutex msg_lock; /* mutex to protect access to msg buffer */ - struct mutex wakeup_mutex; /* mutex to protect access to wakeup call*/ - struct dpu_hdcp_ops *ops; - void *lib_ctx; /* Handle to HDCP 2.2 Trustzone library */ - struct hdcp_txmtr_ops *lib; /* Ops for driver to call into TZ */ - enum hdcp_wakeup_cmd wakeup_cmd; - enum dp_auth_status auth_status; - - struct task_struct *thread; - struct kthread_worker worker; - struct kthread_work status; - struct kthread_work auth; - struct kthread_work send_msg; - struct kthread_work recv_msg; - struct kthread_work link; - char *msg_buf; - uint32_t send_msg_len; /* length of all parameters in msg */ - uint32_t timeout; - uint32_t num_messages; - struct hdcp_msg_part msg_part[HDCP_MAX_MESSAGE_PARTS]; - u8 sink_rx_status; - u8 rx_status; - char abort_mask; - - bool cp_irq_done; - bool polling; -}; - -struct dp_hdcp2p2_int_set { - u32 interrupt; - char *name; - void (*func)(struct dp_hdcp2p2_ctrl *ctrl); -}; - -struct dp_hdcp2p2_interrupts { - u32 reg; - struct dp_hdcp2p2_int_set *int_set; -}; - -static inline bool dp_hdcp2p2_is_valid_state(struct dp_hdcp2p2_ctrl *ctrl) -{ - if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_AUTHENTICATE) - return true; - - if (atomic_read(&ctrl->auth_state) != HDCP_STATE_INACTIVE) - return true; - - return false; -} - -static int dp_hdcp2p2_copy_buf(struct dp_hdcp2p2_ctrl *ctrl, - struct hdcp_wakeup_data *data) -{ - int i = 0; - - if (!data || !data->message_data) - return 0; - - mutex_lock(&ctrl->msg_lock); - - ctrl->timeout = data->timeout; - ctrl->num_messages = data->message_data->num_messages; - ctrl->send_msg_len = 0; /* Total len of all messages */ - - for (i = 0; i < ctrl->num_messages ; i++) - ctrl->send_msg_len += data->message_data->messages[i].length; - - memcpy(ctrl->msg_part, data->message_data->messages, - sizeof(data->message_data->messages)); - - ctrl->rx_status = data->message_data->rx_status; - ctrl->abort_mask = data->abort_mask; - - if (!data->send_msg_len) { - mutex_unlock(&ctrl->msg_lock); - return 0; - } - - kzfree(ctrl->msg_buf); - - ctrl->msg_buf = kzalloc(ctrl->send_msg_len, GFP_KERNEL); - - if (!ctrl->msg_buf) { - mutex_unlock(&ctrl->msg_lock); - return -ENOMEM; - } - - /* ignore first byte as it contains message id */ - memcpy(ctrl->msg_buf, data->send_msg_buf + 1, ctrl->send_msg_len); - - mutex_unlock(&ctrl->msg_lock); - - return 0; -} - -static int dp_hdcp2p2_wakeup(struct hdcp_wakeup_data *data) -{ - struct dp_hdcp2p2_ctrl *ctrl; - u32 const default_timeout_us = 500; - - if (!data) { - pr_err("invalid input\n"); - return -EINVAL; - } - - ctrl = data->context; - if (!ctrl) { - pr_err("invalid ctrl\n"); - return -EINVAL; - } - - mutex_lock(&ctrl->wakeup_mutex); - - ctrl->wakeup_cmd = data->cmd; - - if (data->timeout) - ctrl->timeout = (data->timeout) * 2; - else - ctrl->timeout = default_timeout_us; - - if (!dp_hdcp2p2_is_valid_state(ctrl)) { - pr_err("invalid state\n"); - goto exit; - } - - if (dp_hdcp2p2_copy_buf(ctrl, data)) - goto exit; - - if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_SUCCESS) - ctrl->auth_status = DP_HDCP_AUTH_STATUS_SUCCESS; - else if (ctrl->wakeup_cmd == HDCP_WKUP_CMD_STATUS_FAILED) - ctrl->auth_status = DP_HDCP_AUTH_STATUS_FAILURE; - - switch (ctrl->wakeup_cmd) { - case HDCP_WKUP_CMD_SEND_MESSAGE: - kthread_queue_work(&ctrl->worker, &ctrl->send_msg); - break; - case HDCP_WKUP_CMD_RECV_MESSAGE: - kthread_queue_work(&ctrl->worker, &ctrl->recv_msg); - break; - case HDCP_WKUP_CMD_STATUS_SUCCESS: - case HDCP_WKUP_CMD_STATUS_FAILED: - kthread_queue_work(&ctrl->worker, &ctrl->status); - break; - case HDCP_WKUP_CMD_LINK_POLL: - if (ctrl->cp_irq_done) - kthread_queue_work(&ctrl->worker, &ctrl->recv_msg); - else - ctrl->polling = true; - break; - case HDCP_WKUP_CMD_AUTHENTICATE: - kthread_queue_work(&ctrl->worker, &ctrl->auth); - break; - default: - pr_err("invalid wakeup command %d\n", ctrl->wakeup_cmd); - } -exit: - mutex_unlock(&ctrl->wakeup_mutex); - - return 0; -} - -static inline void dp_hdcp2p2_wakeup_lib(struct dp_hdcp2p2_ctrl *ctrl, - struct hdcp_lib_wakeup_data *data) -{ - int rc = 0; - - if (ctrl && ctrl->lib && ctrl->lib->wakeup && - data && (data->cmd != HDCP_LIB_WKUP_CMD_INVALID)) { - rc = ctrl->lib->wakeup(data); - if (rc) - pr_err("error sending %s to lib\n", - hdcp_lib_cmd_to_str(data->cmd)); - } -} - -static void dp_hdcp2p2_reset(struct dp_hdcp2p2_ctrl *ctrl) -{ - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - ctrl->sink_status = SINK_DISCONNECTED; - atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); -} - -static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable) -{ - void __iomem *base = ctrl->init_data.core_io->base; - struct dp_hdcp2p2_interrupts *intr = ctrl->intr; - - while (intr && intr->reg) { - struct dp_hdcp2p2_int_set *int_set = intr->int_set; - u32 interrupts = 0; - - while (int_set && int_set->interrupt) { - interrupts |= int_set->interrupt; - int_set++; - } - - if (enable) - dp_write(base + intr->reg, - dp_read(base + intr->reg) | interrupts); - else - dp_write(base + intr->reg, - dp_read(base + intr->reg) & ~interrupts); - intr++; - } -} - -static void dp_hdcp2p2_off(void *input) -{ - struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; - struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE}; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { - pr_err("hdcp is off\n"); - return; - } - - dp_hdcp2p2_set_interrupts(ctrl, false); - - dp_hdcp2p2_reset(ctrl); - - kthread_flush_worker(&ctrl->worker); - - cdata.context = input; - dp_hdcp2p2_wakeup(&cdata); -} - -static int dp_hdcp2p2_authenticate(void *input) -{ - struct dp_hdcp2p2_ctrl *ctrl = input; - struct hdcp_wakeup_data cdata = {HDCP_WKUP_CMD_AUTHENTICATE}; - int rc = 0; - - kthread_flush_worker(&ctrl->worker); - - dp_hdcp2p2_set_interrupts(ctrl, true); - - ctrl->sink_status = SINK_CONNECTED; - atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATING); - - cdata.context = input; - dp_hdcp2p2_wakeup(&cdata); - - return rc; -} - -static int dp_hdcp2p2_reauthenticate(void *input) -{ - struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; - - if (!ctrl) { - pr_err("invalid input\n"); - return -EINVAL; - } - - dp_hdcp2p2_reset((struct dp_hdcp2p2_ctrl *)input); - - return dp_hdcp2p2_authenticate(input); -} - -static void dp_hdcp2p2_min_level_change(void *client_ctx, - int min_enc_level) -{ - struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)client_ctx; - struct hdcp_lib_wakeup_data cdata = { - HDCP_LIB_WKUP_CMD_QUERY_STREAM_TYPE}; - bool enc_notify = true; - int enc_lvl; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - switch (min_enc_level) { - case 0: - enc_lvl = HDCP_STATE_AUTH_ENC_NONE; - break; - case 1: - enc_lvl = HDCP_STATE_AUTH_ENC_1X; - break; - case 2: - enc_lvl = HDCP_STATE_AUTH_ENC_2P2; - break; - default: - enc_notify = false; - } - - pr_debug("enc level changed %d\n", min_enc_level); - - cdata.context = ctrl->lib_ctx; - dp_hdcp2p2_wakeup_lib(ctrl, &cdata); - - if (enc_notify && ctrl->init_data.notify_status) - ctrl->init_data.notify_status(ctrl->init_data.cb_data, enc_lvl); -} - -static void dp_hdcp2p2_auth_failed(struct dp_hdcp2p2_ctrl *ctrl) -{ - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - dp_hdcp2p2_set_interrupts(ctrl, false); - - atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); - - /* notify DP about HDCP failure */ - ctrl->init_data.notify_status(ctrl->init_data.cb_data, - HDCP_STATE_AUTH_FAIL); -} - -static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl, - u8 *buf, int size, int offset, u32 timeout) -{ - int const max_size = 16; - int rc = 0, read_size = 0, bytes_read = 0; - - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { - pr_err("hdcp is off\n"); - return -EINVAL; - } - - do { - read_size = min(size, max_size); - - bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, - offset, buf, read_size); - if (bytes_read != read_size) { - pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", - offset, read_size, bytes_read); - break; - } - - buf += read_size; - offset += read_size; - size -= read_size; - } while (size > 0); - - return rc; -} - -static int dp_hdcp2p2_aux_write_message(struct dp_hdcp2p2_ctrl *ctrl, - u8 *buf, int size, uint offset, uint timeout) -{ - int const max_size = 16; - int rc = 0, write_size = 0, bytes_written = 0; - - do { - write_size = min(size, max_size); - - bytes_written = drm_dp_dpcd_write(ctrl->init_data.drm_aux, - offset, buf, write_size); - if (bytes_written != write_size) { - pr_err("fail: offset(0x%x), size(0x%x), rc(0x%x)\n", - offset, write_size, bytes_written); - break; - } - - buf += write_size; - offset += write_size; - size -= write_size; - } while (size > 0); - - return rc; -} - -static bool dp_hdcp2p2_feature_supported(void *input) -{ - struct dp_hdcp2p2_ctrl *ctrl = input; - struct hdcp_txmtr_ops *lib = NULL; - bool supported = false; - - if (!ctrl) { - pr_err("invalid input\n"); - goto end; - } - - lib = ctrl->lib; - if (!lib) { - pr_err("invalid lib ops data\n"); - goto end; - } - - if (lib->feature_supported) - supported = lib->feature_supported( - ctrl->lib_ctx); -end: - return supported; -} - -static void dp_hdcp2p2_send_msg_work(struct kthread_work *work) -{ - int rc = 0; - struct dp_hdcp2p2_ctrl *ctrl = container_of(work, - struct dp_hdcp2p2_ctrl, send_msg); - struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; - - if (!ctrl) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto exit; - } - - cdata.context = ctrl->lib_ctx; - - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { - pr_err("hdcp is off\n"); - goto exit; - } - - mutex_lock(&ctrl->msg_lock); - - rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->msg_buf, - ctrl->send_msg_len, ctrl->msg_part->offset, - ctrl->timeout); - if (rc) { - pr_err("Error sending msg to sink %d\n", rc); - mutex_unlock(&ctrl->msg_lock); - goto exit; - } - - cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_SEND_SUCCESS; - cdata.timeout = ctrl->timeout; - mutex_unlock(&ctrl->msg_lock); - -exit: - if (rc == -ETIMEDOUT) - cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT; - else if (rc) - cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED; - - dp_hdcp2p2_wakeup_lib(ctrl, &cdata); -} - -static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl) -{ - int rc = 0; - char *recvd_msg_buf = NULL; - struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID }; - - cdata.context = ctrl->lib_ctx; - - recvd_msg_buf = kzalloc(ctrl->send_msg_len, GFP_KERNEL); - if (!recvd_msg_buf) { - rc = -ENOMEM; - goto exit; - } - - rc = dp_hdcp2p2_aux_read_message(ctrl, recvd_msg_buf, - ctrl->send_msg_len, ctrl->msg_part->offset, - ctrl->timeout); - if (rc) { - pr_err("error reading message %d\n", rc); - goto exit; - } - - cdata.recvd_msg_buf = recvd_msg_buf; - cdata.recvd_msg_len = ctrl->send_msg_len; - cdata.timeout = ctrl->timeout; -exit: - if (rc == -ETIMEDOUT) - cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_TIMEOUT; - else if (rc) - cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_FAILED; - else - cdata.cmd = HDCP_LIB_WKUP_CMD_MSG_RECV_SUCCESS; - - dp_hdcp2p2_wakeup_lib(ctrl, &cdata); - kfree(recvd_msg_buf); - - return rc; -} - -static void dp_hdcp2p2_recv_msg_work(struct kthread_work *work) -{ - struct hdcp_lib_wakeup_data cdata = { HDCP_LIB_WKUP_CMD_INVALID }; - struct dp_hdcp2p2_ctrl *ctrl = container_of(work, - struct dp_hdcp2p2_ctrl, recv_msg); - - cdata.context = ctrl->lib_ctx; - - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { - pr_err("hdcp is off\n"); - return; - } - - if (ctrl->rx_status) { - if (!ctrl->cp_irq_done) { - pr_debug("waiting for CP_IRQ\n"); - ctrl->polling = true; - return; - } - - if (ctrl->rx_status & ctrl->sink_rx_status) { - ctrl->cp_irq_done = false; - ctrl->sink_rx_status = 0; - ctrl->rx_status = 0; - } - } - - dp_hdcp2p2_get_msg_from_sink(ctrl); -} - -static void dp_hdcp2p2_auth_status_work(struct kthread_work *work) -{ - struct dp_hdcp2p2_ctrl *ctrl = container_of(work, - struct dp_hdcp2p2_ctrl, status); - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { - pr_err("hdcp is off\n"); - return; - } - - if (ctrl->auth_status == DP_HDCP_AUTH_STATUS_SUCCESS) { - ctrl->init_data.notify_status(ctrl->init_data.cb_data, - HDCP_STATE_AUTHENTICATED); - - atomic_set(&ctrl->auth_state, HDCP_STATE_AUTHENTICATED); - } else { - dp_hdcp2p2_auth_failed(ctrl); - } -} - -static void dp_hdcp2p2_link_work(struct kthread_work *work) -{ - int rc = 0; - struct dp_hdcp2p2_ctrl *ctrl = container_of(work, - struct dp_hdcp2p2_ctrl, link); - struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || - atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { - pr_err("invalid hdcp state\n"); - return; - } - - cdata.context = ctrl->lib_ctx; - - if (ctrl->sink_rx_status & ctrl->abort_mask) { - if (ctrl->sink_rx_status & BIT(3)) - pr_err("reauth_req set by sink\n"); - - if (ctrl->sink_rx_status & BIT(4)) - pr_err("link failure reported by sink\n"); - - ctrl->sink_rx_status = 0; - ctrl->rx_status = 0; - - rc = -ENOLINK; - - cdata.cmd = HDCP_LIB_WKUP_CMD_LINK_FAILED; - atomic_set(&ctrl->auth_state, HDCP_STATE_AUTH_FAIL); - goto exit; - } - - if (ctrl->polling && (ctrl->sink_rx_status & ctrl->rx_status)) { - ctrl->sink_rx_status = 0; - ctrl->rx_status = 0; - - dp_hdcp2p2_get_msg_from_sink(ctrl); - - ctrl->polling = false; - } else { - ctrl->cp_irq_done = true; - } -exit: - if (rc) - dp_hdcp2p2_wakeup_lib(ctrl, &cdata); -} - -static void dp_hdcp2p2_auth_work(struct kthread_work *work) -{ - struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; - struct dp_hdcp2p2_ctrl *ctrl = container_of(work, - struct dp_hdcp2p2_ctrl, auth); - - cdata.context = ctrl->lib_ctx; - - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTHENTICATING) - cdata.cmd = HDCP_LIB_WKUP_CMD_START; - else - cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; - - dp_hdcp2p2_wakeup_lib(ctrl, &cdata); -} - -static int dp_hdcp2p2_read_rx_status(struct dp_hdcp2p2_ctrl *ctrl, - u8 *rx_status) -{ - u32 const cp_irq_dpcd_offset = 0x201; - u32 const rxstatus_dpcd_offset = 0x69493; - ssize_t const bytes_to_read = 1; - ssize_t bytes_read = 0; - u8 buf = 0; - int rc = 0; - bool cp_irq = 0; - - *rx_status = 0; - - bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, - cp_irq_dpcd_offset, &buf, bytes_to_read); - if (bytes_read != bytes_to_read) { - pr_err("cp irq read failed\n"); - rc = bytes_read; - goto error; - } - - cp_irq = buf & BIT(2); - pr_debug("cp_irq=0x%x\n", cp_irq); - buf = 0; - - if (cp_irq) { - bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, - rxstatus_dpcd_offset, &buf, bytes_to_read); - if (bytes_read != bytes_to_read) { - pr_err("rxstatus read failed\n"); - rc = bytes_read; - goto error; - } - *rx_status = buf; - pr_debug("rx_status=0x%x\n", *rx_status); - } - -error: - return rc; -} - -static int dp_hdcp2p2_cp_irq(void *input) -{ - int rc = 0; - struct dp_hdcp2p2_ctrl *ctrl = input; - - if (!ctrl) { - pr_err("invalid input\n"); - return -EINVAL; - } - - if (atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL || - atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE) { - pr_err("invalid hdcp state\n"); - rc = -EINVAL; - goto error; - } - - ctrl->sink_rx_status = 0; - rc = dp_hdcp2p2_read_rx_status(ctrl, &ctrl->sink_rx_status); - if (rc) { - pr_err("failed to read rx status\n"); - goto error; - } - - pr_debug("sink_rx_status=0x%x\n", ctrl->sink_rx_status); - - if (!ctrl->sink_rx_status) { - pr_debug("not a hdcp 2.2 irq\n"); - rc = -EINVAL; - goto error; - } - - kthread_queue_work(&ctrl->worker, &ctrl->link); - - return 0; -error: - return rc; -} - -static int dp_hdcp2p2_isr(void *input) -{ - struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; - int rc = 0; - struct dss_io_data *io; - struct dp_hdcp2p2_interrupts *intr; - u32 hdcp_int_val = 0; - - if (!ctrl || !ctrl->init_data.core_io) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - io = ctrl->init_data.core_io; - intr = ctrl->intr; - - while (intr && intr->reg) { - struct dp_hdcp2p2_int_set *int_set = intr->int_set; - - hdcp_int_val = dp_read(io->base + intr->reg); - - while (int_set && int_set->interrupt) { - if (hdcp_int_val & (int_set->interrupt >> 2)) { - pr_debug("%s\n", int_set->name); - - if (int_set->func) - int_set->func(ctrl); - - dp_write(io->base + intr->reg, hdcp_int_val | - (int_set->interrupt >> 1)); - } - int_set++; - } - intr++; - } -end: - return rc; -} - -void dpu_dp_hdcp2p2_deinit(void *input) -{ - struct dp_hdcp2p2_ctrl *ctrl = (struct dp_hdcp2p2_ctrl *)input; - struct hdcp_lib_wakeup_data cdata = {HDCP_LIB_WKUP_CMD_INVALID}; - - if (!ctrl) { - pr_err("invalid input\n"); - return; - } - - cdata.cmd = HDCP_LIB_WKUP_CMD_STOP; - cdata.context = ctrl->lib_ctx; - dp_hdcp2p2_wakeup_lib(ctrl, &cdata); - - kthread_stop(ctrl->thread); - - mutex_destroy(&ctrl->mutex); - mutex_destroy(&ctrl->msg_lock); - mutex_destroy(&ctrl->wakeup_mutex); - kzfree(ctrl->msg_buf); - kfree(ctrl); -} - -void *dpu_dp_hdcp2p2_init(struct dpu_hdcp_init_data *init_data) -{ - int rc; - struct dp_hdcp2p2_ctrl *ctrl; - static struct hdcp_txmtr_ops txmtr_ops; - struct hdcp_register_data register_data; - static struct dpu_hdcp_ops ops = { - .isr = dp_hdcp2p2_isr, - .reauthenticate = dp_hdcp2p2_reauthenticate, - .authenticate = dp_hdcp2p2_authenticate, - .feature_supported = dp_hdcp2p2_feature_supported, - .off = dp_hdcp2p2_off, - .cp_irq = dp_hdcp2p2_cp_irq, - }; - - static struct hdcp_client_ops client_ops = { - .wakeup = dp_hdcp2p2_wakeup, - .notify_lvl_change = dp_hdcp2p2_min_level_change, - }; - static struct dp_hdcp2p2_int_set int_set1[] = { - {BIT(17), "authentication successful", NULL}, - {BIT(20), "authentication failed", NULL}, - {BIT(24), "encryption enabled", NULL}, - {BIT(27), "encryption disabled", NULL}, - {0}, - }; - static struct dp_hdcp2p2_int_set int_set2[] = { - {BIT(2), "key fifo underflow", NULL}, - {0}, - }; - static struct dp_hdcp2p2_interrupts intr[] = { - {DP_INTR_STATUS2, int_set1}, - {DP_INTR_STATUS3, int_set2}, - {0} - }; - - if (!init_data || !init_data->cb_data || - !init_data->notify_status || !init_data->drm_aux) { - pr_err("invalid input\n"); - return ERR_PTR(-EINVAL); - } - - ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); - if (!ctrl) - return ERR_PTR(-ENOMEM); - - ctrl->init_data = *init_data; - ctrl->lib = &txmtr_ops; - ctrl->msg_buf = NULL; - - ctrl->sink_status = SINK_DISCONNECTED; - ctrl->intr = intr; - - atomic_set(&ctrl->auth_state, HDCP_STATE_INACTIVE); - - ctrl->ops = &ops; - mutex_init(&ctrl->mutex); - mutex_init(&ctrl->msg_lock); - mutex_init(&ctrl->wakeup_mutex); - - register_data.hdcp_ctx = &ctrl->lib_ctx; - register_data.client_ops = &client_ops; - register_data.txmtr_ops = &txmtr_ops; - register_data.device_type = HDCP_TXMTR_DP; - register_data.client_ctx = ctrl; - - rc = hdcp_library_register(®ister_data); - if (rc) { - pr_err("Unable to register with HDCP 2.2 library\n"); - goto error; - } - - kthread_init_worker(&ctrl->worker); - - kthread_init_work(&ctrl->auth, dp_hdcp2p2_auth_work); - kthread_init_work(&ctrl->send_msg, dp_hdcp2p2_send_msg_work); - kthread_init_work(&ctrl->recv_msg, dp_hdcp2p2_recv_msg_work); - kthread_init_work(&ctrl->status, dp_hdcp2p2_auth_status_work); - kthread_init_work(&ctrl->link, dp_hdcp2p2_link_work); - - ctrl->thread = kthread_run(kthread_worker_fn, - &ctrl->worker, "dp_hdcp2p2"); - - if (IS_ERR(ctrl->thread)) { - pr_err("unable to start DP hdcp2p2 thread\n"); - rc = PTR_ERR(ctrl->thread); - ctrl->thread = NULL; - goto error; - } - - return ctrl; -error: - kfree(ctrl); - return ERR_PTR(rc); -} - -static bool dp_hdcp2p2_supported(struct dp_hdcp2p2_ctrl *ctrl) -{ - u32 const rxcaps_dpcd_offset = 0x6921d; - ssize_t bytes_read = 0; - u8 buf[DP_HDCP_RXCAPS_LENGTH]; - - bytes_read = drm_dp_dpcd_read(ctrl->init_data.drm_aux, - rxcaps_dpcd_offset, &buf, DP_HDCP_RXCAPS_LENGTH); - if (bytes_read != DP_HDCP_RXCAPS_LENGTH) { - pr_err("RxCaps read failed\n"); - goto error; - } - - pr_debug("HDCP_CAPABLE=%lu\n", (buf[2] & BIT(1)) >> 1); - pr_debug("VERSION=%d\n", buf[0]); - - if ((buf[2] & BIT(1)) && (buf[0] == 0x2)) - return true; - -error: - return false; -} - -struct dpu_hdcp_ops *dpu_dp_hdcp2p2_start(void *input) -{ - struct dp_hdcp2p2_ctrl *ctrl = input; - - pr_debug("Checking sink capability\n"); - if (dp_hdcp2p2_supported(ctrl)) - return ctrl->ops; - else - return NULL; -} - diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c deleted file mode 100644 index 9480861..0000000 --- a/drivers/gpu/drm/msm/dp/dp_link.c +++ /dev/null @@ -1,1548 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include "dp_link.h" -#include "dp_panel.h" - -enum dynamic_range { - DP_DYNAMIC_RANGE_RGB_VESA = 0x00, - DP_DYNAMIC_RANGE_RGB_CEA = 0x01, - DP_DYNAMIC_RANGE_UNKNOWN = 0xFFFFFFFF, -}; - -enum audio_sample_rate { - AUDIO_SAMPLE_RATE_32_KHZ = 0x00, - AUDIO_SAMPLE_RATE_44_1_KHZ = 0x01, - AUDIO_SAMPLE_RATE_48_KHZ = 0x02, - AUDIO_SAMPLE_RATE_88_2_KHZ = 0x03, - AUDIO_SAMPLE_RATE_96_KHZ = 0x04, - AUDIO_SAMPLE_RATE_176_4_KHZ = 0x05, - AUDIO_SAMPLE_RATE_192_KHZ = 0x06, -}; - -enum audio_pattern_type { - AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0x00, - AUDIO_TEST_PATTERN_SAWTOOTH = 0x01, -}; - -struct dp_link_request { - u32 test_requested; - u32 test_link_rate; - u32 test_lane_count; -}; - -struct dp_link_private { - u32 prev_sink_count; - struct device *dev; - struct dp_aux *aux; - struct dp_link dp_link; - - struct dp_link_request request; - u8 link_status[DP_LINK_STATUS_SIZE]; -}; - -static char *dp_link_get_audio_test_pattern(u32 pattern) -{ - switch (pattern) { - case AUDIO_TEST_PATTERN_OPERATOR_DEFINED: - return DP_LINK_ENUM_STR(AUDIO_TEST_PATTERN_OPERATOR_DEFINED); - case AUDIO_TEST_PATTERN_SAWTOOTH: - return DP_LINK_ENUM_STR(AUDIO_TEST_PATTERN_SAWTOOTH); - default: - return "unknown"; - } -} - -static char *dp_link_get_audio_sample_rate(u32 rate) -{ - switch (rate) { - case AUDIO_SAMPLE_RATE_32_KHZ: - return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_32_KHZ); - case AUDIO_SAMPLE_RATE_44_1_KHZ: - return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_44_1_KHZ); - case AUDIO_SAMPLE_RATE_48_KHZ: - return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_48_KHZ); - case AUDIO_SAMPLE_RATE_88_2_KHZ: - return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_88_2_KHZ); - case AUDIO_SAMPLE_RATE_96_KHZ: - return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_96_KHZ); - case AUDIO_SAMPLE_RATE_176_4_KHZ: - return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_176_4_KHZ); - case AUDIO_SAMPLE_RATE_192_KHZ: - return DP_LINK_ENUM_STR(AUDIO_SAMPLE_RATE_192_KHZ); - default: - return "unknown"; - } -} - -static int dp_link_get_period(struct dp_link_private *link, int const addr) -{ - int ret = 0; - u8 bp; - u8 data; - u32 const param_len = 0x1; - u32 const max_audio_period = 0xA; - - /* TEST_AUDIO_PERIOD_CH_XX */ - if (drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, - param_len) < param_len) { - pr_err("failed to read test_audio_period (0x%x)\n", addr); - ret = -EINVAL; - goto exit; - } - - data = bp; - - /* Period - Bits 3:0 */ - data = data & 0xF; - if ((int)data > max_audio_period) { - pr_err("invalid test_audio_period_ch_1 = 0x%x\n", data); - ret = -EINVAL; - goto exit; - } - - ret = data; -exit: - return ret; -} - -static int dp_link_parse_audio_channel_period(struct dp_link_private *link) -{ - int ret = 0; - struct dp_link_test_audio *req = &link->dp_link.test_audio; - - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH1); - if (ret == -EINVAL) - goto exit; - - req->test_audio_period_ch_1 = ret; - pr_debug("test_audio_period_ch_1 = 0x%x\n", ret); - - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH2); - if (ret == -EINVAL) - goto exit; - - req->test_audio_period_ch_2 = ret; - pr_debug("test_audio_period_ch_2 = 0x%x\n", ret); - - /* TEST_AUDIO_PERIOD_CH_3 (Byte 0x275) */ - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH3); - if (ret == -EINVAL) - goto exit; - - req->test_audio_period_ch_3 = ret; - pr_debug("test_audio_period_ch_3 = 0x%x\n", ret); - - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH4); - if (ret == -EINVAL) - goto exit; - - req->test_audio_period_ch_4 = ret; - pr_debug("test_audio_period_ch_4 = 0x%x\n", ret); - - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH5); - if (ret == -EINVAL) - goto exit; - - req->test_audio_period_ch_5 = ret; - pr_debug("test_audio_period_ch_5 = 0x%x\n", ret); - - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH6); - if (ret == -EINVAL) - goto exit; - - req->test_audio_period_ch_6 = ret; - pr_debug("test_audio_period_ch_6 = 0x%x\n", ret); - - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH7); - if (ret == -EINVAL) - goto exit; - - req->test_audio_period_ch_7 = ret; - pr_debug("test_audio_period_ch_7 = 0x%x\n", ret); - - ret = dp_link_get_period(link, DP_TEST_AUDIO_PERIOD_CH8); - if (ret == -EINVAL) - goto exit; - - req->test_audio_period_ch_8 = ret; - pr_debug("test_audio_period_ch_8 = 0x%x\n", ret); -exit: - return ret; -} - -static int dp_link_parse_audio_pattern_type(struct dp_link_private *link) -{ - int ret = 0; - u8 bp; - u8 data; - int rlen; - int const param_len = 0x1; - int const max_audio_pattern_type = 0x1; - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, - DP_TEST_AUDIO_PATTERN_TYPE, &bp, param_len); - if (rlen < param_len) { - pr_err("failed to read link audio mode data\n"); - ret = -EINVAL; - goto exit; - } - data = bp; - - /* Audio Pattern Type - Bits 7:0 */ - if ((int)data > max_audio_pattern_type) { - pr_err("invalid audio pattern type = 0x%x\n", data); - ret = -EINVAL; - goto exit; - } - - link->dp_link.test_audio.test_audio_pattern_type = data; - pr_debug("audio pattern type = %s\n", - dp_link_get_audio_test_pattern(data)); -exit: - return ret; -} - -static int dp_link_parse_audio_mode(struct dp_link_private *link) -{ - int ret = 0; - u8 bp; - u8 data; - int rlen; - int const param_len = 0x1; - int const max_audio_sampling_rate = 0x6; - int const max_audio_channel_count = 0x8; - int sampling_rate = 0x0; - int channel_count = 0x0; - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_AUDIO_MODE, - &bp, param_len); - if (rlen < param_len) { - pr_err("failed to read link audio mode data\n"); - ret = -EINVAL; - goto exit; - } - data = bp; - - /* Sampling Rate - Bits 3:0 */ - sampling_rate = data & 0xF; - if (sampling_rate > max_audio_sampling_rate) { - pr_err("sampling rate (0x%x) greater than max (0x%x)\n", - sampling_rate, max_audio_sampling_rate); - ret = -EINVAL; - goto exit; - } - - /* Channel Count - Bits 7:4 */ - channel_count = ((data & 0xF0) >> 4) + 1; - if (channel_count > max_audio_channel_count) { - pr_err("channel_count (0x%x) greater than max (0x%x)\n", - channel_count, max_audio_channel_count); - ret = -EINVAL; - goto exit; - } - - link->dp_link.test_audio.test_audio_sampling_rate = sampling_rate; - link->dp_link.test_audio.test_audio_channel_count = channel_count; - pr_debug("sampling_rate = %s, channel_count = 0x%x\n", - dp_link_get_audio_sample_rate(sampling_rate), channel_count); -exit: - return ret; -} - -/** - * dp_parse_audio_pattern_params() - parses audio pattern parameters from DPCD - * @link: Display Port Driver data - * - * Returns 0 if it successfully parses the audio link pattern parameters. - */ -static int dp_link_parse_audio_pattern_params(struct dp_link_private *link) -{ - int ret = 0; - - ret = dp_link_parse_audio_mode(link); - if (ret) - goto exit; - - ret = dp_link_parse_audio_pattern_type(link); - if (ret) - goto exit; - - ret = dp_link_parse_audio_channel_period(link); - -exit: - return ret; -} - -/** - * dp_link_is_video_pattern_valid() - validates the video pattern - * @pattern: video pattern requested by the sink - * - * Returns true if the requested video pattern is supported. - */ -static bool dp_link_is_video_pattern_valid(u32 pattern) -{ - switch (pattern) { - case DP_NO_TEST_PATTERN: - case DP_COLOR_RAMP: - case DP_BLACK_AND_WHITE_VERTICAL_LINES: - case DP_COLOR_SQUARE: - return true; - default: - return false; - } -} - -static char *dp_link_video_pattern_to_string(u32 test_video_pattern) -{ - switch (test_video_pattern) { - case DP_NO_TEST_PATTERN: - return DP_LINK_ENUM_STR(DP_NO_TEST_PATTERN); - case DP_COLOR_RAMP: - return DP_LINK_ENUM_STR(DP_COLOR_RAMP); - case DP_BLACK_AND_WHITE_VERTICAL_LINES: - return DP_LINK_ENUM_STR(DP_BLACK_AND_WHITE_VERTICAL_LINES); - case DP_COLOR_SQUARE: - return DP_LINK_ENUM_STR(DP_COLOR_SQUARE); - default: - return "unknown"; - } -} - -/** - * dp_link_is_dynamic_range_valid() - validates the dynamic range - * @bit_depth: the dynamic range value to be checked - * - * Returns true if the dynamic range value is supported. - */ -static bool dp_link_is_dynamic_range_valid(u32 dr) -{ - switch (dr) { - case DP_DYNAMIC_RANGE_RGB_VESA: - case DP_DYNAMIC_RANGE_RGB_CEA: - return true; - default: - return false; - } -} - -static char *dp_link_dynamic_range_to_string(u32 dr) -{ - switch (dr) { - case DP_DYNAMIC_RANGE_RGB_VESA: - return DP_LINK_ENUM_STR(DP_DYNAMIC_RANGE_RGB_VESA); - case DP_DYNAMIC_RANGE_RGB_CEA: - return DP_LINK_ENUM_STR(DP_DYNAMIC_RANGE_RGB_CEA); - case DP_DYNAMIC_RANGE_UNKNOWN: - default: - return "unknown"; - } -} - -/** - * dp_link_is_bit_depth_valid() - validates the bit depth requested - * @bit_depth: bit depth requested by the sink - * - * Returns true if the requested bit depth is supported. - */ -static bool dp_link_is_bit_depth_valid(u32 tbd) -{ - /* DP_TEST_VIDEO_PATTERN_NONE is treated as invalid */ - switch (tbd) { - case DP_TEST_BIT_DEPTH_6: - case DP_TEST_BIT_DEPTH_8: - case DP_TEST_BIT_DEPTH_10: - return true; - default: - return false; - } -} - -static char *dp_link_bit_depth_to_string(u32 tbd) -{ - switch (tbd) { - case DP_TEST_BIT_DEPTH_6: - return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_6); - case DP_TEST_BIT_DEPTH_8: - return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_8); - case DP_TEST_BIT_DEPTH_10: - return DP_LINK_ENUM_STR(DP_TEST_BIT_DEPTH_10); - case DP_TEST_BIT_DEPTH_UNKNOWN: - default: - return "unknown"; - } -} - -static int dp_link_parse_timing_params1(struct dp_link_private *link, - int const addr, int const len, u32 *val) -{ - u8 bp[2]; - int rlen; - - if (len < 2) - return -EINVAL; - - /* Read the requested video link pattern (Byte 0x221). */ - rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, bp, len); - if (rlen < len) { - pr_err("failed to read 0x%x\n", addr); - return -EINVAL; - } - - *val = bp[1] | (bp[0] << 8); - - return 0; -} - -static int dp_link_parse_timing_params2(struct dp_link_private *link, - int const addr, int const len, u32 *val1, u32 *val2) -{ - u8 bp[2]; - int rlen; - - if (len < 2) - return -EINVAL; - - /* Read the requested video link pattern (Byte 0x221). */ - rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, bp, len); - if (rlen < len) { - pr_err("failed to read 0x%x\n", addr); - return -EINVAL; - } - - *val1 = (bp[0] & BIT(7)) >> 7; - *val2 = bp[1] | ((bp[0] & 0x7F) << 8); - - return 0; -} - -static int dp_link_parse_timing_params3(struct dp_link_private *link, - int const addr, u32 *val) -{ - u8 bp; - u32 len = 1; - int rlen; - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, addr, &bp, len); - if (rlen < 1) { - pr_err("failed to read 0x%x\n", addr); - return -EINVAL; - } - *val = bp; - - return 0; -} - -/** - * dp_parse_video_pattern_params() - parses video pattern parameters from DPCD - * @link: Display Port Driver data - * - * Returns 0 if it successfully parses the video link pattern and the link - * bit depth requested by the sink and, and if the values parsed are valid. - */ -static int dp_link_parse_video_pattern_params(struct dp_link_private *link) -{ - int ret = 0; - int rlen; - u8 bp; - u8 data; - u32 dyn_range; - int const param_len = 0x1; - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PATTERN, - &bp, param_len); - if (rlen < param_len) { - pr_err("failed to read link video pattern\n"); - ret = -EINVAL; - goto exit; - } - data = bp; - - if (!dp_link_is_video_pattern_valid(data)) { - pr_err("invalid link video pattern = 0x%x\n", data); - ret = -EINVAL; - goto exit; - } - - link->dp_link.test_video.test_video_pattern = data; - pr_debug("link video pattern = 0x%x (%s)\n", - link->dp_link.test_video.test_video_pattern, - dp_link_video_pattern_to_string( - link->dp_link.test_video.test_video_pattern)); - - /* Read the requested color bit depth and dynamic range (Byte 0x232) */ - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_MISC0, - &bp, param_len); - if (rlen < param_len) { - pr_err("failed to read link bit depth\n"); - ret = -EINVAL; - goto exit; - } - data = bp; - - /* Dynamic Range */ - dyn_range = (data & DP_TEST_DYNAMIC_RANGE_CEA) >> 3; - if (!dp_link_is_dynamic_range_valid(dyn_range)) { - pr_err("invalid link dynamic range = 0x%x", dyn_range); - ret = -EINVAL; - goto exit; - } - link->dp_link.test_video.test_dyn_range = dyn_range; - pr_debug("link dynamic range = 0x%x (%s)\n", - link->dp_link.test_video.test_dyn_range, - dp_link_dynamic_range_to_string( - link->dp_link.test_video.test_dyn_range)); - - /* Color bit depth */ - data &= DP_TEST_BIT_DEPTH_MASK; - if (!dp_link_is_bit_depth_valid(data)) { - pr_err("invalid link bit depth = 0x%x\n", data); - ret = -EINVAL; - goto exit; - } - - link->dp_link.test_video.test_bit_depth = data; - pr_debug("link bit depth = 0x%x (%s)\n", - link->dp_link.test_video.test_bit_depth, - dp_link_bit_depth_to_string( - link->dp_link.test_video.test_bit_depth)); - - /* resolution timing params */ - ret = dp_link_parse_timing_params1(link, DP_TEST_H_TOTAL_HI, 2, - &link->dp_link.test_video.test_h_total); - if (ret) { - pr_err("failed to parse test_h_total (DP_TEST_H_TOTAL_HI)\n"); - goto exit; - } - pr_debug("TEST_H_TOTAL = %d\n", link->dp_link.test_video.test_h_total); - - ret = dp_link_parse_timing_params1(link, DP_TEST_V_TOTAL_HI, 2, - &link->dp_link.test_video.test_v_total); - if (ret) { - pr_err("failed to parse test_v_total (DP_TEST_V_TOTAL_HI)\n"); - goto exit; - } - pr_debug("TEST_V_TOTAL = %d\n", link->dp_link.test_video.test_v_total); - - ret = dp_link_parse_timing_params1(link, DP_TEST_H_START_HI, 2, - &link->dp_link.test_video.test_h_start); - if (ret) { - pr_err("failed to parse test_h_start (DP_TEST_H_START_HI)\n"); - goto exit; - } - pr_debug("TEST_H_START = %d\n", link->dp_link.test_video.test_h_start); - - ret = dp_link_parse_timing_params1(link, DP_TEST_V_START_HI, 2, - &link->dp_link.test_video.test_v_start); - if (ret) { - pr_err("failed to parse test_v_start (DP_TEST_V_START_HI)\n"); - goto exit; - } - pr_debug("TEST_V_START = %d\n", link->dp_link.test_video.test_v_start); - - ret = dp_link_parse_timing_params2(link, DP_TEST_HSYNC_HI, 2, - &link->dp_link.test_video.test_hsync_pol, - &link->dp_link.test_video.test_hsync_width); - if (ret) { - pr_err("failed to parse (DP_TEST_HSYNC_HI)\n"); - goto exit; - } - pr_debug("TEST_HSYNC_POL = %d\n", - link->dp_link.test_video.test_hsync_pol); - pr_debug("TEST_HSYNC_WIDTH = %d\n", - link->dp_link.test_video.test_hsync_width); - - ret = dp_link_parse_timing_params2(link, DP_TEST_VSYNC_HI, 2, - &link->dp_link.test_video.test_vsync_pol, - &link->dp_link.test_video.test_vsync_width); - if (ret) { - pr_err("failed to parse (DP_TEST_VSYNC_HI)\n"); - goto exit; - } - pr_debug("TEST_VSYNC_POL = %d\n", - link->dp_link.test_video.test_vsync_pol); - pr_debug("TEST_VSYNC_WIDTH = %d\n", - link->dp_link.test_video.test_vsync_width); - - ret = dp_link_parse_timing_params1(link, DP_TEST_H_WIDTH_HI, 2, - &link->dp_link.test_video.test_h_width); - if (ret) { - pr_err("failed to parse test_h_width (DP_TEST_H_WIDTH_HI)\n"); - goto exit; - } - pr_debug("TEST_H_WIDTH = %d\n", link->dp_link.test_video.test_h_width); - - ret = dp_link_parse_timing_params1(link, DP_TEST_V_HEIGHT_HI, 2, - &link->dp_link.test_video.test_v_height); - if (ret) { - pr_err("failed to parse test_v_height (DP_TEST_V_HEIGHT_HI)\n"); - goto exit; - } - pr_debug("TEST_V_HEIGHT = %d\n", - link->dp_link.test_video.test_v_height); - - ret = dp_link_parse_timing_params3(link, DP_TEST_MISC1, - &link->dp_link.test_video.test_rr_d); - link->dp_link.test_video.test_rr_d &= DP_TEST_REFRESH_DENOMINATOR; - if (ret) { - pr_err("failed to parse test_rr_d (DP_TEST_MISC1)\n"); - goto exit; - } - pr_debug("TEST_REFRESH_DENOMINATOR = %d\n", - link->dp_link.test_video.test_rr_d); - - ret = dp_link_parse_timing_params3(link, DP_TEST_REFRESH_RATE_NUMERATOR, - &link->dp_link.test_video.test_rr_n); - if (ret) { - pr_err("failed to parse test_rr_n (DP_TEST_REFRESH_RATE_NUMERATOR)\n"); - goto exit; - } - pr_debug("TEST_REFRESH_NUMERATOR = %d\n", - link->dp_link.test_video.test_rr_n); -exit: - return ret; -} - -/** - * dp_link_parse_link_training_params() - parses link training parameters from - * DPCD - * @link: Display Port Driver data - * - * Returns 0 if it successfully parses the link rate (Byte 0x219) and lane - * count (Byte 0x220), and if these values parse are valid. - */ -static int dp_link_parse_link_training_params(struct dp_link_private *link) -{ - u8 bp; - u8 data; - int ret = 0; - int rlen; - int const param_len = 0x1; - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LINK_RATE, - &bp, param_len); - if (rlen < param_len) { - pr_err("failed to read link rate\n"); - ret = -EINVAL; - goto exit; - } - data = bp; - - if (!is_link_rate_valid(data)) { - pr_err("invalid link rate = 0x%x\n", data); - ret = -EINVAL; - goto exit; - } - - link->request.test_link_rate = data; - pr_debug("link rate = 0x%x\n", link->request.test_link_rate); - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_LANE_COUNT, - &bp, param_len); - if (rlen < param_len) { - pr_err("failed to read lane count\n"); - ret = -EINVAL; - goto exit; - } - data = bp; - data &= 0x1F; - - if (!is_lane_count_valid(data)) { - pr_err("invalid lane count = 0x%x\n", data); - ret = -EINVAL; - goto exit; - } - - link->request.test_lane_count = data; - pr_debug("lane count = 0x%x\n", link->request.test_lane_count); -exit: - return ret; -} - -static bool dp_link_is_phy_test_pattern_supported(u32 phy_test_pattern_sel) -{ - switch (phy_test_pattern_sel) { - case DP_TEST_PHY_PATTERN_NONE: - case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: - case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: - case DP_TEST_PHY_PATTERN_PRBS7: - case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: - case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN: - return true; - default: - return false; - } -} - -/** - * dp_parse_phy_test_params() - parses the phy link parameters - * @link: Display Port Driver data - * - * Parses the DPCD (Byte 0x248) for the DP PHY link pattern that is being - * requested. - */ -static int dp_link_parse_phy_test_params(struct dp_link_private *link) -{ - u8 bp; - u8 data; - int rlen; - int const param_len = 0x1; - int ret = 0; - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_PHY_PATTERN, - &bp, param_len); - if (rlen < param_len) { - pr_err("failed to read phy link pattern\n"); - ret = -EINVAL; - goto end; - } - - data = bp; - - link->dp_link.phy_params.phy_test_pattern_sel = data; - - pr_debug("phy_test_pattern_sel = %s\n", - dp_link_get_phy_test_pattern(data)); - - if (!dp_link_is_phy_test_pattern_supported(data)) - ret = -EINVAL; -end: - return ret; -} - -static char *dp_link_get_test_name(u32 test_requested) -{ - switch (test_requested) { - case DP_TEST_LINK_TRAINING: - return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING); - case DP_TEST_LINK_VIDEO_PATTERN: - return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN); - case DP_TEST_LINK_EDID_READ: - return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ); - case DP_TEST_LINK_PHY_TEST_PATTERN: - return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN); - case DP_TEST_LINK_AUDIO_PATTERN: - return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN); - default: - return "unknown"; - } -} - -/** - * dp_link_is_video_audio_test_requested() - checks for audio/video link request - * @link: link requested by the sink - * - * Returns true if the requested link is a permitted audio/video link. - */ -static bool dp_link_is_video_audio_test_requested(u32 link) -{ - return (link == DP_TEST_LINK_VIDEO_PATTERN) || - (link == (DP_TEST_LINK_AUDIO_PATTERN | - DP_TEST_LINK_VIDEO_PATTERN)) || - (link == DP_TEST_LINK_AUDIO_PATTERN) || - (link == (DP_TEST_LINK_AUDIO_PATTERN | - DP_TEST_LINK_AUDIO_DISABLED_VIDEO)); -} - -/** - * dp_link_supported() - checks if link requested by sink is supported - * @test_requested: link requested by the sink - * - * Returns true if the requested link is supported. - */ -static bool dp_link_is_test_supported(u32 test_requested) -{ - return (test_requested == DP_TEST_LINK_TRAINING) || - (test_requested == DP_TEST_LINK_EDID_READ) || - (test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) || - dp_link_is_video_audio_test_requested(test_requested); -} - -static bool dp_link_is_test_edid_read(struct dp_link_private *link) -{ - return (link->request.test_requested == DP_TEST_LINK_EDID_READ); -} - -/** - * dp_sink_parse_test_request() - parses link request parameters from sink - * @link: Display Port Driver data - * - * Parses the DPCD to check if an automated link is requested (Byte 0x201), - * and what type of link automation is being requested (Byte 0x218). - */ -static int dp_link_parse_request(struct dp_link_private *link) -{ - int ret = 0; - u8 bp; - u8 data; - int rlen; - u32 const param_len = 0x1; - - /** - * Read the device service IRQ vector (Byte 0x201) to determine - * whether an automated link has been requested by the sink. - */ - rlen = drm_dp_dpcd_read(link->aux->drm_aux, - DP_DEVICE_SERVICE_IRQ_VECTOR, &bp, param_len); - if (rlen < param_len) { - pr_err("aux read failed\n"); - ret = -EINVAL; - goto end; - } - - data = bp; - - pr_debug("device service irq vector = 0x%x\n", data); - - if (!(data & DP_AUTOMATED_TEST_REQUEST)) { - pr_debug("no test requested\n"); - return 0; - } - - /** - * Read the link request byte (Byte 0x218) to determine what type - * of automated link has been requested by the sink. - */ - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_TEST_REQUEST, - &bp, param_len); - if (rlen < param_len) { - pr_err("aux read failed\n"); - ret = -EINVAL; - goto end; - } - - data = bp; - - if (!dp_link_is_test_supported(data)) { - pr_debug("link 0x%x not supported\n", data); - goto end; - } - - pr_debug("%s (0x%x) requested\n", dp_link_get_test_name(data), data); - link->request.test_requested = data; - - if (link->request.test_requested == DP_TEST_LINK_PHY_TEST_PATTERN) { - ret = dp_link_parse_phy_test_params(link); - if (ret) - goto end; - ret = dp_link_parse_link_training_params(link); - } - - if (link->request.test_requested == DP_TEST_LINK_TRAINING) - ret = dp_link_parse_link_training_params(link); - - if (dp_link_is_video_audio_test_requested( - link->request.test_requested)) { - ret = dp_link_parse_video_pattern_params(link); - if (ret) - goto end; - - ret = dp_link_parse_audio_pattern_params(link); - } -end: - /** - * Send a DP_TEST_ACK if all link parameters are valid, otherwise send - * a DP_TEST_NAK. - */ - if (ret) { - link->dp_link.test_response = DP_TEST_NAK; - } else { - if (!dp_link_is_test_edid_read(link)) - link->dp_link.test_response = DP_TEST_ACK; - else - link->dp_link.test_response = - DP_TEST_EDID_CHECKSUM_WRITE; - } - - return ret; -} - -/** - * dp_link_parse_sink_count() - parses the sink count - * - * Parses the DPCD to check if there is an update to the sink count - * (Byte 0x200), and whether all the sink devices connected have Content - * Protection enabled. - */ -static int dp_link_parse_sink_count(struct dp_link *dp_link) -{ - int rlen; - int const param_len = 0x1; - struct dp_link_private *link = container_of(dp_link, - struct dp_link_private, dp_link); - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_SINK_COUNT, - &link->dp_link.sink_count.count, param_len); - if (rlen < param_len) { - pr_err("failed to read sink count\n"); - return -EINVAL; - } - - link->dp_link.sink_count.cp_ready = - link->dp_link.sink_count.count & DP_SINK_CP_READY; - /* BIT 7, BIT 5:0 */ - link->dp_link.sink_count.count = - DP_GET_SINK_COUNT(link->dp_link.sink_count.count); - - pr_debug("sink_count = 0x%x, cp_ready = 0x%x\n", - link->dp_link.sink_count.count, - link->dp_link.sink_count.cp_ready); - return 0; -} - -static void dp_link_parse_sink_status_field(struct dp_link_private *link) -{ - int len = 0; - - link->prev_sink_count = link->dp_link.sink_count.count; - dp_link_parse_sink_count(&link->dp_link); - - len = drm_dp_dpcd_read_link_status(link->aux->drm_aux, - link->link_status); - if (len < DP_LINK_STATUS_SIZE) - pr_err("DP link status read failed\n"); - dp_link_parse_request(link); -} - -static bool dp_link_is_link_training_requested(struct dp_link_private *link) -{ - return (link->request.test_requested == DP_TEST_LINK_TRAINING); -} - -/** - * dp_link_process_link_training_request() - processes new training requests - * @link: Display Port link data - * - * This function will handle new link training requests that are initiated by - * the sink. In particular, it will update the requested lane count and link - * link rate, and then trigger the link retraining procedure. - * - * The function will return 0 if a link training request has been processed, - * otherwise it will return -EINVAL. - */ -static int dp_link_process_link_training_request(struct dp_link_private *link) -{ - if (!dp_link_is_link_training_requested(link)) - return -EINVAL; - - pr_debug("%s link rate = 0x%x, lane count = 0x%x\n", - dp_link_get_test_name(DP_TEST_LINK_TRAINING), - link->request.test_link_rate, - link->request.test_lane_count); - - link->dp_link.link_params.lane_count = link->request.test_lane_count; - link->dp_link.link_params.bw_code = link->request.test_link_rate; - - return 0; -} - -static void dp_link_send_test_response(struct dp_link *dp_link) -{ - struct dp_link_private *link = NULL; - u32 const response_len = 0x1; - - if (!dp_link) { - pr_err("invalid input\n"); - return; - } - - link = container_of(dp_link, struct dp_link_private, dp_link); - - drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_RESPONSE, - &dp_link->test_response, response_len); -} - -static int dp_link_psm_config(struct dp_link *dp_link, - struct drm_dp_link *link_info, bool enable) -{ - struct dp_link_private *link = NULL; - int ret = 0; - - if (!dp_link) { - pr_err("invalid params\n"); - return -EINVAL; - } - - link = container_of(dp_link, struct dp_link_private, dp_link); - - if (enable) - ret = drm_dp_link_power_down(link->aux->drm_aux, link_info); - else - ret = drm_dp_link_power_up(link->aux->drm_aux, link_info); - - if (ret) - pr_err("Failed to %s low power mode\n", - (enable ? "enter" : "exit")); - else - dp_link->psm_enabled = enable; - - return ret; -} - -static void dp_link_send_edid_checksum(struct dp_link *dp_link, u8 checksum) -{ - struct dp_link_private *link = NULL; - u32 const response_len = 0x1; - - if (!dp_link) { - pr_err("invalid input\n"); - return; - } - - link = container_of(dp_link, struct dp_link_private, dp_link); - - drm_dp_dpcd_write(link->aux->drm_aux, DP_TEST_EDID_CHECKSUM, - &checksum, response_len); -} - -static int dp_link_parse_vx_px(struct dp_link_private *link) -{ - u8 bp; - u8 data; - int const param_len = 0x1; - int ret = 0; - u32 v0, p0, v1, p1, v2, p2, v3, p3; - int rlen; - - pr_debug("\n"); - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE0_1, - &bp, param_len); - if (rlen < param_len) { - pr_err("failed reading lanes 0/1\n"); - ret = -EINVAL; - goto end; - } - - data = bp; - - pr_debug("lanes 0/1 (Byte 0x206): 0x%x\n", data); - - v0 = data & 0x3; - data = data >> 2; - p0 = data & 0x3; - data = data >> 2; - - v1 = data & 0x3; - data = data >> 2; - p1 = data & 0x3; - data = data >> 2; - - rlen = drm_dp_dpcd_read(link->aux->drm_aux, DP_ADJUST_REQUEST_LANE2_3, - &bp, param_len); - if (rlen < param_len) { - pr_err("failed reading lanes 2/3\n"); - ret = -EINVAL; - goto end; - } - - data = bp; - - pr_debug("lanes 2/3 (Byte 0x207): 0x%x\n", data); - - v2 = data & 0x3; - data = data >> 2; - p2 = data & 0x3; - data = data >> 2; - - v3 = data & 0x3; - data = data >> 2; - p3 = data & 0x3; - data = data >> 2; - - pr_debug("vx: 0=%d, 1=%d, 2=%d, 3=%d\n", v0, v1, v2, v3); - pr_debug("px: 0=%d, 1=%d, 2=%d, 3=%d\n", p0, p1, p2, p3); - - /** - * Update the voltage and pre-emphasis levels as per DPCD request - * vector. - */ - pr_debug("Current: v_level = 0x%x, p_level = 0x%x\n", - link->dp_link.phy_params.v_level, - link->dp_link.phy_params.p_level); - pr_debug("Requested: v_level = 0x%x, p_level = 0x%x\n", v0, p0); - link->dp_link.phy_params.v_level = v0; - link->dp_link.phy_params.p_level = p0; - - pr_debug("Success\n"); -end: - return ret; -} - -/** - * dp_link_process_phy_test_pattern_request() - process new phy link requests - * @link: Display Port Driver data - * - * This function will handle new phy link pattern requests that are initiated - * by the sink. The function will return 0 if a phy link pattern has been - * processed, otherwise it will return -EINVAL. - */ -static int dp_link_process_phy_test_pattern_request( - struct dp_link_private *link) -{ - u32 test_link_rate = 0, test_lane_count = 0; - - if (!(link->request.test_requested & DP_TEST_LINK_PHY_TEST_PATTERN)) { - pr_debug("no phy test\n"); - return -EINVAL; - } - - test_link_rate = link->request.test_link_rate; - test_lane_count = link->request.test_lane_count; - - if (!is_link_rate_valid(test_link_rate) || - !is_lane_count_valid(test_lane_count)) { - pr_err("Invalid params: link rate = 0x%x, lane count = 0x%x\n", - test_link_rate, test_lane_count); - return -EINVAL; - } - - pr_debug("start\n"); - - pr_info("Current: bw_code = 0x%x, lane count = 0x%x\n", - link->dp_link.link_params.bw_code, - link->dp_link.link_params.lane_count); - - pr_info("Requested: bw_code = 0x%x, lane count = 0x%x\n", - test_link_rate, test_lane_count); - - link->dp_link.link_params.lane_count = link->request.test_lane_count; - link->dp_link.link_params.bw_code = link->request.test_link_rate; - - dp_link_parse_vx_px(link); - - pr_debug("end\n"); - - return 0; -} - -static u8 get_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r) -{ - return link_status[r - DP_LANE0_1_STATUS]; -} - -/** - * dp_link_process_link_status_update() - processes link status updates - * @link: Display Port link module data - * - * This function will check for changes in the link status, e.g. clock - * recovery done on all lanes, and trigger link training if there is a - * failure/error on the link. - * - * The function will return 0 if the a link status update has been processed, - * otherwise it will return -EINVAL. - */ -static int dp_link_process_link_status_update(struct dp_link_private *link) -{ - if (!(get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) & - DP_LINK_STATUS_UPDATED) || /* link status updated */ - (drm_dp_clock_recovery_ok(link->link_status, - link->dp_link.link_params.lane_count) && - drm_dp_channel_eq_ok(link->link_status, - link->dp_link.link_params.lane_count))) - return -EINVAL; - - pr_debug("channel_eq_done = %d, clock_recovery_done = %d\n", - drm_dp_clock_recovery_ok(link->link_status, - link->dp_link.link_params.lane_count), - drm_dp_clock_recovery_ok(link->link_status, - link->dp_link.link_params.lane_count)); - - return 0; -} - -static bool dp_link_is_ds_port_status_changed(struct dp_link_private *link) -{ - if (get_link_status(link->link_status, DP_LANE_ALIGN_STATUS_UPDATED) & - DP_DOWNSTREAM_PORT_STATUS_CHANGED) /* port status changed */ - return true; - - if (link->prev_sink_count != link->dp_link.sink_count.count) - return true; - - return false; -} - -/** - * dp_link_process_downstream_port_status_change() - process port status changes - * @link: Display Port Driver data - * - * This function will handle downstream port updates that are initiated by - * the sink. If the downstream port status has changed, the EDID is read via - * AUX. - * - * The function will return 0 if a downstream port update has been - * processed, otherwise it will return -EINVAL. - */ -static int dp_link_process_ds_port_status_change(struct dp_link_private *link) -{ - if (!dp_link_is_ds_port_status_changed(link)) - return -EINVAL; - - /* reset prev_sink_count */ - link->prev_sink_count = link->dp_link.sink_count.count; - - return 0; -} - -static bool dp_link_is_video_pattern_requested(struct dp_link_private *link) -{ - return (link->request.test_requested & DP_TEST_LINK_VIDEO_PATTERN) - && !(link->request.test_requested & - DP_TEST_LINK_AUDIO_DISABLED_VIDEO); -} - -static bool dp_link_is_audio_pattern_requested(struct dp_link_private *link) -{ - return (link->request.test_requested & DP_TEST_LINK_AUDIO_PATTERN); -} - -/** - * dp_link_process_video_pattern_request() - process new video pattern request - * @link: Display Port link module's data - * - * This function will handle a new video pattern request that are initiated by - * the sink. This is acheieved by first sending a disconnect notification to - * the sink followed by a subsequent connect notification to the user modules, - * where it is expected that the user modules would draw the required link - * pattern. - */ -static int dp_link_process_video_pattern_request(struct dp_link_private *link) -{ - if (!dp_link_is_video_pattern_requested(link)) - goto end; - - pr_debug("%s: bit depth=%d(%d bpp) pattern=%s\n", - dp_link_get_test_name(DP_TEST_LINK_VIDEO_PATTERN), - link->dp_link.test_video.test_bit_depth, - dp_link_bit_depth_to_bpp( - link->dp_link.test_video.test_bit_depth), - dp_link_video_pattern_to_string( - link->dp_link.test_video.test_video_pattern)); - - return 0; -end: - return -EINVAL; -} - -/** - * dp_link_process_audio_pattern_request() - process new audio pattern request - * @link: Display Port link module data - * - * This function will handle a new audio pattern request that is initiated by - * the sink. This is acheieved by sending the necessary secondary data packets - * to the sink. It is expected that any simulatenous requests for video - * patterns will be handled before the audio pattern is sent to the sink. - */ -static int dp_link_process_audio_pattern_request(struct dp_link_private *link) -{ - if (!dp_link_is_audio_pattern_requested(link)) - return -EINVAL; - - pr_debug("sampling_rate=%s, channel_count=%d, pattern_type=%s\n", - dp_link_get_audio_sample_rate( - link->dp_link.test_audio.test_audio_sampling_rate), - link->dp_link.test_audio.test_audio_channel_count, - dp_link_get_audio_test_pattern( - link->dp_link.test_audio.test_audio_pattern_type)); - - pr_debug("audio_period: ch1=0x%x, ch2=0x%x, ch3=0x%x, ch4=0x%x\n", - link->dp_link.test_audio.test_audio_period_ch_1, - link->dp_link.test_audio.test_audio_period_ch_2, - link->dp_link.test_audio.test_audio_period_ch_3, - link->dp_link.test_audio.test_audio_period_ch_4); - - pr_debug("audio_period: ch5=0x%x, ch6=0x%x, ch7=0x%x, ch8=0x%x\n", - link->dp_link.test_audio.test_audio_period_ch_5, - link->dp_link.test_audio.test_audio_period_ch_6, - link->dp_link.test_audio.test_audio_period_ch_7, - link->dp_link.test_audio.test_audio_period_ch_8); - - return 0; -} - -static void dp_link_reset_data(struct dp_link_private *link) -{ - link->request = (const struct dp_link_request){ 0 }; - link->dp_link.test_video = (const struct dp_link_test_video){ 0 }; - link->dp_link.test_video.test_bit_depth = DP_TEST_BIT_DEPTH_UNKNOWN; - link->dp_link.test_audio = (const struct dp_link_test_audio){ 0 }; - link->dp_link.phy_params.phy_test_pattern_sel = 0; - link->dp_link.sink_request = 0; - link->dp_link.test_response = 0; -} - -/** - * dp_link_process_request() - handle HPD IRQ transition to HIGH - * @link: pointer to link module data - * - * This function will handle the HPD IRQ state transitions from LOW to HIGH - * (including cases when there are back to back HPD IRQ HIGH) indicating - * the start of a new link training request or sink status update. - */ -static int dp_link_process_request(struct dp_link *dp_link) -{ - int ret = 0; - struct dp_link_private *link; - - if (!dp_link) { - pr_err("invalid input\n"); - return -EINVAL; - } - - link = container_of(dp_link, struct dp_link_private, dp_link); - - pr_debug("start\n"); - - dp_link_reset_data(link); - - dp_link_parse_sink_status_field(link); - - if (dp_link_is_test_edid_read(link)) { - dp_link->sink_request |= DP_TEST_LINK_EDID_READ; - goto exit; - } - - ret = dp_link_process_ds_port_status_change(link); - if (!ret) { - dp_link->sink_request |= DS_PORT_STATUS_CHANGED; - goto exit; - } - - ret = dp_link_process_link_training_request(link); - if (!ret) { - dp_link->sink_request |= DP_TEST_LINK_TRAINING; - goto exit; - } - - ret = dp_link_process_phy_test_pattern_request(link); - if (!ret) { - dp_link->sink_request |= DP_TEST_LINK_PHY_TEST_PATTERN; - goto exit; - } - - ret = dp_link_process_link_status_update(link); - if (!ret) { - dp_link->sink_request |= DP_LINK_STATUS_UPDATED; - goto exit; - } - - ret = dp_link_process_video_pattern_request(link); - if (!ret) { - dp_link->sink_request |= DP_TEST_LINK_VIDEO_PATTERN; - goto exit; - } - - ret = dp_link_process_audio_pattern_request(link); - if (!ret) { - dp_link->sink_request |= DP_TEST_LINK_AUDIO_PATTERN; - goto exit; - } - - pr_debug("done\n"); -exit: - return ret; -} - -static int dp_link_get_colorimetry_config(struct dp_link *dp_link) -{ - u32 cc; - enum dynamic_range dr; - struct dp_link_private *link; - - if (!dp_link) { - pr_err("invalid input\n"); - return -EINVAL; - } - - link = container_of(dp_link, struct dp_link_private, dp_link); - - /* unless a video pattern CTS test is ongoing, use CEA_VESA */ - if (dp_link_is_video_pattern_requested(link)) - dr = link->dp_link.test_video.test_dyn_range; - else - dr = DP_DYNAMIC_RANGE_RGB_VESA; - - /* Only RGB_VESA nd RGB_CEA supported for now */ - switch (dr) { - case DP_DYNAMIC_RANGE_RGB_CEA: - cc = BIT(3); - break; - case DP_DYNAMIC_RANGE_RGB_VESA: - default: - cc = 0; - } - - return cc; -} - -static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status) -{ - int i; - int max = 0; - u8 data; - struct dp_link_private *link; - - if (!dp_link) { - pr_err("invalid input\n"); - return -EINVAL; - } - - link = container_of(dp_link, struct dp_link_private, dp_link); - - /* use the max level across lanes */ - for (i = 0; i < dp_link->link_params.lane_count; i++) { - data = drm_dp_get_adjust_request_voltage(link_status, i); - pr_debug("lane=%d req_voltage_swing=%d\n", i, data); - if (max < data) - max = data; - } - - dp_link->phy_params.v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT; - - /* use the max level across lanes */ - max = 0; - for (i = 0; i < dp_link->link_params.lane_count; i++) { - data = drm_dp_get_adjust_request_pre_emphasis(link_status, i); - pr_debug("lane=%d req_pre_emphasis=%d\n", i, data); - if (max < data) - max = data; - } - - dp_link->phy_params.p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT; - - /** - * Adjust the voltage swing and pre-emphasis level combination to within - * the allowable range. - */ - if (dp_link->phy_params.v_level > DP_LINK_VOLTAGE_MAX) { - pr_debug("Requested vSwingLevel=%d, change to %d\n", - dp_link->phy_params.v_level, DP_LINK_VOLTAGE_MAX); - dp_link->phy_params.v_level = DP_LINK_VOLTAGE_MAX; - } - - if (dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_MAX) { - pr_debug("Requested preEmphasisLevel=%d, change to %d\n", - dp_link->phy_params.p_level, DP_LINK_PRE_EMPHASIS_MAX); - dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_MAX; - } - - if ((dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_LEVEL_1) - && (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_2)) { - pr_debug("Requested preEmphasisLevel=%d, change to %d\n", - dp_link->phy_params.p_level, - DP_LINK_PRE_EMPHASIS_LEVEL_1); - dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1; - } - - pr_debug("adjusted: v_level=%d, p_level=%d\n", - dp_link->phy_params.v_level, dp_link->phy_params.p_level); - - return 0; -} - -static int dp_link_send_psm_request(struct dp_link *dp_link, bool req) -{ - struct dp_link_private *link; - - if (!dp_link) { - pr_err("invalid input\n"); - return -EINVAL; - } - - link = container_of(dp_link, struct dp_link_private, dp_link); - - return 0; -} - -static u32 dp_link_get_test_bits_depth(struct dp_link *dp_link, u32 bpp) -{ - u32 tbd; - - /* - * Few simplistic rules and assumptions made here: - * 1. Test bit depth is bit depth per color component - * 2. Assume 3 color components - */ - switch (bpp) { - case 18: - tbd = DP_TEST_BIT_DEPTH_6; - break; - case 24: - tbd = DP_TEST_BIT_DEPTH_8; - break; - case 30: - tbd = DP_TEST_BIT_DEPTH_10; - break; - default: - tbd = DP_TEST_BIT_DEPTH_UNKNOWN; - break; - } - - if (tbd != DP_TEST_BIT_DEPTH_UNKNOWN) - tbd = (tbd >> DP_TEST_BIT_DEPTH_SHIFT); - - return tbd; -} - -struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux) -{ - int rc = 0; - struct dp_link_private *link; - struct dp_link *dp_link; - - if (!dev || !aux) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - link = devm_kzalloc(dev, sizeof(*link), GFP_KERNEL); - if (!link) { - rc = -EINVAL; - goto error; - } - - link->dev = dev; - link->aux = aux; - - dp_link = &link->dp_link; - - dp_link->process_request = dp_link_process_request; - dp_link->get_test_bits_depth = dp_link_get_test_bits_depth; - dp_link->get_colorimetry_config = dp_link_get_colorimetry_config; - dp_link->adjust_levels = dp_link_adjust_levels; - dp_link->send_psm_request = dp_link_send_psm_request; - dp_link->send_test_response = dp_link_send_test_response; - dp_link->psm_config = dp_link_psm_config; - dp_link->send_edid_checksum = dp_link_send_edid_checksum; - - return dp_link; -error: - return ERR_PTR(rc); -} - -void dp_link_put(struct dp_link *dp_link) -{ - struct dp_link_private *link; - - if (!dp_link) - return; - - link = container_of(dp_link, struct dp_link_private, dp_link); - - devm_kfree(link->dev, link); -} diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h deleted file mode 100644 index 6d6ef43..0000000 --- a/drivers/gpu/drm/msm/dp/dp_link.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_LINK_H_ -#define _DP_LINK_H_ - -#include "dp_aux.h" - -#define DS_PORT_STATUS_CHANGED 0x200 -#define DP_TEST_BIT_DEPTH_UNKNOWN 0xFFFFFFFF -#define DP_LINK_ENUM_STR(x) #x - -enum dp_link_voltage_level { - DP_LINK_VOLTAGE_LEVEL_0 = 0, - DP_LINK_VOLTAGE_LEVEL_1 = 1, - DP_LINK_VOLTAGE_LEVEL_2 = 2, - DP_LINK_VOLTAGE_MAX = DP_LINK_VOLTAGE_LEVEL_2, -}; - -enum dp_link_preemaphasis_level { - DP_LINK_PRE_EMPHASIS_LEVEL_0 = 0, - DP_LINK_PRE_EMPHASIS_LEVEL_1 = 1, - DP_LINK_PRE_EMPHASIS_LEVEL_2 = 2, - DP_LINK_PRE_EMPHASIS_MAX = DP_LINK_PRE_EMPHASIS_LEVEL_2, -}; - -struct dp_link_sink_count { - u32 count; - bool cp_ready; -}; - -struct dp_link_test_video { - u32 test_video_pattern; - u32 test_bit_depth; - u32 test_dyn_range; - u32 test_h_total; - u32 test_v_total; - u32 test_h_start; - u32 test_v_start; - u32 test_hsync_pol; - u32 test_hsync_width; - u32 test_vsync_pol; - u32 test_vsync_width; - u32 test_h_width; - u32 test_v_height; - u32 test_rr_d; - u32 test_rr_n; -}; - -struct dp_link_test_audio { - u32 test_audio_sampling_rate; - u32 test_audio_channel_count; - u32 test_audio_pattern_type; - u32 test_audio_period_ch_1; - u32 test_audio_period_ch_2; - u32 test_audio_period_ch_3; - u32 test_audio_period_ch_4; - u32 test_audio_period_ch_5; - u32 test_audio_period_ch_6; - u32 test_audio_period_ch_7; - u32 test_audio_period_ch_8; -}; - -struct dp_link_phy_params { - u32 phy_test_pattern_sel; - u8 v_level; - u8 p_level; -}; - -struct dp_link_params { - u32 lane_count; - u32 bw_code; -}; - -struct dp_link { - u32 sink_request; - u32 test_response; - bool psm_enabled; - - struct dp_link_sink_count sink_count; - struct dp_link_test_video test_video; - struct dp_link_test_audio test_audio; - struct dp_link_phy_params phy_params; - struct dp_link_params link_params; - - u32 (*get_test_bits_depth)(struct dp_link *dp_link, u32 bpp); - int (*process_request)(struct dp_link *dp_link); - int (*get_colorimetry_config)(struct dp_link *dp_link); - int (*adjust_levels)(struct dp_link *dp_link, u8 *link_status); - int (*send_psm_request)(struct dp_link *dp_link, bool req); - void (*send_test_response)(struct dp_link *dp_link); - int (*psm_config)(struct dp_link *dp_link, - struct drm_dp_link *link_info, bool enable); - void (*send_edid_checksum)(struct dp_link *dp_link, u8 checksum); -}; - -static inline char *dp_link_get_phy_test_pattern(u32 phy_test_pattern_sel) -{ - switch (phy_test_pattern_sel) { - case DP_TEST_PHY_PATTERN_NONE: - return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_NONE); - case DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING: - return DP_LINK_ENUM_STR( - DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING); - case DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT: - return DP_LINK_ENUM_STR( - DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT); - case DP_TEST_PHY_PATTERN_PRBS7: - return DP_LINK_ENUM_STR(DP_TEST_PHY_PATTERN_PRBS7); - case DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN: - return DP_LINK_ENUM_STR( - DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN); - case DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN: - return DP_LINK_ENUM_STR( - DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN); - default: - return "unknown"; - } -} - -/** - * mdss_dp_test_bit_depth_to_bpp() - convert test bit depth to bpp - * @tbd: test bit depth - * - * Returns the bits per pixel (bpp) to be used corresponding to the - * git bit depth value. This function assumes that bit depth has - * already been validated. - */ -static inline u32 dp_link_bit_depth_to_bpp(u32 tbd) -{ - u32 bpp; - - /* - * Few simplistic rules and assumptions made here: - * 1. Bit depth is per color component - * 2. If bit depth is unknown return 0 - * 3. Assume 3 color components - */ - switch (tbd) { - case DP_TEST_BIT_DEPTH_6: - bpp = 18; - break; - case DP_TEST_BIT_DEPTH_8: - bpp = 24; - break; - case DP_TEST_BIT_DEPTH_10: - bpp = 30; - break; - case DP_TEST_BIT_DEPTH_UNKNOWN: - default: - bpp = 0; - } - - return bpp; -} - -/** - * dp_link_get() - get the functionalities of dp test module - * - * - * return: a pointer to dp_link struct - */ -struct dp_link *dp_link_get(struct device *dev, struct dp_aux *aux); - -/** - * dp_link_put() - releases the dp test module's resources - * - * @dp_link: an instance of dp_link module - * - */ -void dp_link_put(struct dp_link *dp_link); - -#endif /* _DP_LINK_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c deleted file mode 100644 index 63f9bf4..0000000 --- a/drivers/gpu/drm/msm/dp/dp_panel.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include "dp_panel.h" - -#include <drm/drm_connector.h> -#include <drm/drm_edid.h> - -#define DP_PANEL_DEFAULT_BPP 24 -#define DP_MAX_DS_PORT_COUNT 1 - -enum { - DP_LINK_RATE_MULTIPLIER = 27000000, -}; - -struct dp_panel_private { - struct device *dev; - struct dp_panel dp_panel; - struct dp_aux *aux; - struct dp_link *link; - struct dp_catalog_panel *catalog; - bool aux_cfg_update_done; -}; - -static const struct dp_panel_info fail_safe = { - .h_active = 640, - .v_active = 480, - .h_back_porch = 48, - .h_front_porch = 16, - .h_sync_width = 96, - .h_active_low = 0, - .v_back_porch = 33, - .v_front_porch = 10, - .v_sync_width = 2, - .v_active_low = 0, - .h_skew = 0, - .refresh_rate = 60, - .pixel_clk_khz = 25200, - .bpp = 24, -}; - -static int dp_panel_read_dpcd(struct dp_panel *dp_panel) -{ - int rlen, rc = 0; - struct dp_panel_private *panel; - struct drm_dp_link *link_info; - u8 *dpcd, major = 0, minor = 0; - u32 dfp_count = 0; - unsigned long caps = DP_LINK_CAP_ENHANCED_FRAMING; - - if (!dp_panel) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - dpcd = dp_panel->dpcd; - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - link_info = &dp_panel->link_info; - - rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV, - dpcd, (DP_RECEIVER_CAP_SIZE + 1)); - if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) { - pr_err("dpcd read failed, rlen=%d\n", rlen); - rc = -EINVAL; - goto end; - } - - link_info->revision = dp_panel->dpcd[DP_DPCD_REV]; - - major = (link_info->revision >> 4) & 0x0f; - minor = link_info->revision & 0x0f; - pr_debug("version: %d.%d\n", major, minor); - - link_info->rate = - drm_dp_bw_code_to_link_rate(dp_panel->dpcd[DP_MAX_LINK_RATE]); - pr_debug("link_rate=%d\n", link_info->rate); - - link_info->num_lanes = dp_panel->dpcd[DP_MAX_LANE_COUNT] & - DP_MAX_LANE_COUNT_MASK; - - pr_debug("lane_count=%d\n", link_info->num_lanes); - - if (drm_dp_enhanced_frame_cap(dpcd)) - link_info->capabilities |= caps; - - dfp_count = dpcd[DP_DOWN_STREAM_PORT_COUNT] & - DP_DOWN_STREAM_PORT_COUNT; - - if ((dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT) - && (dpcd[DP_DPCD_REV] > 0x10)) { - rlen = drm_dp_dpcd_read(panel->aux->drm_aux, - DP_DOWNSTREAM_PORT_0, dp_panel->ds_ports, - DP_MAX_DOWNSTREAM_PORTS); - if (rlen < DP_MAX_DOWNSTREAM_PORTS) { - pr_err("ds port status failed, rlen=%d\n", rlen); - rc = -EINVAL; - goto end; - } - } - - if (dfp_count > DP_MAX_DS_PORT_COUNT) - pr_debug("DS port count %d greater that max (%d) supported\n", - dfp_count, DP_MAX_DS_PORT_COUNT); - -end: - return rc; -} - -static int dp_panel_set_default_link_params(struct dp_panel *dp_panel) -{ - struct drm_dp_link *link_info; - const int default_bw_code = 162000; - const int default_num_lanes = 1; - - if (!dp_panel) { - pr_err("invalid input\n"); - return -EINVAL; - } - link_info = &dp_panel->link_info; - link_info->rate = default_bw_code; - link_info->num_lanes = default_num_lanes; - pr_debug("link_rate=%d num_lanes=%d\n", - link_info->rate, link_info->num_lanes); - return 0; -} - -static int dp_panel_read_edid(struct dp_panel *dp_panel, - struct drm_connector *connector) -{ - int retry_cnt = 0; - const int max_retry = 10; - struct dp_panel_private *panel; - - if (!dp_panel) { - pr_err("invalid input\n"); - return -EINVAL; - } - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - - do { - kfree(dp_panel->edid); - dp_panel->edid = drm_get_edid(connector, - &panel->aux->drm_aux->ddc); - if (!dp_panel->edid) { - pr_err("EDID read failed\n"); - retry_cnt++; - panel->aux->reconfig(panel->aux); - panel->aux_cfg_update_done = true; - } else { - return 0; - } - } while (retry_cnt < max_retry); - - return drm_add_edid_modes(connector, dp_panel->edid); -} - -static int dp_panel_read_sink_caps(struct dp_panel *dp_panel, - struct drm_connector *connector) -{ - int rc = 0; - struct dp_panel_private *panel; - - if (!dp_panel || !connector) { - pr_err("invalid input\n"); - return -EINVAL; - } - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - - rc = dp_panel_read_dpcd(dp_panel); - if (rc || !is_link_rate_valid(drm_dp_link_rate_to_bw_code( - dp_panel->link_info.rate)) || !is_lane_count_valid( - dp_panel->link_info.num_lanes)) { - pr_err("panel dpcd read failed/incorrect, set default params\n"); - dp_panel_set_default_link_params(dp_panel); - } - - rc = dp_panel_read_edid(dp_panel, connector); - if (rc < 0) { - pr_err("panel edid read failed, set failsafe mode\n"); - return rc; - } - - if (panel->aux_cfg_update_done) { - pr_debug("read DPCD with updated AUX config\n"); - dp_panel_read_dpcd(dp_panel); - panel->aux_cfg_update_done = false; - } - - return 0; -} - -static u32 dp_panel_get_max_pclk(struct dp_panel *dp_panel) -{ - struct drm_dp_link *link_info; - const u8 num_components = 3; - u32 bpc = 0, bpp = 0, max_data_rate_khz = 0, max_pclk_rate_khz = 0; - - if (!dp_panel) { - pr_err("invalid input\n"); - return 0; - } - - link_info = &dp_panel->link_info; - - bpc = dp_panel->connector->display_info.bpc; - bpp = bpc * num_components; - if (!bpp) - bpp = DP_PANEL_DEFAULT_BPP; - - max_data_rate_khz = (link_info->num_lanes * link_info->rate * 8); - max_pclk_rate_khz = max_data_rate_khz / bpp; - - pr_debug("bpp=%d, max_lane_cnt=%d\n", bpp, link_info->num_lanes); - pr_debug("max_data_rate=%dKHz, max_pclk_rate=%dKHz\n", - max_data_rate_khz, max_pclk_rate_khz); - - return max_pclk_rate_khz; -} - -static void dp_panel_set_test_mode(struct dp_panel_private *panel, - struct dp_display_mode *mode) -{ - struct dp_panel_info *pinfo = NULL; - struct dp_link_test_video *test_info = NULL; - - if (!panel) { - pr_err("invalid params\n"); - return; - } - - pinfo = &mode->timing; - test_info = &panel->link->test_video; - - pinfo->h_active = test_info->test_h_width; - pinfo->h_sync_width = test_info->test_hsync_width; - pinfo->h_back_porch = test_info->test_h_start - - test_info->test_hsync_width; - pinfo->h_front_porch = test_info->test_h_total - - (test_info->test_h_start + test_info->test_h_width); - - pinfo->v_active = test_info->test_v_height; - pinfo->v_sync_width = test_info->test_vsync_width; - pinfo->v_back_porch = test_info->test_v_start - - test_info->test_vsync_width; - pinfo->v_front_porch = test_info->test_v_total - - (test_info->test_v_start + test_info->test_v_height); - - pinfo->bpp = dp_link_bit_depth_to_bpp(test_info->test_bit_depth); - pinfo->h_active_low = test_info->test_hsync_pol; - pinfo->v_active_low = test_info->test_vsync_pol; - - pinfo->refresh_rate = test_info->test_rr_n; - pinfo->pixel_clk_khz = test_info->test_h_total * - test_info->test_v_total * pinfo->refresh_rate; - - if (test_info->test_rr_d == 0) - pinfo->pixel_clk_khz /= 1000; - else - pinfo->pixel_clk_khz /= 1001; - - if (test_info->test_h_width == 640) - pinfo->pixel_clk_khz = 25170; -} - -static int dp_panel_get_modes(struct dp_panel *dp_panel, - struct drm_connector *connector, struct dp_display_mode *mode) -{ - struct dp_panel_private *panel; - - if (!dp_panel) { - pr_err("invalid input\n"); - return -EINVAL; - } - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - - if (dp_panel->video_test) { - dp_panel_set_test_mode(panel, mode); - return 1; - } else if (dp_panel->edid) { - return dp_panel_read_edid(dp_panel, connector); - } - - /* fail-safe mode */ - memcpy(&mode->timing, &fail_safe, - sizeof(fail_safe)); - return 1; -} - -static u8 dp_panel_get_edid_checksum(struct edid *edid) -{ - struct edid *last_block = NULL; - u8 *raw_edid = NULL; - - if (!edid) { - pr_err("invalid edid input\n"); - return 0; - } - - raw_edid = (u8 *)edid; - raw_edid += (edid->extensions * EDID_LENGTH); - last_block = (struct edid *)raw_edid; - - if (last_block) - return last_block->checksum; - - pr_err("Invalid block, no checksum\n"); - return 0; -} - -static void dp_panel_handle_sink_request(struct dp_panel *dp_panel) -{ - struct dp_panel_private *panel; - - if (!dp_panel) { - pr_err("invalid input\n"); - return; - } - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - - if (panel->link->sink_request & DP_TEST_LINK_EDID_READ) { - u8 checksum = dp_panel_get_edid_checksum(dp_panel->edid); - - panel->link->send_edid_checksum(panel->link, checksum); - panel->link->send_test_response(panel->link); - } -} - -static int dp_panel_timing_cfg(struct dp_panel *dp_panel) -{ - int rc = 0; - u32 data, total_ver, total_hor; - struct dp_catalog_panel *catalog; - struct dp_panel_private *panel; - struct dp_panel_info *pinfo; - - if (!dp_panel) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - catalog = panel->catalog; - pinfo = &panel->dp_panel.pinfo; - - pr_debug("width=%d hporch= %d %d %d\n", - pinfo->h_active, pinfo->h_back_porch, - pinfo->h_front_porch, pinfo->h_sync_width); - - pr_debug("height=%d vporch= %d %d %d\n", - pinfo->v_active, pinfo->v_back_porch, - pinfo->v_front_porch, pinfo->v_sync_width); - - total_hor = pinfo->h_active + pinfo->h_back_porch + - pinfo->h_front_porch + pinfo->h_sync_width; - - total_ver = pinfo->v_active + pinfo->v_back_porch + - pinfo->v_front_porch + pinfo->v_sync_width; - - data = total_ver; - data <<= 16; - data |= total_hor; - - catalog->total = data; - - data = (pinfo->v_back_porch + pinfo->v_sync_width); - data <<= 16; - data |= (pinfo->h_back_porch + pinfo->h_sync_width); - - catalog->sync_start = data; - - data = pinfo->v_sync_width; - data <<= 16; - data |= (pinfo->v_active_low << 31); - data |= pinfo->h_sync_width; - data |= (pinfo->h_active_low << 15); - - catalog->width_blanking = data; - - data = pinfo->v_active; - data <<= 16; - data |= pinfo->h_active; - - catalog->dp_active = data; - - panel->catalog->timing_cfg(catalog); -end: - return rc; -} - -static int dp_panel_init_panel_info(struct dp_panel *dp_panel) -{ - int rc = 0; - struct dp_panel_info *pinfo; - - if (!dp_panel) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto end; - } - - pinfo = &dp_panel->pinfo; - - /* - * print resolution info as this is a result - * of user initiated action of cable connection - */ - pr_info("SET NEW RESOLUTION:\n"); - pr_info("%dx%d@%dfps\n", pinfo->h_active, - pinfo->v_active, pinfo->refresh_rate); - pr_info("h_porches(back|front|width) = (%d|%d|%d)\n", - pinfo->h_back_porch, - pinfo->h_front_porch, - pinfo->h_sync_width); - pr_info("v_porches(back|front|width) = (%d|%d|%d)\n", - pinfo->v_back_porch, - pinfo->v_front_porch, - pinfo->v_sync_width); - pr_info("pixel clock (KHz)=(%d)\n", pinfo->pixel_clk_khz); - pr_info("bpp = %d\n", pinfo->bpp); - pr_info("active low (h|v)=(%d|%d)\n", pinfo->h_active_low, - pinfo->v_active_low); - - pinfo->bpp = max_t(u32, 18, min_t(u32, pinfo->bpp, 30)); - pr_info("updated bpp = %d\n", pinfo->bpp); -end: - return rc; -} - -static u32 dp_panel_get_min_req_link_rate(struct dp_panel *dp_panel) -{ - const u32 encoding_factx10 = 8; - u32 min_link_rate_khz = 0, lane_cnt; - struct dp_panel_info *pinfo; - - if (!dp_panel) { - pr_err("invalid input\n"); - goto end; - } - - lane_cnt = dp_panel->link_info.num_lanes; - pinfo = &dp_panel->pinfo; - - /* num_lanes * lane_count * 8 >= pclk * bpp * 10 */ - min_link_rate_khz = pinfo->pixel_clk_khz / - (lane_cnt * encoding_factx10); - min_link_rate_khz *= pinfo->bpp; - - pr_debug("min lclk req=%d khz for pclk=%d khz, lanes=%d, bpp=%d\n", - min_link_rate_khz, pinfo->pixel_clk_khz, lane_cnt, - pinfo->bpp); -end: - return min_link_rate_khz; -} - -struct dp_panel *dp_panel_get(struct dp_panel_in *in) -{ - int rc = 0; - struct dp_panel_private *panel; - struct dp_panel *dp_panel; - - if (!in->dev || !in->catalog || !in->aux || !in->link) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - panel = devm_kzalloc(in->dev, sizeof(*panel), GFP_KERNEL); - if (!panel) { - rc = -ENOMEM; - goto error; - } - - panel->dev = in->dev; - panel->aux = in->aux; - panel->catalog = in->catalog; - panel->link = in->link; - - dp_panel = &panel->dp_panel; - panel->aux_cfg_update_done = false; - - dp_panel->init_info = dp_panel_init_panel_info; - dp_panel->timing_cfg = dp_panel_timing_cfg; - dp_panel->read_sink_caps = dp_panel_read_sink_caps; - dp_panel->get_min_req_link_rate = dp_panel_get_min_req_link_rate; - dp_panel->get_max_pclk = dp_panel_get_max_pclk; - dp_panel->get_modes = dp_panel_get_modes; - dp_panel->handle_sink_request = dp_panel_handle_sink_request; - - return dp_panel; -error: - return ERR_PTR(rc); -} - -void dp_panel_put(struct dp_panel *dp_panel) -{ - struct dp_panel_private *panel; - - if (!dp_panel) - return; - - panel = container_of(dp_panel, struct dp_panel_private, dp_panel); - - kfree(dp_panel->edid); - dp_panel->edid = NULL; - devm_kfree(panel->dev, panel); -} diff --git a/drivers/gpu/drm/msm/dp/dp_panel.h b/drivers/gpu/drm/msm/dp/dp_panel.h deleted file mode 100644 index d6ebdb9..0000000 --- a/drivers/gpu/drm/msm/dp/dp_panel.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_PANEL_H_ -#define _DP_PANEL_H_ - -#include "dp_aux.h" -#include "dp_link.h" -#include "dp_usbpd.h" - -struct edid; - -enum dp_lane_count { - DP_LANE_COUNT_1 = 1, - DP_LANE_COUNT_2 = 2, - DP_LANE_COUNT_4 = 4, -}; - -#define DP_MAX_DOWNSTREAM_PORTS 0x10 - -struct dp_panel_info { - u32 h_active; - u32 v_active; - u32 h_back_porch; - u32 h_front_porch; - u32 h_sync_width; - u32 h_active_low; - u32 v_back_porch; - u32 v_front_porch; - u32 v_sync_width; - u32 v_active_low; - u32 h_skew; - u32 refresh_rate; - u32 pixel_clk_khz; - u32 bpp; -}; - -struct dp_display_mode { - struct dp_panel_info timing; - u32 capabilities; -}; - -struct dp_panel_in { - struct device *dev; - struct dp_aux *aux; - struct dp_link *link; - struct dp_catalog_panel *catalog; -}; - -struct dp_panel { - /* dpcd raw data */ - u8 dpcd[DP_RECEIVER_CAP_SIZE]; - u8 ds_ports[DP_MAX_DOWNSTREAM_PORTS]; - - struct drm_dp_link link_info; - struct edid *edid; - struct drm_connector *connector; - struct dp_panel_info pinfo; - bool video_test; - - u32 vic; - u32 max_pclk_khz; - - int (*init_info)(struct dp_panel *dp_panel); - int (*timing_cfg)(struct dp_panel *dp_panel); - int (*read_sink_caps)(struct dp_panel *dp_panel, - struct drm_connector *connector); - u32 (*get_min_req_link_rate)(struct dp_panel *dp_panel); - u32 (*get_max_pclk)(struct dp_panel *dp_panel); - int (*get_modes)(struct dp_panel *dp_panel, - struct drm_connector *connector, struct dp_display_mode *mode); - void (*handle_sink_request)(struct dp_panel *dp_panel); -}; - -/** - * is_link_rate_valid() - validates the link rate - * @lane_rate: link rate requested by the sink - * - * Returns true if the requested link rate is supported. - */ -static inline bool is_link_rate_valid(u32 bw_code) -{ - return ((bw_code == DP_LINK_BW_1_62) || - (bw_code == DP_LINK_BW_2_7) || - (bw_code == DP_LINK_BW_5_4) || - (bw_code == DP_LINK_BW_8_1)); -} - -/** - * dp_link_is_lane_count_valid() - validates the lane count - * @lane_count: lane count requested by the sink - * - * Returns true if the requested lane count is supported. - */ -static inline bool is_lane_count_valid(u32 lane_count) -{ - return (lane_count == DP_LANE_COUNT_1) || - (lane_count == DP_LANE_COUNT_2) || - (lane_count == DP_LANE_COUNT_4); -} - -struct dp_panel *dp_panel_get(struct dp_panel_in *in); -void dp_panel_put(struct dp_panel *dp_panel); -#endif /* _DP_PANEL_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_parser.c b/drivers/gpu/drm/msm/dp/dp_parser.c deleted file mode 100644 index b78c311..0000000 --- a/drivers/gpu/drm/msm/dp/dp_parser.c +++ /dev/null @@ -1,645 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/of_gpio.h> - -#include "dp_parser.h" - -static void dp_parser_unmap_io_resources(struct dp_parser *parser) -{ - struct dp_io *io = &parser->io; - - msm_dss_iounmap(&io->ctrl_io); - msm_dss_iounmap(&io->phy_io); - msm_dss_iounmap(&io->ln_tx0_io); - msm_dss_iounmap(&io->ln_tx0_io); - msm_dss_iounmap(&io->dp_pll_io); - msm_dss_iounmap(&io->dp_cc_io); - msm_dss_iounmap(&io->usb3_dp_com); - msm_dss_iounmap(&io->qfprom_io); - msm_dss_iounmap(&io->hdcp_io); -} - -static int dp_parser_ctrl_res(struct dp_parser *parser) -{ - int rc = 0; - u32 index; - struct platform_device *pdev = parser->pdev; - struct device_node *of_node = parser->pdev->dev.of_node; - struct dp_io *io = &parser->io; - - rc = of_property_read_u32(of_node, "cell-index", &index); - if (rc) { - pr_err("cell-index not specified, rc=%d\n", rc); - goto err; - } - - rc = msm_dss_ioremap_byname(pdev, &io->ctrl_io, "dp_ctrl"); - if (rc) { - pr_err("unable to remap dp io resources\n"); - goto err; - } - - rc = msm_dss_ioremap_byname(pdev, &io->phy_io, "dp_phy"); - if (rc) { - pr_err("unable to remap dp PHY resources\n"); - goto err; - } - - rc = msm_dss_ioremap_byname(pdev, &io->ln_tx0_io, "dp_ln_tx0"); - if (rc) { - pr_err("unable to remap dp TX0 resources\n"); - goto err; - } - - rc = msm_dss_ioremap_byname(pdev, &io->ln_tx1_io, "dp_ln_tx1"); - if (rc) { - pr_err("unable to remap dp TX1 resources\n"); - goto err; - } - - rc = msm_dss_ioremap_byname(pdev, &io->dp_pll_io, "dp_pll"); - if (rc) { - pr_err("unable to remap DP PLL resources\n"); - goto err; - } - - rc = msm_dss_ioremap_byname(pdev, &io->usb3_dp_com, "usb3_dp_com"); - if (rc) { - pr_err("unable to remap USB3 DP com resources\n"); - goto err; - } - - if (msm_dss_ioremap_byname(pdev, &io->dp_cc_io, "dp_mmss_cc")) { - pr_err("unable to remap dp MMSS_CC resources\n"); - goto err; - } - - if (msm_dss_ioremap_byname(pdev, &io->qfprom_io, "qfprom_physical")) - pr_warn("unable to remap dp qfprom resources\n"); - - if (msm_dss_ioremap_byname(pdev, &io->hdcp_io, "hdcp_physical")) - pr_warn("unable to remap dp hdcp resources\n"); - - return 0; -err: - dp_parser_unmap_io_resources(parser); - return rc; -} - -static const char *dp_get_phy_aux_config_property(u32 cfg_type) -{ - switch (cfg_type) { - case PHY_AUX_CFG0: - return "qcom,aux-cfg0-settings"; - case PHY_AUX_CFG1: - return "qcom,aux-cfg1-settings"; - case PHY_AUX_CFG2: - return "qcom,aux-cfg2-settings"; - case PHY_AUX_CFG3: - return "qcom,aux-cfg3-settings"; - case PHY_AUX_CFG4: - return "qcom,aux-cfg4-settings"; - case PHY_AUX_CFG5: - return "qcom,aux-cfg5-settings"; - case PHY_AUX_CFG6: - return "qcom,aux-cfg6-settings"; - case PHY_AUX_CFG7: - return "qcom,aux-cfg7-settings"; - case PHY_AUX_CFG8: - return "qcom,aux-cfg8-settings"; - case PHY_AUX_CFG9: - return "qcom,aux-cfg9-settings"; - default: - return "unknown"; - } -} - -static void dp_parser_phy_aux_cfg_reset(struct dp_parser *parser) -{ - int i = 0; - - for (i = 0; i < PHY_AUX_CFG_MAX; i++) - parser->aux_cfg[i] = (const struct dp_aux_cfg){ 0 }; -} - -static int dp_parser_aux(struct dp_parser *parser) -{ - struct device_node *of_node = parser->pdev->dev.of_node; - int len = 0, i = 0, j = 0, config_count = 0; - const char *data; - int const minimum_config_count = 1; - - for (i = 0; i < PHY_AUX_CFG_MAX; i++) { - const char *property = dp_get_phy_aux_config_property(i); - - data = of_get_property(of_node, property, &len); - if (!data) { - pr_err("Unable to read %s\n", property); - goto error; - } - - config_count = len - 1; - if ((config_count < minimum_config_count) || - (config_count > DP_AUX_CFG_MAX_VALUE_CNT)) { - pr_err("Invalid config count (%d) configs for %s\n", - config_count, property); - goto error; - } - - parser->aux_cfg[i].offset = data[0]; - parser->aux_cfg[i].cfg_cnt = config_count; - pr_debug("%s offset=0x%x, cfg_cnt=%d\n", - property, - parser->aux_cfg[i].offset, - parser->aux_cfg[i].cfg_cnt); - for (j = 1; j < len; j++) { - parser->aux_cfg[i].lut[j - 1] = data[j]; - pr_debug("%s lut[%d]=0x%x\n", - property, - i, - parser->aux_cfg[i].lut[j - 1]); - } - } - return 0; - -error: - dp_parser_phy_aux_cfg_reset(parser); - return -EINVAL; -} - -static int dp_parser_misc(struct dp_parser *parser) -{ - int rc = 0; - struct device_node *of_node = parser->pdev->dev.of_node; - - rc = of_property_read_u32(of_node, - "qcom,max-pclk-frequency-khz", &parser->max_pclk_khz); - if (rc) - parser->max_pclk_khz = DP_MAX_PIXEL_CLK_KHZ; - - return 0; -} - -static int dp_parser_pinctrl(struct dp_parser *parser) -{ - int rc = 0; - struct dp_pinctrl *pinctrl = &parser->pinctrl; - - pinctrl->pin = devm_pinctrl_get(&parser->pdev->dev); - - if (IS_ERR_OR_NULL(pinctrl->pin)) { - rc = PTR_ERR(pinctrl->pin); - pr_err("failed to get pinctrl, rc=%d\n", rc); - goto error; - } - - pinctrl->state_active = pinctrl_lookup_state(pinctrl->pin, - "mdss_dp_active"); - if (IS_ERR_OR_NULL(pinctrl->state_active)) { - rc = PTR_ERR(pinctrl->state_active); - pr_err("failed to get pinctrl active state, rc=%d\n", rc); - goto error; - } - - pinctrl->state_suspend = pinctrl_lookup_state(pinctrl->pin, - "mdss_dp_sleep"); - if (IS_ERR_OR_NULL(pinctrl->state_suspend)) { - rc = PTR_ERR(pinctrl->state_suspend); - pr_err("failed to get pinctrl suspend state, rc=%d\n", rc); - goto error; - } -error: - return rc; -} - -static int dp_parser_gpio(struct dp_parser *parser) -{ - int i = 0; - struct device *dev = &parser->pdev->dev; - struct device_node *of_node = dev->of_node; - struct dss_module_power *mp = &parser->mp[DP_CORE_PM]; - static const char * const dp_gpios[] = { - "qcom,aux-en-gpio", - "qcom,aux-sel-gpio", - "qcom,usbplug-cc-gpio", - }; - - mp->gpio_config = devm_kzalloc(dev, - sizeof(struct dss_gpio) * ARRAY_SIZE(dp_gpios), GFP_KERNEL); - mp->num_gpio = ARRAY_SIZE(dp_gpios); - - for (i = 0; i < ARRAY_SIZE(dp_gpios); i++) { - mp->gpio_config[i].gpio = of_get_named_gpio(of_node, - dp_gpios[i], 0); - - if (!gpio_is_valid(mp->gpio_config[i].gpio)) { - pr_err("%s gpio not specified\n", dp_gpios[i]); - return -EINVAL; - } - - strlcpy(mp->gpio_config[i].gpio_name, dp_gpios[i], - sizeof(mp->gpio_config[i].gpio_name)); - - mp->gpio_config[i].value = 0; - } - - return 0; -} - -static const char *dp_parser_supply_node_name(enum dp_pm_type module) -{ - switch (module) { - case DP_CORE_PM: return "qcom,core-supply-entries"; - case DP_CTRL_PM: return "qcom,ctrl-supply-entries"; - case DP_PHY_PM: return "qcom,phy-supply-entries"; - default: return "???"; - } -} - -static int dp_parser_get_vreg(struct dp_parser *parser, - enum dp_pm_type module) -{ - int i = 0, rc = 0; - u32 tmp = 0; - const char *pm_supply_name = NULL; - struct device_node *supply_node = NULL; - struct device_node *of_node = parser->pdev->dev.of_node; - struct device_node *supply_root_node = NULL; - struct dss_module_power *mp = &parser->mp[module]; - - mp->num_vreg = 0; - pm_supply_name = dp_parser_supply_node_name(module); - supply_root_node = of_get_child_by_name(of_node, pm_supply_name); - if (!supply_root_node) { - pr_err("no supply entry present: %s\n", pm_supply_name); - goto novreg; - } - - mp->num_vreg = of_get_available_child_count(supply_root_node); - - if (mp->num_vreg == 0) { - pr_debug("no vreg\n"); - goto novreg; - } else { - pr_debug("vreg found. count=%d\n", mp->num_vreg); - } - - mp->vreg_config = devm_kzalloc(&parser->pdev->dev, - sizeof(struct dss_vreg) * mp->num_vreg, GFP_KERNEL); - if (!mp->vreg_config) { - rc = -ENOMEM; - goto error; - } - - for_each_child_of_node(supply_root_node, supply_node) { - const char *st = NULL; - /* vreg-name */ - rc = of_property_read_string(supply_node, - "qcom,supply-name", &st); - if (rc) { - pr_err("error reading name. rc=%d\n", - rc); - goto error; - } - snprintf(mp->vreg_config[i].vreg_name, - ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st); - /* vreg-min-voltage */ - rc = of_property_read_u32(supply_node, - "qcom,supply-min-voltage", &tmp); - if (rc) { - pr_err("error reading min volt. rc=%d\n", - rc); - goto error; - } - mp->vreg_config[i].min_voltage = tmp; - - /* vreg-max-voltage */ - rc = of_property_read_u32(supply_node, - "qcom,supply-max-voltage", &tmp); - if (rc) { - pr_err("error reading max volt. rc=%d\n", - rc); - goto error; - } - mp->vreg_config[i].max_voltage = tmp; - - /* enable-load */ - rc = of_property_read_u32(supply_node, - "qcom,supply-enable-load", &tmp); - if (rc) { - pr_err("error reading enable load. rc=%d\n", - rc); - goto error; - } - mp->vreg_config[i].enable_load = tmp; - - /* disable-load */ - rc = of_property_read_u32(supply_node, - "qcom,supply-disable-load", &tmp); - if (rc) { - pr_err("error reading disable load. rc=%d\n", - rc); - goto error; - } - mp->vreg_config[i].disable_load = tmp; - - pr_debug("%s min=%d, max=%d, enable=%d, disable=%d\n", - mp->vreg_config[i].vreg_name, - mp->vreg_config[i].min_voltage, - mp->vreg_config[i].max_voltage, - mp->vreg_config[i].enable_load, - mp->vreg_config[i].disable_load - ); - ++i; - } - - return rc; - -error: - if (mp->vreg_config) { - devm_kfree(&parser->pdev->dev, mp->vreg_config); - mp->vreg_config = NULL; - } -novreg: - mp->num_vreg = 0; - - return rc; -} - -static void dp_parser_put_vreg_data(struct device *dev, - struct dss_module_power *mp) -{ - if (!mp) { - DEV_ERR("invalid input\n"); - return; - } - - if (mp->vreg_config) { - devm_kfree(dev, mp->vreg_config); - mp->vreg_config = NULL; - } - mp->num_vreg = 0; -} - -static int dp_parser_regulator(struct dp_parser *parser) -{ - int i, rc = 0; - struct platform_device *pdev = parser->pdev; - - /* Parse the regulator information */ - for (i = DP_CORE_PM; i < DP_MAX_PM; i++) { - rc = dp_parser_get_vreg(parser, i); - if (rc) { - pr_err("get_dt_vreg_data failed for %s. rc=%d\n", - dp_parser_pm_name(i), rc); - i--; - for (; i >= DP_CORE_PM; i--) - dp_parser_put_vreg_data(&pdev->dev, - &parser->mp[i]); - break; - } - } - - return rc; -} - -static bool dp_parser_check_prefix(const char *clk_prefix, const char *clk_name) -{ - return !!strnstr(clk_name, clk_prefix, strlen(clk_name)); -} - -static void dp_parser_put_clk_data(struct device *dev, - struct dss_module_power *mp) -{ - if (!mp) { - DEV_ERR("%s: invalid input\n", __func__); - return; - } - - if (mp->clk_config) { - devm_kfree(dev, mp->clk_config); - mp->clk_config = NULL; - } - - mp->num_clk = 0; -} - -static int dp_parser_init_clk_data(struct dp_parser *parser) -{ - int num_clk = 0, i = 0, rc = 0; - int core_clk_count = 0, ctrl_clk_count = 0; - const char *core_clk = "core"; - const char *ctrl_clk = "ctrl"; - const char *clk_name; - struct device *dev = &parser->pdev->dev; - struct dss_module_power *core_power = &parser->mp[DP_CORE_PM]; - struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM]; - - num_clk = of_property_count_strings(dev->of_node, "clock-names"); - if (num_clk <= 0) { - pr_err("no clocks are defined\n"); - rc = -EINVAL; - goto exit; - } - - for (i = 0; i < num_clk; i++) { - of_property_read_string_index(dev->of_node, - "clock-names", i, &clk_name); - - if (dp_parser_check_prefix(core_clk, clk_name)) - core_clk_count++; - - if (dp_parser_check_prefix(ctrl_clk, clk_name)) - ctrl_clk_count++; - } - - /* Initialize the CORE power module */ - if (core_clk_count <= 0) { - pr_err("no core clocks are defined\n"); - rc = -EINVAL; - goto exit; - } - - core_power->num_clk = core_clk_count; - core_power->clk_config = devm_kzalloc(dev, - sizeof(struct dss_clk) * core_power->num_clk, - GFP_KERNEL); - if (!core_power->clk_config) { - rc = -EINVAL; - goto exit; - } - - /* Initialize the CTRL power module */ - if (ctrl_clk_count <= 0) { - pr_err("no ctrl clocks are defined\n"); - rc = -EINVAL; - goto ctrl_clock_error; - } - - ctrl_power->num_clk = ctrl_clk_count; - ctrl_power->clk_config = devm_kzalloc(dev, - sizeof(struct dss_clk) * ctrl_power->num_clk, - GFP_KERNEL); - if (!ctrl_power->clk_config) { - ctrl_power->num_clk = 0; - rc = -EINVAL; - goto ctrl_clock_error; - } - - return rc; - -ctrl_clock_error: - dp_parser_put_clk_data(dev, core_power); -exit: - return rc; -} - -static int dp_parser_clock(struct dp_parser *parser) -{ - int rc = 0, i = 0; - int num_clk = 0; - int core_clk_index = 0, ctrl_clk_index = 0; - int core_clk_count = 0, ctrl_clk_count = 0; - const char *clk_name; - const char *core_clk = "core"; - const char *ctrl_clk = "ctrl"; - struct device *dev = &parser->pdev->dev; - struct dss_module_power *core_power = &parser->mp[DP_CORE_PM]; - struct dss_module_power *ctrl_power = &parser->mp[DP_CTRL_PM]; - - core_power = &parser->mp[DP_CORE_PM]; - ctrl_power = &parser->mp[DP_CTRL_PM]; - - rc = dp_parser_init_clk_data(parser); - if (rc) { - pr_err("failed to initialize power data\n"); - rc = -EINVAL; - goto exit; - } - - core_clk_count = core_power->num_clk; - ctrl_clk_count = ctrl_power->num_clk; - - num_clk = core_clk_count + ctrl_clk_count; - - for (i = 0; i < num_clk; i++) { - of_property_read_string_index(dev->of_node, "clock-names", - i, &clk_name); - - if (dp_parser_check_prefix(core_clk, clk_name) && - core_clk_index < core_clk_count) { - struct dss_clk *clk = - &core_power->clk_config[core_clk_index]; - strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); - clk->type = DSS_CLK_AHB; - core_clk_index++; - } else if (dp_parser_check_prefix(ctrl_clk, clk_name) && - ctrl_clk_index < ctrl_clk_count) { - struct dss_clk *clk = - &ctrl_power->clk_config[ctrl_clk_index]; - strlcpy(clk->clk_name, clk_name, sizeof(clk->clk_name)); - ctrl_clk_index++; - - if (!strcmp(clk_name, "ctrl_link_clk") || - !strcmp(clk_name, "ctrl_pixel_clk")) - clk->type = DSS_CLK_PCLK; - else - clk->type = DSS_CLK_AHB; - } - } - - pr_debug("clock parsing successful\n"); - -exit: - return rc; -} - -static int dp_parser_parse(struct dp_parser *parser) -{ - int rc = 0; - - if (!parser) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto err; - } - - rc = dp_parser_ctrl_res(parser); - if (rc) - goto err; - - rc = dp_parser_aux(parser); - if (rc) - goto err; - - rc = dp_parser_misc(parser); - if (rc) - goto err; - - rc = dp_parser_clock(parser); - if (rc) - goto err; - - rc = dp_parser_regulator(parser); - if (rc) - goto err; - - rc = dp_parser_gpio(parser); - if (rc) - goto err; - - rc = dp_parser_pinctrl(parser); -err: - return rc; -} - -struct dp_parser *dp_parser_get(struct platform_device *pdev) -{ - struct dp_parser *parser; - - parser = devm_kzalloc(&pdev->dev, sizeof(*parser), GFP_KERNEL); - if (!parser) - return ERR_PTR(-ENOMEM); - - parser->parse = dp_parser_parse; - parser->pdev = pdev; - - return parser; -} - -void dp_parser_put(struct dp_parser *parser) -{ - int i = 0; - struct dss_module_power *power = NULL; - - if (!parser) { - pr_err("invalid parser module\n"); - return; - } - - power = parser->mp; - - for (i = 0; i < DP_MAX_PM; i++) { - struct dss_module_power *mp = &power[i]; - - devm_kfree(&parser->pdev->dev, mp->clk_config); - devm_kfree(&parser->pdev->dev, mp->vreg_config); - devm_kfree(&parser->pdev->dev, mp->gpio_config); - } - - devm_kfree(&parser->pdev->dev, parser); -} diff --git a/drivers/gpu/drm/msm/dp/dp_parser.h b/drivers/gpu/drm/msm/dp/dp_parser.h deleted file mode 100644 index a9cfd03..0000000 --- a/drivers/gpu/drm/msm/dp/dp_parser.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_PARSER_H_ -#define _DP_PARSER_H_ - -#include <linux/dpu_io_util.h> - -#define DP_LABEL "MDSS DP DISPLAY" -#define AUX_CFG_LEN 10 -#define DP_MAX_PIXEL_CLK_KHZ 675000 - -enum dp_pm_type { - DP_CORE_PM, - DP_CTRL_PM, - DP_PHY_PM, - DP_MAX_PM -}; - -static inline const char *dp_parser_pm_name(enum dp_pm_type module) -{ - switch (module) { - case DP_CORE_PM: return "DP_CORE_PM"; - case DP_CTRL_PM: return "DP_CTRL_PM"; - case DP_PHY_PM: return "DP_PHY_PM"; - default: return "???"; - } -} - -/** - * struct dp_display_data - display related device tree data. - * - * @ctrl_node: referece to controller device - * @phy_node: reference to phy device - * @is_active: is the controller currently active - * @name: name of the display - * @display_type: type of the display - */ -struct dp_display_data { - struct device_node *ctrl_node; - struct device_node *phy_node; - bool is_active; - const char *name; - const char *display_type; -}; - -/** - * struct dp_ctrl_resource - controller's IO related data - * - * @ctrl_io: controller's mapped memory address - * @phy_io: phy's mapped memory address - * @ln_tx0_io: USB-DP lane TX0's mapped memory address - * @ln_tx1_io: USB-DP lane TX1's mapped memory address - * @dp_cc_io: DP cc's mapped memory address - * @qfprom_io: qfprom's mapped memory address - * @dp_pll_io: DP PLL mapped memory address - * @usb3_dp_com: USB3 DP PHY combo mapped memory address - * @hdcp_io: hdcp's mapped memory address - */ -struct dp_io { - struct dss_io_data ctrl_io; - struct dss_io_data phy_io; - struct dss_io_data ln_tx0_io; - struct dss_io_data ln_tx1_io; - struct dss_io_data dp_cc_io; - struct dss_io_data qfprom_io; - struct dss_io_data dp_pll_io; - struct dss_io_data usb3_dp_com; - struct dss_io_data hdcp_io; -}; - -/** - * struct dp_pinctrl - DP's pin control - * - * @pin: pin-controller's instance - * @state_active: active state pin control - * @state_hpd_active: hpd active state pin control - * @state_suspend: suspend state pin control - */ -struct dp_pinctrl { - struct pinctrl *pin; - struct pinctrl_state *state_active; - struct pinctrl_state *state_hpd_active; - struct pinctrl_state *state_suspend; -}; - -#define DP_ENUM_STR(x) #x -#define DP_AUX_CFG_MAX_VALUE_CNT 3 -/** - * struct dp_aux_cfg - DP's AUX configuration settings - * - * @cfg_cnt: count of the configurable settings for the AUX register - * @current_index: current index of the AUX config lut - * @offset: register offset of the AUX config register - * @lut: look up table for the AUX config values for this register - */ -struct dp_aux_cfg { - u32 cfg_cnt; - u32 current_index; - u32 offset; - u32 lut[DP_AUX_CFG_MAX_VALUE_CNT]; -}; - -/* PHY AUX config registers */ -enum dp_phy_aux_config_type { - PHY_AUX_CFG0, - PHY_AUX_CFG1, - PHY_AUX_CFG2, - PHY_AUX_CFG3, - PHY_AUX_CFG4, - PHY_AUX_CFG5, - PHY_AUX_CFG6, - PHY_AUX_CFG7, - PHY_AUX_CFG8, - PHY_AUX_CFG9, - PHY_AUX_CFG_MAX, -}; - -static inline char *dp_phy_aux_config_type_to_string(u32 cfg_type) -{ - switch (cfg_type) { - case PHY_AUX_CFG0: - return DP_ENUM_STR(PHY_AUX_CFG0); - case PHY_AUX_CFG1: - return DP_ENUM_STR(PHY_AUX_CFG1); - case PHY_AUX_CFG2: - return DP_ENUM_STR(PHY_AUX_CFG2); - case PHY_AUX_CFG3: - return DP_ENUM_STR(PHY_AUX_CFG3); - case PHY_AUX_CFG4: - return DP_ENUM_STR(PHY_AUX_CFG4); - case PHY_AUX_CFG5: - return DP_ENUM_STR(PHY_AUX_CFG5); - case PHY_AUX_CFG6: - return DP_ENUM_STR(PHY_AUX_CFG6); - case PHY_AUX_CFG7: - return DP_ENUM_STR(PHY_AUX_CFG7); - case PHY_AUX_CFG8: - return DP_ENUM_STR(PHY_AUX_CFG8); - case PHY_AUX_CFG9: - return DP_ENUM_STR(PHY_AUX_CFG9); - default: - return "unknown"; - } -} - -/** - * struct dp_parser - DP parser's data exposed to clients - * - * @pdev: platform data of the client - * @mp: gpio, regulator and clock related data - * @pinctrl: pin-control related data - * @disp_data: controller's display related data - * @parse: function to be called by client to parse device tree. - */ -struct dp_parser { - struct platform_device *pdev; - struct dss_module_power mp[DP_MAX_PM]; - struct dp_pinctrl pinctrl; - struct dp_io io; - struct dp_display_data disp_data; - - u8 l_map[4]; - struct dp_aux_cfg aux_cfg[AUX_CFG_LEN]; - u32 max_pclk_khz; - - int (*parse)(struct dp_parser *parser); -}; - -/** - * dp_parser_get() - get the DP's device tree parser module - * - * @pdev: platform data of the client - * return: pointer to dp_parser structure. - * - * This function provides client capability to parse the - * device tree and populate the data structures. The data - * related to clock, regulators, pin-control and other - * can be parsed using this module. - */ -struct dp_parser *dp_parser_get(struct platform_device *pdev); - -/** - * dp_parser_put() - cleans the dp_parser module - * - * @parser: pointer to the parser's data. - */ -void dp_parser_put(struct dp_parser *parser); -#endif diff --git a/drivers/gpu/drm/msm/dp/dp_power.c b/drivers/gpu/drm/msm/dp/dp_power.c deleted file mode 100644 index 2a85b38..0000000 --- a/drivers/gpu/drm/msm/dp/dp_power.c +++ /dev/null @@ -1,593 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/clk.h> -#include "dp_power.h" - -#define DP_CLIENT_NAME_SIZE 20 - -struct dp_power_private { - struct dp_parser *parser; - struct platform_device *pdev; - struct clk *pixel_clk_rcg; - struct clk *pixel_parent; - - struct dp_power dp_power; - - bool core_clks_on; - bool link_clks_on; -}; - -static int dp_power_regulator_init(struct dp_power_private *power) -{ - int rc = 0, i = 0, j = 0; - struct platform_device *pdev; - struct dp_parser *parser; - - parser = power->parser; - pdev = power->pdev; - - for (i = DP_CORE_PM; !rc && (i < DP_MAX_PM); i++) { - rc = msm_dss_config_vreg(&pdev->dev, - parser->mp[i].vreg_config, - parser->mp[i].num_vreg, 1); - if (rc) { - pr_err("failed to init vregs for %s\n", - dp_parser_pm_name(i)); - for (j = i - 1; j >= DP_CORE_PM; j--) { - msm_dss_config_vreg(&pdev->dev, - parser->mp[j].vreg_config, - parser->mp[j].num_vreg, 0); - } - - goto error; - } - } -error: - return rc; -} - -static void dp_power_regulator_deinit(struct dp_power_private *power) -{ - int rc = 0, i = 0; - struct platform_device *pdev; - struct dp_parser *parser; - - parser = power->parser; - pdev = power->pdev; - - for (i = DP_CORE_PM; (i < DP_MAX_PM); i++) { - rc = msm_dss_config_vreg(&pdev->dev, - parser->mp[i].vreg_config, - parser->mp[i].num_vreg, 0); - if (rc) - pr_err("failed to deinit vregs for %s\n", - dp_parser_pm_name(i)); - } -} - -static int dp_power_regulator_ctrl(struct dp_power_private *power, bool enable) -{ - int rc = 0, i = 0, j = 0; - struct dp_parser *parser; - - parser = power->parser; - - for (i = DP_CORE_PM; i < DP_MAX_PM; i++) { - rc = msm_dss_enable_vreg( - parser->mp[i].vreg_config, - parser->mp[i].num_vreg, enable); - if (rc) { - pr_err("failed to '%s' vregs for %s\n", - enable ? "enable" : "disable", - dp_parser_pm_name(i)); - if (enable) { - for (j = i-1; j >= DP_CORE_PM; j--) { - msm_dss_enable_vreg( - parser->mp[j].vreg_config, - parser->mp[j].num_vreg, 0); - } - } - goto error; - } - } -error: - return rc; -} - -static int dp_power_pinctrl_set(struct dp_power_private *power, bool active) -{ - int rc = -EFAULT; - struct pinctrl_state *pin_state; - struct dp_parser *parser; - - parser = power->parser; - - if (IS_ERR_OR_NULL(parser->pinctrl.pin)) - return PTR_ERR(parser->pinctrl.pin); - - pin_state = active ? parser->pinctrl.state_active - : parser->pinctrl.state_suspend; - if (!IS_ERR_OR_NULL(pin_state)) { - rc = pinctrl_select_state(parser->pinctrl.pin, - pin_state); - if (rc) - pr_err("can not set %s pins\n", - active ? "dp_active" - : "dp_sleep"); - } else { - pr_err("invalid '%s' pinstate\n", - active ? "dp_active" - : "dp_sleep"); - } - - return rc; -} - -static int dp_power_clk_init(struct dp_power_private *power, bool enable) -{ - int rc = 0; - struct dss_module_power *core, *ctrl; - struct device *dev; - - core = &power->parser->mp[DP_CORE_PM]; - ctrl = &power->parser->mp[DP_CTRL_PM]; - - dev = &power->pdev->dev; - - if (!core || !ctrl) { - pr_err("invalid power_data\n"); - rc = -EINVAL; - goto exit; - } - - if (enable) { - rc = msm_dss_get_clk(dev, core->clk_config, core->num_clk); - if (rc) { - pr_err("failed to get %s clk. err=%d\n", - dp_parser_pm_name(DP_CORE_PM), rc); - goto exit; - } - - rc = msm_dss_get_clk(dev, ctrl->clk_config, ctrl->num_clk); - if (rc) { - pr_err("failed to get %s clk. err=%d\n", - dp_parser_pm_name(DP_CTRL_PM), rc); - goto ctrl_get_error; - } - - power->pixel_clk_rcg = devm_clk_get(dev, "pixel_clk_rcg"); - if (IS_ERR(power->pixel_clk_rcg)) { - pr_debug("Unable to get DP pixel clk RCG\n"); - power->pixel_clk_rcg = NULL; - } - - power->pixel_parent = devm_clk_get(dev, "pixel_parent"); - if (IS_ERR(power->pixel_parent)) { - pr_debug("Unable to get DP pixel RCG parent\n"); - power->pixel_parent = NULL; - } - } else { - if (power->pixel_parent) - devm_clk_put(dev, power->pixel_parent); - - if (power->pixel_clk_rcg) - devm_clk_put(dev, power->pixel_clk_rcg); - - msm_dss_put_clk(ctrl->clk_config, ctrl->num_clk); - msm_dss_put_clk(core->clk_config, core->num_clk); - } - - return rc; - -ctrl_get_error: - msm_dss_put_clk(core->clk_config, core->num_clk); -exit: - return rc; -} - -static int dp_power_clk_set_rate(struct dp_power_private *power, - enum dp_pm_type module, bool enable) -{ - int rc = 0; - struct dss_module_power *mp; - - if (!power) { - pr_err("invalid power data\n"); - rc = -EINVAL; - goto exit; - } - - mp = &power->parser->mp[module]; - - if (enable) { - rc = msm_dss_clk_set_rate(mp->clk_config, mp->num_clk); - if (rc) { - pr_err("failed to set clks rate.\n"); - goto exit; - } - - rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 1); - if (rc) { - pr_err("failed to enable clks\n"); - goto exit; - } - } else { - rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, 0); - if (rc) { - pr_err("failed to disable clks\n"); - goto exit; - } - } -exit: - return rc; -} - -static int dp_power_clk_enable(struct dp_power *dp_power, - enum dp_pm_type pm_type, bool enable) -{ - int rc = 0; - struct dss_module_power *mp; - struct dp_power_private *power; - - if (!dp_power) { - pr_err("invalid power data\n"); - rc = -EINVAL; - goto error; - } - - power = container_of(dp_power, struct dp_power_private, dp_power); - - mp = &power->parser->mp[pm_type]; - - if ((pm_type != DP_CORE_PM) && (pm_type != DP_CTRL_PM)) { - pr_err("unsupported power module: %s\n", - dp_parser_pm_name(pm_type)); - return -EINVAL; - } - - if (enable) { - if ((pm_type == DP_CORE_PM) - && (power->core_clks_on)) { - pr_debug("core clks already enabled\n"); - return 0; - } - - if ((pm_type == DP_CTRL_PM) - && (power->link_clks_on)) { - pr_debug("links clks already enabled\n"); - return 0; - } - - if ((pm_type == DP_CTRL_PM) && (!power->core_clks_on)) { - pr_debug("Need to enable core clks before link clks\n"); - - rc = dp_power_clk_set_rate(power, pm_type, enable); - if (rc) { - pr_err("failed to enable clks: %s. err=%d\n", - dp_parser_pm_name(DP_CORE_PM), rc); - goto error; - } else { - power->core_clks_on = true; - } - } - } - - rc = dp_power_clk_set_rate(power, pm_type, enable); - if (rc) { - pr_err("failed to '%s' clks for: %s. err=%d\n", - enable ? "enable" : "disable", - dp_parser_pm_name(pm_type), rc); - goto error; - } - - if (pm_type == DP_CORE_PM) - power->core_clks_on = enable; - else - power->link_clks_on = enable; - - pr_debug("%s clocks for %s\n", - enable ? "enable" : "disable", - dp_parser_pm_name(pm_type)); - pr_debug("link_clks:%s core_clks:%s\n", - power->link_clks_on ? "on" : "off", - power->core_clks_on ? "on" : "off"); -error: - return rc; -} - -static int dp_power_request_gpios(struct dp_power_private *power) -{ - int rc = 0, i; - struct device *dev; - struct dss_module_power *mp; - static const char * const gpio_names[] = { - "aux_enable", "aux_sel", "usbplug_cc", - }; - - if (!power) { - pr_err("invalid power data\n"); - return -EINVAL; - } - - dev = &power->pdev->dev; - mp = &power->parser->mp[DP_CORE_PM]; - - for (i = 0; i < ARRAY_SIZE(gpio_names); i++) { - unsigned int gpio = mp->gpio_config[i].gpio; - - if (gpio_is_valid(gpio)) { - rc = devm_gpio_request(dev, gpio, gpio_names[i]); - if (rc) { - pr_err("request %s gpio failed, rc=%d\n", - gpio_names[i], rc); - goto error; - } - } - } - return 0; -error: - for (i = 0; i < ARRAY_SIZE(gpio_names); i++) { - unsigned int gpio = mp->gpio_config[i].gpio; - - if (gpio_is_valid(gpio)) - gpio_free(gpio); - } - return rc; -} - -static bool dp_power_find_gpio(const char *gpio1, const char *gpio2) -{ - return !!strnstr(gpio1, gpio2, strlen(gpio1)); -} - -static void dp_power_set_gpio(struct dp_power_private *power, bool flip) -{ - int i; - struct dss_module_power *mp = &power->parser->mp[DP_CORE_PM]; - struct dss_gpio *config = mp->gpio_config; - - for (i = 0; i < mp->num_gpio; i++) { - if (dp_power_find_gpio(config->gpio_name, "aux-sel")) - config->value = flip; - - if (gpio_is_valid(config->gpio)) { - pr_debug("gpio %s, value %d\n", config->gpio_name, - config->value); - - if (dp_power_find_gpio(config->gpio_name, "aux-en") || - dp_power_find_gpio(config->gpio_name, "aux-sel")) - gpio_direction_output(config->gpio, - config->value); - else - gpio_set_value(config->gpio, config->value); - - } - config++; - } -} - -static int dp_power_config_gpios(struct dp_power_private *power, bool flip, - bool enable) -{ - int rc = 0, i; - struct dss_module_power *mp; - struct dss_gpio *config; - - mp = &power->parser->mp[DP_CORE_PM]; - config = mp->gpio_config; - - if (enable) { - rc = dp_power_request_gpios(power); - if (rc) { - pr_err("gpio request failed\n"); - return rc; - } - - dp_power_set_gpio(power, flip); - } else { - for (i = 0; i < mp->num_gpio; i++) { - gpio_set_value(config[i].gpio, 0); - gpio_free(config[i].gpio); - } - } - - return 0; -} - -static int dp_power_client_init(struct dp_power *dp_power) -{ - int rc = 0; - struct dp_power_private *power; - char dp_client_name[DP_CLIENT_NAME_SIZE]; - - if (!dp_power) { - pr_err("invalid power data\n"); - return -EINVAL; - } - - power = container_of(dp_power, struct dp_power_private, dp_power); - - rc = dp_power_regulator_init(power); - if (rc) { - pr_err("failed to init regulators\n"); - goto error_power; - } - - rc = dp_power_clk_init(power, true); - if (rc) { - pr_err("failed to init clocks\n"); - goto error_clk; - } - - return 0; - -error_clk: - dp_power_regulator_deinit(power); -error_power: - return rc; -} - -static void dp_power_client_deinit(struct dp_power *dp_power) -{ - struct dp_power_private *power; - - if (!dp_power) { - pr_err("invalid power data\n"); - return; - } - - power = container_of(dp_power, struct dp_power_private, dp_power); - - dp_power_clk_init(power, false); - dp_power_regulator_deinit(power); -} - -static int dp_power_set_pixel_clk_parent(struct dp_power *dp_power) -{ - int rc = 0; - struct dp_power_private *power; - - if (!dp_power) { - pr_err("invalid power data\n"); - rc = -EINVAL; - goto exit; - } - - power = container_of(dp_power, struct dp_power_private, dp_power); - - if (power->pixel_clk_rcg && power->pixel_parent) - clk_set_parent(power->pixel_clk_rcg, power->pixel_parent); -exit: - return rc; -} - -static int dp_power_init(struct dp_power *dp_power, bool flip) -{ - int rc = 0; - struct dp_power_private *power; - - if (!dp_power) { - pr_err("invalid power data\n"); - rc = -EINVAL; - goto exit; - } - - power = container_of(dp_power, struct dp_power_private, dp_power); - - rc = dp_power_regulator_ctrl(power, true); - if (rc) { - pr_err("failed to enable regulators\n"); - goto exit; - } - - rc = dp_power_pinctrl_set(power, true); - if (rc) { - pr_err("failed to set pinctrl state\n"); - goto err_pinctrl; - } - - rc = dp_power_config_gpios(power, flip, true); - if (rc) { - pr_err("failed to enable gpios\n"); - goto err_gpio; - } - - rc = dp_power_clk_enable(dp_power, DP_CORE_PM, true); - if (rc) { - pr_err("failed to enable DP core clocks\n"); - goto err_clk; - } - - return 0; - -err_clk: - dp_power_config_gpios(power, flip, false); -err_gpio: - dp_power_pinctrl_set(power, false); -err_pinctrl: - dp_power_regulator_ctrl(power, false); -exit: - return rc; -} - -static int dp_power_deinit(struct dp_power *dp_power) -{ - int rc = 0; - struct dp_power_private *power; - - if (!dp_power) { - pr_err("invalid power data\n"); - rc = -EINVAL; - goto exit; - } - - power = container_of(dp_power, struct dp_power_private, dp_power); - - dp_power_clk_enable(dp_power, DP_CORE_PM, false); - dp_power_config_gpios(power, false, false); - dp_power_pinctrl_set(power, false); - dp_power_regulator_ctrl(power, false); -exit: - return rc; -} - -struct dp_power *dp_power_get(struct dp_parser *parser) -{ - int rc = 0; - struct dp_power_private *power; - struct dp_power *dp_power; - - if (!parser) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - power = devm_kzalloc(&parser->pdev->dev, sizeof(*power), GFP_KERNEL); - if (!power) { - rc = -ENOMEM; - goto error; - } - - power->parser = parser; - power->pdev = parser->pdev; - - dp_power = &power->dp_power; - - dp_power->init = dp_power_init; - dp_power->deinit = dp_power_deinit; - dp_power->clk_enable = dp_power_clk_enable; - dp_power->set_pixel_clk_parent = dp_power_set_pixel_clk_parent; - dp_power->power_client_init = dp_power_client_init; - dp_power->power_client_deinit = dp_power_client_deinit; - - return dp_power; -error: - return ERR_PTR(rc); -} - -void dp_power_put(struct dp_power *dp_power) -{ - struct dp_power_private *power = NULL; - - if (!dp_power) - return; - - power = container_of(dp_power, struct dp_power_private, dp_power); - - devm_kfree(&power->pdev->dev, power); -} diff --git a/drivers/gpu/drm/msm/dp/dp_power.h b/drivers/gpu/drm/msm/dp/dp_power.h deleted file mode 100644 index d9dab72..0000000 --- a/drivers/gpu/drm/msm/dp/dp_power.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_POWER_H_ -#define _DP_POWER_H_ - -#include "dp_parser.h" - -/** - * sruct dp_power - DisplayPort's power related data - * - * @init: initializes the regulators/core clocks/GPIOs/pinctrl - * @deinit: turns off the regulators/core clocks/GPIOs/pinctrl - * @clk_enable: enable/disable the DP clocks - * @set_pixel_clk_parent: set the parent of DP pixel clock - */ -struct dp_power { - int (*init)(struct dp_power *power, bool flip); - int (*deinit)(struct dp_power *power); - int (*clk_enable)(struct dp_power *power, enum dp_pm_type pm_type, - bool enable); - int (*set_pixel_clk_parent)(struct dp_power *power); - int (*power_client_init)(struct dp_power *power); - void (*power_client_deinit)(struct dp_power *power); -}; - -/** - * dp_power_get() - configure and get the DisplayPort power module data - * - * @parser: instance of parser module - * return: pointer to allocated power module data - * - * This API will configure the DisplayPort's power module and provides - * methods to be called by the client to configure the power related - * modueles. - */ -struct dp_power *dp_power_get(struct dp_parser *parser); - -/** - * dp_power_put() - release the power related resources - * - * @power: pointer to the power module's data - */ -void dp_power_put(struct dp_power *power); -#endif /* _DP_POWER_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_reg.h b/drivers/gpu/drm/msm/dp/dp_reg.h deleted file mode 100644 index dba9098..0000000 --- a/drivers/gpu/drm/msm/dp/dp_reg.h +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_REG_H_ -#define _DP_REG_H_ - -/* DP_TX Registers */ -#define DP_HW_VERSION (0x00000000) -#define DP_SW_RESET (0x00000010) -#define DP_PHY_CTRL (0x00000014) -#define DP_CLK_CTRL (0x00000018) -#define DP_CLK_ACTIVE (0x0000001C) -#define DP_INTR_STATUS (0x00000020) -#define DP_INTR_STATUS2 (0x00000024) -#define DP_INTR_STATUS3 (0x00000028) - -#define DP_DP_HPD_CTRL (0x00000200) -#define DP_DP_HPD_INT_STATUS (0x00000204) -#define DP_DP_HPD_INT_ACK (0x00000208) -#define DP_DP_HPD_INT_MASK (0x0000020C) -#define DP_DP_HPD_REFTIMER (0x00000218) -#define DP_DP_HPD_EVENT_TIME_0 (0x0000021C) -#define DP_DP_HPD_EVENT_TIME_1 (0x00000220) -#define DP_AUX_CTRL (0x00000230) -#define DP_AUX_DATA (0x00000234) -#define DP_AUX_TRANS_CTRL (0x00000238) -#define DP_TIMEOUT_COUNT (0x0000023C) -#define DP_AUX_LIMITS (0x00000240) -#define DP_AUX_STATUS (0x00000244) - -#define DP_DPCD_CP_IRQ (0x201) -#define DP_DPCD_RXSTATUS (0x69493) - -#define DP_INTERRUPT_TRANS_NUM (0x000002A0) - -#define DP_MAINLINK_CTRL (0x00000400) -#define DP_STATE_CTRL (0x00000404) -#define DP_CONFIGURATION_CTRL (0x00000408) -#define DP_SOFTWARE_MVID (0x00000410) -#define DP_SOFTWARE_NVID (0x00000418) -#define DP_TOTAL_HOR_VER (0x0000041C) -#define DP_START_HOR_VER_FROM_SYNC (0x00000420) -#define DP_HSYNC_VSYNC_WIDTH_POLARITY (0x00000424) -#define DP_ACTIVE_HOR_VER (0x00000428) -#define DP_MISC1_MISC0 (0x0000042C) -#define DP_VALID_BOUNDARY (0x00000430) -#define DP_VALID_BOUNDARY_2 (0x00000434) -#define DP_LOGICAL2PHYSCIAL_LANE_MAPPING (0x00000438) - -#define DP_MAINLINK_READY (0x00000440) -#define DP_MAINLINK_LEVELS (0x00000444) -#define DP_TU (0x0000044C) - -#define DP_HBR2_COMPLIANCE_SCRAMBLER_RESET (0x00000454) -#define DP_TEST_80BIT_CUSTOM_PATTERN_REG0 (0x000004C0) -#define DP_TEST_80BIT_CUSTOM_PATTERN_REG1 (0x000004C4) -#define DP_TEST_80BIT_CUSTOM_PATTERN_REG2 (0x000004C8) - -#define MMSS_DP_MISC1_MISC0 (0x0000042C) -#define MMSS_DP_AUDIO_TIMING_GEN (0x00000480) -#define MMSS_DP_AUDIO_TIMING_RBR_32 (0x00000484) -#define MMSS_DP_AUDIO_TIMING_HBR_32 (0x00000488) -#define MMSS_DP_AUDIO_TIMING_RBR_44 (0x0000048C) -#define MMSS_DP_AUDIO_TIMING_HBR_44 (0x00000490) -#define MMSS_DP_AUDIO_TIMING_RBR_48 (0x00000494) -#define MMSS_DP_AUDIO_TIMING_HBR_48 (0x00000498) - -#define MMSS_DP_PSR_CRC_RG (0x00000554) -#define MMSS_DP_PSR_CRC_B (0x00000558) - -#define DP_COMPRESSION_MODE_CTRL (0x00000580) - -#define MMSS_DP_AUDIO_CFG (0x00000600) -#define MMSS_DP_AUDIO_STATUS (0x00000604) -#define MMSS_DP_AUDIO_PKT_CTRL (0x00000608) -#define MMSS_DP_AUDIO_PKT_CTRL2 (0x0000060C) -#define MMSS_DP_AUDIO_ACR_CTRL (0x00000610) -#define MMSS_DP_AUDIO_CTRL_RESET (0x00000614) - -#define MMSS_DP_SDP_CFG (0x00000628) -#define MMSS_DP_SDP_CFG2 (0x0000062C) -#define MMSS_DP_AUDIO_TIMESTAMP_0 (0x00000630) -#define MMSS_DP_AUDIO_TIMESTAMP_1 (0x00000634) - -#define MMSS_DP_AUDIO_STREAM_0 (0x00000640) -#define MMSS_DP_AUDIO_STREAM_1 (0x00000644) - -#define MMSS_DP_EXTENSION_0 (0x00000650) -#define MMSS_DP_EXTENSION_1 (0x00000654) -#define MMSS_DP_EXTENSION_2 (0x00000658) -#define MMSS_DP_EXTENSION_3 (0x0000065C) -#define MMSS_DP_EXTENSION_4 (0x00000660) -#define MMSS_DP_EXTENSION_5 (0x00000664) -#define MMSS_DP_EXTENSION_6 (0x00000668) -#define MMSS_DP_EXTENSION_7 (0x0000066C) -#define MMSS_DP_EXTENSION_8 (0x00000670) -#define MMSS_DP_EXTENSION_9 (0x00000674) -#define MMSS_DP_AUDIO_COPYMANAGEMENT_0 (0x00000678) -#define MMSS_DP_AUDIO_COPYMANAGEMENT_1 (0x0000067C) -#define MMSS_DP_AUDIO_COPYMANAGEMENT_2 (0x00000680) -#define MMSS_DP_AUDIO_COPYMANAGEMENT_3 (0x00000684) -#define MMSS_DP_AUDIO_COPYMANAGEMENT_4 (0x00000688) -#define MMSS_DP_AUDIO_COPYMANAGEMENT_5 (0x0000068C) -#define MMSS_DP_AUDIO_ISRC_0 (0x00000690) -#define MMSS_DP_AUDIO_ISRC_1 (0x00000694) -#define MMSS_DP_AUDIO_ISRC_2 (0x00000698) -#define MMSS_DP_AUDIO_ISRC_3 (0x0000069C) -#define MMSS_DP_AUDIO_ISRC_4 (0x000006A0) -#define MMSS_DP_AUDIO_ISRC_5 (0x000006A4) -#define MMSS_DP_AUDIO_INFOFRAME_0 (0x000006A8) -#define MMSS_DP_AUDIO_INFOFRAME_1 (0x000006AC) -#define MMSS_DP_AUDIO_INFOFRAME_2 (0x000006B0) - -#define MMSS_DP_GENERIC0_0 (0x00000700) -#define MMSS_DP_GENERIC0_1 (0x00000704) -#define MMSS_DP_GENERIC0_2 (0x00000708) -#define MMSS_DP_GENERIC0_3 (0x0000070C) -#define MMSS_DP_GENERIC0_4 (0x00000710) -#define MMSS_DP_GENERIC0_5 (0x00000714) -#define MMSS_DP_GENERIC0_6 (0x00000718) -#define MMSS_DP_GENERIC0_7 (0x0000071C) -#define MMSS_DP_GENERIC0_8 (0x00000720) -#define MMSS_DP_GENERIC0_9 (0x00000724) -#define MMSS_DP_GENERIC1_0 (0x00000728) -#define MMSS_DP_GENERIC1_1 (0x0000072C) -#define MMSS_DP_GENERIC1_2 (0x00000730) -#define MMSS_DP_GENERIC1_3 (0x00000734) -#define MMSS_DP_GENERIC1_4 (0x00000738) -#define MMSS_DP_GENERIC1_5 (0x0000073C) -#define MMSS_DP_GENERIC1_6 (0x00000740) -#define MMSS_DP_GENERIC1_7 (0x00000744) -#define MMSS_DP_GENERIC1_8 (0x00000748) -#define MMSS_DP_GENERIC1_9 (0x0000074C) - -#define MMSS_DP_VSCEXT_0 (0x000006D0) -#define MMSS_DP_VSCEXT_1 (0x000006D4) -#define MMSS_DP_VSCEXT_2 (0x000006D8) -#define MMSS_DP_VSCEXT_3 (0x000006DC) -#define MMSS_DP_VSCEXT_4 (0x000006E0) -#define MMSS_DP_VSCEXT_5 (0x000006E4) -#define MMSS_DP_VSCEXT_6 (0x000006E8) -#define MMSS_DP_VSCEXT_7 (0x000006EC) -#define MMSS_DP_VSCEXT_8 (0x000006F0) -#define MMSS_DP_VSCEXT_9 (0x000006F4) - -#define MMSS_DP_TIMING_ENGINE_EN (0x00000A10) -#define MMSS_DP_ASYNC_FIFO_CONFIG (0x00000A88) - -/*DP PHY Register offsets */ -#define DP_PHY_REVISION_ID0 (0x00000000) -#define DP_PHY_REVISION_ID1 (0x00000004) -#define DP_PHY_REVISION_ID2 (0x00000008) -#define DP_PHY_REVISION_ID3 (0x0000000C) - -#define DP_PHY_CFG (0x00000010) -#define DP_PHY_PD_CTL (0x00000018) -#define DP_PHY_MODE (0x0000001C) - -#define DP_PHY_AUX_CFG0 (0x00000020) -#define DP_PHY_AUX_CFG1 (0x00000024) -#define DP_PHY_AUX_CFG2 (0x00000028) -#define DP_PHY_AUX_CFG3 (0x0000002C) -#define DP_PHY_AUX_CFG4 (0x00000030) -#define DP_PHY_AUX_CFG5 (0x00000034) -#define DP_PHY_AUX_CFG6 (0x00000038) -#define DP_PHY_AUX_CFG7 (0x0000003C) -#define DP_PHY_AUX_CFG8 (0x00000040) -#define DP_PHY_AUX_CFG9 (0x00000044) -#define DP_PHY_AUX_INTERRUPT_MASK (0x00000048) -#define DP_PHY_AUX_INTERRUPT_CLEAR (0x0000004C) - -#define DP_PHY_SPARE0 (0x00AC) - -#define TXn_TX_EMP_POST1_LVL (0x000C) -#define TXn_TX_DRV_LVL (0x001C) - -#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN (0x004) - -/* DP MMSS_CC registers */ -#define MMSS_DP_LINK_CMD_RCGR (0x0138) -#define MMSS_DP_LINK_CFG_RCGR (0x013C) -#define MMSS_DP_PIXEL_M (0x0174) -#define MMSS_DP_PIXEL_N (0x0178) - -/* DP HDCP 1.3 registers */ -#define DP_HDCP_CTRL (0x0A0) -#define DP_HDCP_STATUS (0x0A4) -#define DP_HDCP_SW_UPPER_AKSV (0x298) -#define DP_HDCP_SW_LOWER_AKSV (0x29C) -#define DP_HDCP_ENTROPY_CTRL0 (0x750) -#define DP_HDCP_ENTROPY_CTRL1 (0x75C) -#define DP_HDCP_SHA_STATUS (0x0C8) -#define DP_HDCP_RCVPORT_DATA2_0 (0x0B0) -#define DP_HDCP_RCVPORT_DATA3 (0x2A4) -#define DP_HDCP_RCVPORT_DATA4 (0x2A8) -#define DP_HDCP_RCVPORT_DATA5 (0x0C0) -#define DP_HDCP_RCVPORT_DATA6 (0x0C4) - -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_CTRL (0x024) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_SHA_DATA (0x028) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA0 (0x004) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA1 (0x008) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA7 (0x00C) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA8 (0x010) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA9 (0x014) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA10 (0x018) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA11 (0x01C) -#define HDCP_SEC_DP_TZ_HV_HLOS_HDCP_RCVPORT_DATA12 (0x020) - -/* USB3 DP COM registers */ -#define USB3_DP_COM_RESET_OVRD_CTRL (0x1C) -#define USB3_DP_COM_PHY_MODE_CTRL (0x00) -#define USB3_DP_COM_SW_RESET (0x04) -#define USB3_DP_COM_TYPEC_CTRL (0x10) -#define USB3_DP_COM_SWI_CTRL (0x0c) -#define USB3_DP_COM_POWER_DOWN_CTRL (0x08) - - - -#endif /* _DP_REG_H_ */ diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c deleted file mode 100644 index 6f0e380..0000000 --- a/drivers/gpu/drm/msm/dp/dp_usbpd.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#define pr_fmt(fmt) "[drm-dp] %s: " fmt, __func__ - -#include <linux/slab.h> -#include <linux/device.h> - -#include "dp_usbpd.h" - -/* DP specific VDM commands */ -#define DP_USBPD_VDM_STATUS 0x10 -#define DP_USBPD_VDM_CONFIGURE 0x11 - -/* USBPD-TypeC specific Macros */ -#define VDM_VERSION 0x0 -#define USB_C_DP_SID 0xFF01 - -enum dp_usbpd_pin_assignment { - DP_USBPD_PIN_A, - DP_USBPD_PIN_B, - DP_USBPD_PIN_C, - DP_USBPD_PIN_D, - DP_USBPD_PIN_E, - DP_USBPD_PIN_F, - DP_USBPD_PIN_MAX, -}; - -enum dp_usbpd_events { - DP_USBPD_EVT_DISCOVER, - DP_USBPD_EVT_ENTER, - DP_USBPD_EVT_STATUS, - DP_USBPD_EVT_CONFIGURE, - DP_USBPD_EVT_CC_PIN_POLARITY, - DP_USBPD_EVT_EXIT, - DP_USBPD_EVT_ATTENTION, -}; - -enum dp_usbpd_alt_mode { - DP_USBPD_ALT_MODE_NONE = 0, - DP_USBPD_ALT_MODE_INIT = BIT(0), - DP_USBPD_ALT_MODE_DISCOVER = BIT(1), - DP_USBPD_ALT_MODE_ENTER = BIT(2), - DP_USBPD_ALT_MODE_STATUS = BIT(3), - DP_USBPD_ALT_MODE_CONFIGURE = BIT(4), -}; - -struct dp_usbpd_capabilities { - enum dp_usbpd_port port; - bool receptacle_state; - u8 ulink_pin_config; - u8 dlink_pin_config; -}; - -struct dp_usbpd_private { - u32 vdo; - struct device *dev; - struct usbpd *pd; - struct usbpd_svid_handler svid_handler; - struct dp_usbpd_cb *dp_cb; - struct dp_usbpd_capabilities cap; - struct dp_usbpd dp_usbpd; - enum dp_usbpd_alt_mode alt_mode; - u32 dp_usbpd_config; -}; - -static const char *dp_usbpd_pin_name(u8 pin) -{ - switch (pin) { - case DP_USBPD_PIN_A: return "DP_USBPD_PIN_ASSIGNMENT_A"; - case DP_USBPD_PIN_B: return "DP_USBPD_PIN_ASSIGNMENT_B"; - case DP_USBPD_PIN_C: return "DP_USBPD_PIN_ASSIGNMENT_C"; - case DP_USBPD_PIN_D: return "DP_USBPD_PIN_ASSIGNMENT_D"; - case DP_USBPD_PIN_E: return "DP_USBPD_PIN_ASSIGNMENT_E"; - case DP_USBPD_PIN_F: return "DP_USBPD_PIN_ASSIGNMENT_F"; - default: return "UNKNOWN"; - } -} - -static const char *dp_usbpd_port_name(enum dp_usbpd_port port) -{ - switch (port) { - case DP_USBPD_PORT_NONE: return "DP_USBPD_PORT_NONE"; - case DP_USBPD_PORT_UFP_D: return "DP_USBPD_PORT_UFP_D"; - case DP_USBPD_PORT_DFP_D: return "DP_USBPD_PORT_DFP_D"; - case DP_USBPD_PORT_D_UFP_D: return "DP_USBPD_PORT_D_UFP_D"; - default: return "DP_USBPD_PORT_NONE"; - } -} - -static const char *dp_usbpd_cmd_name(u8 cmd) -{ - switch (cmd) { - case USBPD_SVDM_DISCOVER_MODES: return "USBPD_SVDM_DISCOVER_MODES"; - case USBPD_SVDM_ENTER_MODE: return "USBPD_SVDM_ENTER_MODE"; - case USBPD_SVDM_ATTENTION: return "USBPD_SVDM_ATTENTION"; - case DP_USBPD_VDM_STATUS: return "DP_USBPD_VDM_STATUS"; - case DP_USBPD_VDM_CONFIGURE: return "DP_USBPD_VDM_CONFIGURE"; - default: return "DP_USBPD_VDM_ERROR"; - } -} - -static void dp_usbpd_init_port(enum dp_usbpd_port *port, u32 in_port) -{ - switch (in_port) { - case 0: - *port = DP_USBPD_PORT_NONE; - break; - case 1: - *port = DP_USBPD_PORT_UFP_D; - break; - case 2: - *port = DP_USBPD_PORT_DFP_D; - break; - case 3: - *port = DP_USBPD_PORT_D_UFP_D; - break; - default: - *port = DP_USBPD_PORT_NONE; - } - pr_debug("port:%s\n", dp_usbpd_port_name(*port)); -} - -static void dp_usbpd_get_capabilities(struct dp_usbpd_private *pd) -{ - struct dp_usbpd_capabilities *cap = &pd->cap; - u32 buf = pd->vdo; - int port = buf & 0x3; - - cap->receptacle_state = (buf & BIT(6)) ? true : false; - cap->dlink_pin_config = (buf >> 8) & 0xff; - cap->ulink_pin_config = (buf >> 16) & 0xff; - - dp_usbpd_init_port(&cap->port, port); -} - -static void dp_usbpd_get_status(struct dp_usbpd_private *pd) -{ - struct dp_usbpd *status = &pd->dp_usbpd; - u32 buf = pd->vdo; - int port = buf & 0x3; - - status->low_pow_st = (buf & BIT(2)) ? true : false; - status->adaptor_dp_en = (buf & BIT(3)) ? true : false; - status->multi_func = (buf & BIT(4)) ? true : false; - status->usb_config_req = (buf & BIT(5)) ? true : false; - status->exit_dp_mode = (buf & BIT(6)) ? true : false; - status->hpd_high = (buf & BIT(7)) ? true : false; - status->hpd_irq = (buf & BIT(8)) ? true : false; - - pr_debug("low_pow_st = %d, adaptor_dp_en = %d, multi_func = %d\n", - status->low_pow_st, status->adaptor_dp_en, - status->multi_func); - pr_debug("usb_config_req = %d, exit_dp_mode = %d, hpd_high =%d\n", - status->usb_config_req, - status->exit_dp_mode, status->hpd_high); - pr_debug("hpd_irq = %d\n", status->hpd_irq); - - dp_usbpd_init_port(&status->port, port); -} - -static u32 dp_usbpd_gen_config_pkt(struct dp_usbpd_private *pd) -{ - u8 pin_cfg, pin; - u32 config = 0; - const u32 ufp_d_config = 0x2, dp_ver = 0x1; - - if (pd->cap.receptacle_state) - pin_cfg = pd->cap.ulink_pin_config; - else - pin_cfg = pd->cap.dlink_pin_config; - - for (pin = DP_USBPD_PIN_A; pin < DP_USBPD_PIN_MAX; pin++) { - if (pin_cfg & BIT(pin)) { - if (pd->dp_usbpd.multi_func) { - if (pin == DP_USBPD_PIN_D) - break; - } else { - break; - } - } - } - - if (pin == DP_USBPD_PIN_MAX) - pin = DP_USBPD_PIN_C; - - pr_debug("pin assignment: %s\n", dp_usbpd_pin_name(pin)); - - config |= BIT(pin) << 8; - - config |= (dp_ver << 2); - config |= ufp_d_config; - - pr_debug("config = 0x%x\n", config); - return config; -} - -static void dp_usbpd_send_event(struct dp_usbpd_private *pd, - enum dp_usbpd_events event) -{ - u32 config; - - switch (event) { - case DP_USBPD_EVT_DISCOVER: - usbpd_send_svdm(pd->pd, USB_C_DP_SID, - USBPD_SVDM_DISCOVER_MODES, - SVDM_CMD_TYPE_INITIATOR, 0x0, 0x0, 0x0); - break; - case DP_USBPD_EVT_ENTER: - usbpd_send_svdm(pd->pd, USB_C_DP_SID, - USBPD_SVDM_ENTER_MODE, - SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); - break; - case DP_USBPD_EVT_EXIT: - usbpd_send_svdm(pd->pd, USB_C_DP_SID, - USBPD_SVDM_EXIT_MODE, - SVDM_CMD_TYPE_INITIATOR, 0x1, 0x0, 0x0); - break; - case DP_USBPD_EVT_STATUS: - config = 0x1; /* DFP_D connected */ - usbpd_send_svdm(pd->pd, USB_C_DP_SID, DP_USBPD_VDM_STATUS, - SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); - break; - case DP_USBPD_EVT_CONFIGURE: - config = dp_usbpd_gen_config_pkt(pd); - usbpd_send_svdm(pd->pd, USB_C_DP_SID, DP_USBPD_VDM_CONFIGURE, - SVDM_CMD_TYPE_INITIATOR, 0x1, &config, 0x1); - break; - default: - pr_err("unknown event:%d\n", event); - } -} - -static void dp_usbpd_connect_cb(struct usbpd_svid_handler *hdlr) -{ - struct dp_usbpd_private *pd; - - pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); - if (!pd) { - pr_err("get_usbpd phandle failed\n"); - return; - } - - pr_debug("\n"); - dp_usbpd_send_event(pd, DP_USBPD_EVT_DISCOVER); -} - -static void dp_usbpd_disconnect_cb(struct usbpd_svid_handler *hdlr) -{ - struct dp_usbpd_private *pd; - - pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); - if (!pd) { - pr_err("get_usbpd phandle failed\n"); - return; - } - - pd->alt_mode = DP_USBPD_ALT_MODE_NONE; - pd->dp_usbpd.alt_mode_cfg_done = false; - pr_debug("\n"); - - if (pd->dp_cb && pd->dp_cb->disconnect) - pd->dp_cb->disconnect(pd->dev); -} - -static int dp_usbpd_validate_callback(u8 cmd, - enum usbpd_svdm_cmd_type cmd_type, int num_vdos) -{ - int ret = 0; - - if (cmd_type == SVDM_CMD_TYPE_RESP_NAK) { - pr_err("error: NACK\n"); - ret = -EINVAL; - goto end; - } - - if (cmd_type == SVDM_CMD_TYPE_RESP_BUSY) { - pr_err("error: BUSY\n"); - ret = -EBUSY; - goto end; - } - - if (cmd == USBPD_SVDM_ATTENTION) { - if (cmd_type != SVDM_CMD_TYPE_INITIATOR) { - pr_err("error: invalid cmd type for attention\n"); - ret = -EINVAL; - goto end; - } - - if (!num_vdos) { - pr_err("error: no vdo provided\n"); - ret = -EINVAL; - goto end; - } - } else { - if (cmd_type != SVDM_CMD_TYPE_RESP_ACK) { - pr_err("error: invalid cmd type\n"); - ret = -EINVAL; - } - } -end: - return ret; -} - -static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd, - enum usbpd_svdm_cmd_type cmd_type, - const u32 *vdos, int num_vdos) -{ - struct dp_usbpd_private *pd; - - pd = container_of(hdlr, struct dp_usbpd_private, svid_handler); - - pr_debug("callback -> cmd: %s, *vdos = 0x%x, num_vdos = %d\n", - dp_usbpd_cmd_name(cmd), *vdos, num_vdos); - - if (dp_usbpd_validate_callback(cmd, cmd_type, num_vdos)) { - pr_debug("invalid callback received\n"); - return; - } - - switch (cmd) { - case USBPD_SVDM_DISCOVER_MODES: - pd->vdo = *vdos; - dp_usbpd_get_capabilities(pd); - - pd->alt_mode |= DP_USBPD_ALT_MODE_DISCOVER; - - if (pd->cap.port & BIT(0)) - dp_usbpd_send_event(pd, DP_USBPD_EVT_ENTER); - break; - case USBPD_SVDM_ENTER_MODE: - pd->alt_mode |= DP_USBPD_ALT_MODE_ENTER; - - dp_usbpd_send_event(pd, DP_USBPD_EVT_STATUS); - break; - case USBPD_SVDM_ATTENTION: - if (pd->dp_usbpd.forced_disconnect) - break; - - pd->vdo = *vdos; - dp_usbpd_get_status(pd); - - if (pd->dp_cb && pd->dp_cb->attention) - pd->dp_cb->attention(pd->dev); - - if (!pd->dp_usbpd.alt_mode_cfg_done) - dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE); - break; - case DP_USBPD_VDM_STATUS: - pd->vdo = *vdos; - dp_usbpd_get_status(pd); - - if (!(pd->alt_mode & DP_USBPD_ALT_MODE_CONFIGURE)) { - pd->alt_mode |= DP_USBPD_ALT_MODE_STATUS; - - if (pd->dp_usbpd.port & BIT(1)) - dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE); - } - break; - case DP_USBPD_VDM_CONFIGURE: - pd->alt_mode |= DP_USBPD_ALT_MODE_CONFIGURE; - pd->dp_usbpd.alt_mode_cfg_done = true; - dp_usbpd_get_status(pd); - - pd->dp_usbpd.orientation = usbpd_get_plug_orientation(pd->pd); - - /* - * By default, USB reserves two lanes for Super Speed. - * Which means DP has remaining two lanes to operate on. - * If multi-function is not supported, request USB to - * release the Super Speed lanes so that DP can use - * all four lanes in case DPCD indicates support for - * four lanes. - */ - if (!pd->dp_usbpd.multi_func) - pd->svid_handler.request_usb_ss_lane(pd->pd, - &pd->svid_handler); - - if (pd->dp_cb && pd->dp_cb->configure) - pd->dp_cb->configure(pd->dev); - break; - default: - pr_err("unknown cmd: %d\n", cmd); - break; - } -} - -static int dp_usbpd_connect(struct dp_usbpd *dp_usbpd, bool hpd) -{ - int rc = 0; - struct dp_usbpd_private *pd; - - if (!dp_usbpd) { - pr_err("invalid input\n"); - rc = -EINVAL; - goto error; - } - - pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); - - dp_usbpd->hpd_high = hpd; - dp_usbpd->forced_disconnect = !hpd; - - if (hpd) - pd->dp_cb->configure(pd->dev); - else - pd->dp_cb->disconnect(pd->dev); - -error: - return rc; -} - -struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb) -{ - int rc = 0; - const char *pd_phandle = "qcom,dp-usbpd-detection"; - struct usbpd *pd = NULL; - struct dp_usbpd_private *usbpd; - struct dp_usbpd *dp_usbpd; - struct usbpd_svid_handler svid_handler = { - .svid = USB_C_DP_SID, - .vdm_received = NULL, - .connect = &dp_usbpd_connect_cb, - .svdm_received = &dp_usbpd_response_cb, - .disconnect = &dp_usbpd_disconnect_cb, - }; - - if (!cb) { - pr_err("invalid cb data\n"); - rc = -EINVAL; - goto error; - } - - pd = devm_usbpd_get_by_phandle(dev, pd_phandle); - if (IS_ERR(pd)) { - pr_err("usbpd phandle failed (%ld)\n", PTR_ERR(pd)); - rc = PTR_ERR(pd); - goto error; - } - - usbpd = devm_kzalloc(dev, sizeof(*usbpd), GFP_KERNEL); - if (!usbpd) { - rc = -ENOMEM; - goto error; - } - - usbpd->dev = dev; - usbpd->pd = pd; - usbpd->svid_handler = svid_handler; - usbpd->dp_cb = cb; - - rc = usbpd_register_svid(pd, &usbpd->svid_handler); - if (rc) { - pr_err("pd registration failed\n"); - rc = -ENODEV; - devm_kfree(dev, usbpd); - goto error; - } - - dp_usbpd = &usbpd->dp_usbpd; - dp_usbpd->connect = dp_usbpd_connect; - - return dp_usbpd; -error: - return ERR_PTR(rc); -} - -void dp_usbpd_put(struct dp_usbpd *dp_usbpd) -{ - struct dp_usbpd_private *usbpd; - - if (!dp_usbpd) - return; - - usbpd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd); - - usbpd_unregister_svid(usbpd->pd, &usbpd->svid_handler); - - devm_kfree(usbpd->dev, usbpd); -} diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h deleted file mode 100644 index 94953b3..0000000 --- a/drivers/gpu/drm/msm/dp/dp_usbpd.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DP_USBPD_H_ -#define _DP_USBPD_H_ - -#include <linux/usb/usbpd.h> - -#include <linux/types.h> -#include <linux/device.h> - -/** - * enum dp_usbpd_port - usb/dp port type - * @DP_USBPD_PORT_NONE: port not configured - * @DP_USBPD_PORT_UFP_D: Upstream Facing Port - DisplayPort - * @DP_USBPD_PORT_DFP_D: Downstream Facing Port - DisplayPort - * @DP_USBPD_PORT_D_UFP_D: Both UFP & DFP - DisplayPort - */ - -enum dp_usbpd_port { - DP_USBPD_PORT_NONE, - DP_USBPD_PORT_UFP_D, - DP_USBPD_PORT_DFP_D, - DP_USBPD_PORT_D_UFP_D, -}; - -/** - * struct dp_usbpd - DisplayPort status - * - * @port: port configured - * orientation: plug orientation configuration - * @low_pow_st: low power state - * @adaptor_dp_en: adaptor functionality enabled - * @multi_func: multi-function preferred - * @usb_config_req: request to switch to usb - * @exit_dp_mode: request exit from displayport mode - * @hpd_high: Hot Plug Detect signal is high. - * @hpd_irq: Change in the status since last message - * @alt_mode_cfg_done: bool to specify alt mode status - * @debug_en: bool to specify debug mode - * @connect: simulate disconnect or connect for debug mode - */ -struct dp_usbpd { - enum dp_usbpd_port port; - enum plug_orientation orientation; - bool low_pow_st; - bool adaptor_dp_en; - bool multi_func; - bool usb_config_req; - bool exit_dp_mode; - bool hpd_high; - bool hpd_irq; - bool alt_mode_cfg_done; - bool debug_en; - bool forced_disconnect; - - int (*connect)(struct dp_usbpd *dp_usbpd, bool hpd); -}; - -/** - * struct dp_usbpd_cb - callback functions provided by the client - * - * @configure: called by usbpd module when PD communication has - * been completed and the usb peripheral has been configured on - * dp mode. - * @disconnect: notify the cable disconnect issued by usb. - * @attention: notify any attention message issued by usb. - */ -struct dp_usbpd_cb { - int (*configure)(struct device *dev); - int (*disconnect)(struct device *dev); - int (*attention)(struct device *dev); -}; - -/** - * dp_usbpd_get() - setup usbpd module - * - * @dev: device instance of the caller - * @cb: struct containing callback function pointers. - * - * This function allows the client to initialize the usbpd - * module. The module will communicate with usb driver and - * handles the power delivery (PD) communication with the - * sink/usb device. This module will notify the client using - * the callback functions about the connection and status. - */ -struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb); - -void dp_usbpd_put(struct dp_usbpd *pd); -#endif /* _DP_USBPD_H_ */ diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index b30120e..84a125d 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -335,7 +335,6 @@ # define DP_LINK_BW_1_62 0x06 # define DP_LINK_BW_2_7 0x0a # define DP_LINK_BW_5_4 0x14 /* 1.2 */ -# define DP_LINK_BW_8_1 0x1e #define DP_LANE_COUNT_SET 0x101 # define DP_LANE_COUNT_MASK 0x0f @@ -520,8 +519,6 @@ # define DP_TEST_LINK_EDID_READ (1 << 2) # define DP_TEST_LINK_PHY_TEST_PATTERN (1 << 3) /* DPCD >= 1.1 */ # define DP_TEST_LINK_FAUX_PATTERN (1 << 4) /* DPCD >= 1.2 */ -# define DP_TEST_LINK_AUDIO_PATTERN (1 << 5) -# define DP_TEST_LINK_AUDIO_DISABLED_VIDEO (1 << 6) #define DP_TEST_LINK_RATE 0x219 # define DP_LINK_RATE_162 (0x6) @@ -610,13 +607,6 @@ #define DP_TEST_80BIT_CUSTOM_PATTERN_71_64 0x258 #define DP_TEST_80BIT_CUSTOM_PATTERN_79_72 0x259 -#define DP_TEST_PHY_PATTERN_NONE 0x0 -#define DP_TEST_PHY_PATTERN_D10_2_NO_SCRAMBLING 0x1 -#define DP_TEST_PHY_PATTERN_SYMBOL_ERR_MEASUREMENT_CNT 0x2 -#define DP_TEST_PHY_PATTERN_PRBS7 0x3 -#define DP_TEST_PHY_PATTERN_80_BIT_CUSTOM_PATTERN 0x4 -#define DP_TEST_PHY_PATTERN_HBR2_CTS_EYE_PATTERN 0x5 - #define DP_TEST_RESPONSE 0x260 # define DP_TEST_ACK (1 << 0) # define DP_TEST_NAK (1 << 1) @@ -627,19 +617,6 @@ #define DP_TEST_SINK 0x270 # define DP_TEST_SINK_START (1 << 0) -#define DP_TEST_AUDIO_MODE 0x271 - -#define DP_TEST_AUDIO_PATTERN_TYPE 0x272 - -#define DP_TEST_AUDIO_PERIOD_CH1 0x273 -#define DP_TEST_AUDIO_PERIOD_CH2 0x274 -#define DP_TEST_AUDIO_PERIOD_CH3 0x275 -#define DP_TEST_AUDIO_PERIOD_CH4 0x276 -#define DP_TEST_AUDIO_PERIOD_CH5 0x277 -#define DP_TEST_AUDIO_PERIOD_CH6 0x278 -#define DP_TEST_AUDIO_PERIOD_CH7 0x279 -#define DP_TEST_AUDIO_PERIOD_CH8 0x27A - #define DP_PAYLOAD_TABLE_UPDATE_STATUS 0x2c0 /* 1.2 MST */ # define DP_PAYLOAD_TABLE_UPDATED (1 << 0) # define DP_PAYLOAD_ACT_HANDLED (1 << 1) -- The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum, a Linux Foundation Collaborative Project -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html