From 9ec9267905e8e712eba27c106c96e78c6da3e56f Mon Sep 17 00:00:00 2001 From: Chandan Uddaraju Date: Wed, 17 Aug 2016 11:52:41 -0700 Subject: [PATCH 1/3] mdss: display-port: fix Display-port disable sequence Fix the OFF path for display-port driver when cable is disconnected. Check for link clock status before accessing any of the mainlink registers. Use common mutex for DP_ON and DP_OFF sequence. Remove the resource vote when PLL is diabled. Change-Id: I9b81f79043b4ea7355b99ba9d8347d79bed10153 Signed-off-by: Chandan Uddaraju --- .../clk/msm/mdss/mdss-dp-pll-cobalt-util.c | 2 + drivers/video/fbdev/msm/mdss_dp.c | 49 +++++++++---------- drivers/video/fbdev/msm/mdss_dp.h | 2 +- drivers/video/fbdev/msm/mdss_dp_aux.c | 12 +---- 4 files changed, 28 insertions(+), 37 deletions(-) diff --git a/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c b/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c index 74032aba22bc..123a5ae09fa8 100644 --- a/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c +++ b/drivers/clk/msm/mdss/mdss-dp-pll-cobalt-util.c @@ -583,8 +583,10 @@ int dp_vco_prepare(struct clk *c) mdss_pll_resource_enable(dp_pll_res, false); pr_err("ndx=%d failed to enable dsi pll\n", dp_pll_res->index); + goto error; } + mdss_pll_resource_enable(dp_pll_res, false); error: return rc; } diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index f7261d4e3fa4..140836f9e89e 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -895,7 +895,7 @@ int mdss_dp_on(struct mdss_panel_data *pdata) panel_data); /* wait until link training is completed */ - mutex_lock(&dp_drv->host_mutex); + mutex_lock(&dp_drv->train_mutex); pr_debug("Enter++ cont_splash=%d\n", dp_drv->cont_splash); /* Default lane mapping */ @@ -908,7 +908,7 @@ int mdss_dp_on(struct mdss_panel_data *pdata) ret = mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, true); if (ret) { pr_err("Unabled to start core clocks\n"); - return ret; + goto exit; } mdss_dp_hpd_configure(&dp_drv->ctrl_io, true); @@ -941,7 +941,8 @@ int mdss_dp_on(struct mdss_panel_data *pdata) dp_drv->link_rate, dp_drv->dpcd.max_link_rate); if (!dp_drv->link_rate) { pr_err("Unable to configure required link rate\n"); - return -EINVAL; + ret = -EINVAL; + goto exit; } pr_debug("link_rate = 0x%x\n", dp_drv->link_rate); @@ -955,9 +956,8 @@ int mdss_dp_on(struct mdss_panel_data *pdata) ret = mdss_dp_clk_ctrl(dp_drv, DP_CTRL_PM, true); if (ret) { - mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false); pr_err("Unabled to start link clocks\n"); - return ret; + goto exit; } mdss_dp_mainlink_reset(&dp_drv->ctrl_io); @@ -985,17 +985,16 @@ int mdss_dp_on(struct mdss_panel_data *pdata) pr_debug("mainlink ready\n"); dp_drv->power_on = true; - - mutex_unlock(&dp_drv->host_mutex); pr_debug("End-\n"); +exit: + mutex_unlock(&dp_drv->train_mutex); return ret; } int mdss_dp_off(struct mdss_panel_data *pdata) { struct mdss_dp_drv_pdata *dp_drv = NULL; - int ret = 0; dp_drv = container_of(pdata, struct mdss_dp_drv_pdata, panel_data); @@ -1009,34 +1008,31 @@ int mdss_dp_off(struct mdss_panel_data *pdata) mutex_lock(&dp_drv->train_mutex); reinit_completion(&dp_drv->idle_comp); - mdss_dp_state_ctrl(&dp_drv->ctrl_io, ST_PUSH_IDLE); - - ret = wait_for_completion_timeout(&dp_drv->idle_comp, - msecs_to_jiffies(100)); - if (ret == 0) - pr_err("idle pattern timedout\n"); mdss_dp_state_ctrl(&dp_drv->ctrl_io, 0); - mdss_dp_irq_disable(dp_drv); + if (dp_drv->link_clks_on) + mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false); - mdss_dp_mainlink_reset(&dp_drv->ctrl_io); - mdss_dp_mainlink_ctrl(&dp_drv->ctrl_io, false); + mdss_dp_aux_ctrl(&dp_drv->ctrl_io, false); + + mdss_dp_irq_disable(dp_drv); mdss_dp_config_gpios(dp_drv, false); mdss_dp_pinctrl_set_state(dp_drv, false); - mdss_dp_aux_ctrl(&dp_drv->ctrl_io, false); + /* Make sure DP is disabled before clk disable */ + wmb(); mdss_dp_clk_ctrl(dp_drv, DP_CTRL_PM, false); mdss_dp_clk_ctrl(dp_drv, DP_CORE_PM, false); mdss_dp_regulator_ctrl(dp_drv, false); - - pr_debug("End--: state_ctrl=%x\n", - dp_read(dp_drv->base + DP_STATE_CTRL)); + dp_drv->dp_initialized = false; dp_drv->power_on = false; mutex_unlock(&dp_drv->train_mutex); + pr_debug("DP off done\n"); + return 0; } @@ -1124,6 +1120,10 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) dp_drv = container_of(pdata, struct mdss_dp_drv_pdata, panel_data); + if (dp_drv->dp_initialized) { + pr_err("%s: host init done already\n", __func__); + return 0; + } ret = mdss_dp_regulator_ctrl(dp_drv, true); if (ret) { pr_err("failed to enable regulators\n"); @@ -1170,7 +1170,7 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) } mdss_dp_send_cable_notification(dp_drv, true); - + dp_drv->dp_initialized = true; return ret; edid_error: @@ -1781,8 +1781,8 @@ static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, if (cmd_type == SVDM_CMD_TYPE_INITIATOR) { pr_debug("Attention. cmd_type=%d\n", cmd_type); - if (!dp_drv->alt_mode.current_state - == ENTER_MODE_DONE) { + if (!(dp_drv->alt_mode.current_state + == ENTER_MODE_DONE)) { pr_debug("sending discover_mode\n"); dp_send_events(dp_drv, EV_USBPD_DISCOVER_MODES); break; @@ -1909,7 +1909,6 @@ static int mdss_dp_probe(struct platform_device *pdev) dp_drv->mask1 = EDP_INTR_MASK1; dp_drv->mask2 = EDP_INTR_MASK2; mutex_init(&dp_drv->emutex); - mutex_init(&dp_drv->host_mutex); mutex_init(&dp_drv->pd_msg_mutex); mutex_init(&dp_drv->hdcp_mutex); spin_lock_init(&dp_drv->lock); diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index d36c1e4ffce5..e29440746478 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -337,6 +337,7 @@ struct mdss_dp_drv_pdata { struct usbpd *pd; struct usbpd_svid_handler svid_handler; struct dp_alt_mode alt_mode; + bool dp_initialized; struct mutex emutex; int clk_cnt; @@ -398,7 +399,6 @@ struct mdss_dp_drv_pdata { struct completion video_comp; struct mutex aux_mutex; struct mutex train_mutex; - struct mutex host_mutex; struct mutex pd_msg_mutex; struct mutex hdcp_mutex; bool cable_connected; diff --git a/drivers/video/fbdev/msm/mdss_dp_aux.c b/drivers/video/fbdev/msm/mdss_dp_aux.c index aea342ac90db..fc24bb53a61c 100644 --- a/drivers/video/fbdev/msm/mdss_dp_aux.c +++ b/drivers/video/fbdev/msm/mdss_dp_aux.c @@ -1312,7 +1312,7 @@ static void dp_clear_training_pattern(struct mdss_dp_drv_pdata *ep) usleep_range(usleep_time, usleep_time); } -static int dp_aux_link_train(struct mdss_dp_drv_pdata *dp) +int mdss_dp_link_train(struct mdss_dp_drv_pdata *dp) { int ret = 0; int usleep_time; @@ -1412,16 +1412,6 @@ void mdss_dp_fill_link_cfg(struct mdss_dp_drv_pdata *ep) } -int mdss_dp_link_train(struct mdss_dp_drv_pdata *ep) -{ - int ret; - - mutex_lock(&ep->train_mutex); - ret = dp_aux_link_train(ep); - mutex_unlock(&ep->train_mutex); - return ret; -} - void mdss_dp_aux_init(struct mdss_dp_drv_pdata *ep) { mutex_init(&ep->aux_mutex); From fdae3117e039d120d7453f0eb89cc6cfc6c457c9 Mon Sep 17 00:00:00 2001 From: Tatenda Chipeperekwa Date: Tue, 16 Aug 2016 14:24:18 -0700 Subject: [PATCH 2/3] msm: mdss: use external display as wrapper for operations Use the external display as a wrapper for operations making it necessary for clients to only need a pointer to the external display platform device. The external display will implement the book keeping required to map operations to the correct display interface. CRs-Fixed: 1009284 Change-Id: I1f817e0c720dda0a9b1778f6aad653218ff9be60 Signed-off-by: Tatenda Chipeperekwa --- drivers/video/fbdev/msm/mdss_hdmi_tx.c | 3 +- drivers/video/fbdev/msm/msm_ext_display.c | 129 +++++++++++++++++++++- include/linux/msm_ext_display.h | 1 + 3 files changed, 129 insertions(+), 4 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c index 3e4e2f74a32e..3b4bc8acdd10 100644 --- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c +++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c @@ -1915,6 +1915,7 @@ static int hdmi_tx_init_ext_disp(struct hdmi_tx_ctrl *hdmi_ctrl) hdmi_ctrl->ext_audio_data.type = EXT_DISPLAY_TYPE_HDMI; hdmi_ctrl->ext_audio_data.kobj = hdmi_ctrl->kobj; + hdmi_ctrl->ext_audio_data.pdev = hdmi_ctrl->pdev; hdmi_ctrl->ext_audio_data.codec_ops.audio_info_setup = hdmi_tx_audio_info_setup; hdmi_ctrl->ext_audio_data.codec_ops.get_audio_edid_blk = @@ -2978,7 +2979,7 @@ int msm_hdmi_register_audio_codec(struct platform_device *pdev, if (!hdmi_ctrl || !ops) { DEV_ERR("%s: invalid input\n", __func__); - return -ENODEV; + return -EPROBE_DEFER; } ret = msm_ext_disp_register_audio_codec(hdmi_ctrl->ext_pdev, ops); diff --git a/drivers/video/fbdev/msm/msm_ext_display.c b/drivers/video/fbdev/msm/msm_ext_display.c index a21242870a35..903cab1ac059 100644 --- a/drivers/video/fbdev/msm/msm_ext_display.c +++ b/drivers/video/fbdev/msm/msm_ext_display.c @@ -380,6 +380,88 @@ end: return ret; } +static int msm_ext_disp_get_intf_data_helper(struct platform_device *pdev, + struct msm_ext_disp_init_data **data) +{ + int ret = 0; + struct msm_ext_disp *ext_disp = NULL; + + if (!pdev) { + pr_err("No platform device\n"); + ret = -ENODEV; + goto end; + } + + ext_disp = platform_get_drvdata(pdev); + if (!ext_disp) { + pr_err("No drvdata found\n"); + ret = -ENODEV; + goto end; + } + + mutex_lock(&ext_disp->lock); + + if (ext_disp->current_disp == EXT_DISPLAY_TYPE_MAX) { + ret = -EINVAL; + pr_err("No display connected\n"); + goto error; + } + + ret = msm_ext_disp_get_intf_data(ext_disp, ext_disp->current_disp, + data); + if (ret) + goto error; +error: + mutex_unlock(&ext_disp->lock); +end: + return ret; +} +static int msm_ext_disp_cable_status(struct platform_device *pdev, u32 vote) +{ + int ret = 0; + struct msm_ext_disp_init_data *data = NULL; + + ret = msm_ext_disp_get_intf_data_helper(pdev, &data); + if (ret || !data) + goto end; + + ret = data->codec_ops.cable_status(data->pdev, vote); + +end: + return ret; +} + +static int msm_ext_disp_get_audio_edid_blk(struct platform_device *pdev, + struct msm_ext_disp_audio_edid_blk *blk) +{ + int ret = 0; + struct msm_ext_disp_init_data *data = NULL; + + ret = msm_ext_disp_get_intf_data_helper(pdev, &data); + if (ret || !data) + goto end; + + ret = data->codec_ops.get_audio_edid_blk(data->pdev, blk); + +end: + return ret; +} + +static int msm_ext_disp_audio_info_setup(struct platform_device *pdev, + struct msm_ext_disp_audio_setup_params *params) +{ + int ret = 0; + struct msm_ext_disp_init_data *data = NULL; + + ret = msm_ext_disp_get_intf_data_helper(pdev, &data); + if (ret || !data) + goto end; + + ret = data->codec_ops.audio_info_setup(data->pdev, params); + +end: + return ret; +} static int msm_ext_disp_get_intf_id(struct platform_device *pdev) { @@ -456,11 +538,11 @@ static int msm_ext_disp_notify(struct platform_device *pdev, if (new_state == EXT_DISPLAY_CABLE_CONNECT && ext_disp->ops) { ext_disp->ops->audio_info_setup = - data->codec_ops.audio_info_setup; + msm_ext_disp_audio_info_setup; ext_disp->ops->get_audio_edid_blk = - data->codec_ops.get_audio_edid_blk; + msm_ext_disp_get_audio_edid_blk; ext_disp->ops->cable_status = - data->codec_ops.cable_status; + msm_ext_disp_cable_status; ext_disp->ops->get_intf_id = msm_ext_disp_get_intf_id; } @@ -590,6 +672,33 @@ end: return ret; } +static int msm_ext_disp_validate_intf(struct msm_ext_disp_init_data *init_data) +{ + if (!init_data) { + pr_err("Invalid init_data\n"); + return -EINVAL; + } + + if (!init_data->pdev) { + pr_err("Invalid display intf pdev\n"); + return -EINVAL; + } + + if (!init_data->kobj) { + pr_err("Invalid display intf kobj\n"); + return -EINVAL; + } + + if (!init_data->codec_ops.get_audio_edid_blk || + !init_data->codec_ops.cable_status || + !init_data->codec_ops.audio_info_setup) { + pr_err("Invalid codec operation pointers\n"); + return -EINVAL; + } + + return 0; +} + int msm_ext_disp_register_intf(struct platform_device *pdev, struct msm_ext_disp_init_data *init_data) { @@ -610,6 +719,10 @@ int msm_ext_disp_register_intf(struct platform_device *pdev, mutex_lock(&ext_disp->lock); + ret = msm_ext_disp_validate_intf(init_data); + if (ret) + goto end; + ret = msm_ext_disp_get_intf_data(ext_disp, init_data->type, &data); if (!ret) { pr_debug("Display (%s) already registered\n", @@ -675,6 +788,14 @@ static int msm_ext_disp_probe(struct platform_device *pdev) if (ret) goto switch_dev_failure; + ret = of_platform_populate(of_node, NULL, NULL, &pdev->dev); + if (ret) { + pr_err("Failed to add child devices. Error = %d\n", ret); + goto child_node_failure; + } else { + pr_debug("%s: Added child devices.\n", __func__); + } + mutex_init(&ext_disp->lock); INIT_LIST_HEAD(&ext_disp->display_list); @@ -682,6 +803,8 @@ static int msm_ext_disp_probe(struct platform_device *pdev) return ret; +child_node_failure: + msm_ext_disp_switch_dev_unregister(ext_disp); switch_dev_failure: devm_kfree(&ext_disp->pdev->dev, ext_disp); end: diff --git a/include/linux/msm_ext_display.h b/include/linux/msm_ext_display.h index 81a95657a719..54c99d9cb245 100644 --- a/include/linux/msm_ext_display.h +++ b/include/linux/msm_ext_display.h @@ -121,6 +121,7 @@ struct msm_ext_disp_init_data { struct kobject *kobj; struct msm_ext_disp_intf_ops intf_ops; struct msm_ext_disp_audio_codec_ops codec_ops; + struct platform_device *pdev; }; /* From 79f9bdf53ba78163716be1dfc8e46ec980bfba58 Mon Sep 17 00:00:00 2001 From: Chandan Uddaraju Date: Wed, 20 Apr 2016 12:13:30 -0700 Subject: [PATCH 3/3] mdss: display-port: add support for audio programming Add support to configure audio baud rate for display port. CRs-Fixed: 1009284 Change-Id: Iab3c9d578cf398f57d3151a5c895c4a09ddb3dd2 Signed-off-by: Chandan Uddaraju Signed-off-by: Tatenda Chipeperekwa --- drivers/video/fbdev/msm/mdss_dp.c | 161 +++++++++++++++++++----- drivers/video/fbdev/msm/mdss_dp.h | 2 + drivers/video/fbdev/msm/mdss_dp_util.c | 167 +++++++++++++++++++++++++ drivers/video/fbdev/msm/mdss_dp_util.h | 73 +++++++++++ 4 files changed, 374 insertions(+), 29 deletions(-) diff --git a/drivers/video/fbdev/msm/mdss_dp.c b/drivers/video/fbdev/msm/mdss_dp.c index 140836f9e89e..c8b415df4bce 100644 --- a/drivers/video/fbdev/msm/mdss_dp.c +++ b/drivers/video/fbdev/msm/mdss_dp.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "mdss.h" #include "mdss_dp.h" @@ -827,6 +828,112 @@ int mdss_dp_wait4train(struct mdss_dp_drv_pdata *dp_drv) return ret; } +static int dp_get_cable_status(struct platform_device *pdev, u32 vote) +{ + struct mdss_dp_drv_pdata *dp_ctrl = platform_get_drvdata(pdev); + u32 hpd; + + if (!dp_ctrl) { + DEV_ERR("%s: invalid input\n", __func__); + return -ENODEV; + } + + mutex_lock(&dp_ctrl->pd_msg_mutex); + hpd = dp_ctrl->cable_connected; + mutex_unlock(&dp_ctrl->pd_msg_mutex); + + return hpd; +} + +static int dp_audio_info_setup(struct platform_device *pdev, + struct msm_ext_disp_audio_setup_params *params) +{ + int rc = 0; + struct mdss_dp_drv_pdata *dp_ctrl = platform_get_drvdata(pdev); + + if (!dp_ctrl || !params) { + DEV_ERR("%s: invalid input\n", __func__); + return -ENODEV; + } + + mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true); + mdss_dp_config_audio_acr_ctrl(&dp_ctrl->ctrl_io, + dp_ctrl->link_rate); + mdss_dp_audio_setup_sdps(&dp_ctrl->ctrl_io); + + return rc; +} /* dp_audio_info_setup */ + +static int dp_get_audio_edid_blk(struct platform_device *pdev, + struct msm_ext_disp_audio_edid_blk *blk) +{ + struct mdss_dp_drv_pdata *dp = platform_get_drvdata(pdev); + int rc = 0; + + if (!dp) { + DEV_ERR("%s: invalid input\n", __func__); + return -ENODEV; + } + + rc = hdmi_edid_get_audio_blk + (dp->panel_data.panel_info.edid_data, blk); + if (rc) + DEV_ERR("%s:edid_get_audio_blk failed\n", __func__); + + return rc; +} /* dp_get_audio_edid_blk */ + +static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp) +{ + int ret = 0; + struct device_node *pd_np; + const char *phandle = "qcom,msm_ext_disp"; + + if (!dp) { + pr_err("%s: invalid input\n", __func__); + ret = -ENODEV; + goto end; + } + + dp->ext_audio_data.type = EXT_DISPLAY_TYPE_DP; + dp->ext_audio_data.kobj = dp->kobj; + dp->ext_audio_data.pdev = dp->pdev; + dp->ext_audio_data.codec_ops.audio_info_setup = + dp_audio_info_setup; + dp->ext_audio_data.codec_ops.get_audio_edid_blk = + dp_get_audio_edid_blk; + dp->ext_audio_data.codec_ops.cable_status = + dp_get_cable_status; + + if (!dp->pdev->dev.of_node) { + pr_err("%s cannot find dp dev.of_node\n", __func__); + ret = -ENODEV; + goto end; + } + + pd_np = of_parse_phandle(dp->pdev->dev.of_node, phandle, 0); + if (!pd_np) { + pr_err("%s cannot find %s dev\n", __func__, phandle); + ret = -ENODEV; + goto end; + } + + dp->ext_pdev = of_find_device_by_node(pd_np); + if (!dp->ext_pdev) { + pr_err("%s cannot find %s pdev\n", __func__, phandle); + ret = -ENODEV; + goto end; + } + + ret = msm_ext_disp_register_intf(dp->ext_pdev, + &dp->ext_audio_data); + if (ret) + pr_err("%s: failed to register disp\n", __func__); + +end: + return ret; +} + #define DEFAULT_VIDEO_RESOLUTION HDMI_VFRMT_640x480p60_4_3 static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic) @@ -1036,42 +1143,26 @@ int mdss_dp_off(struct mdss_panel_data *pdata) return 0; } +static inline void mdss_dp_set_audio_switch_node( + struct mdss_dp_drv_pdata *dp, int val) +{ + if (dp && dp->ext_audio_data.intf_ops.notify) + dp->ext_audio_data.intf_ops.notify(dp->ext_pdev, + val); +} + static void mdss_dp_send_cable_notification( struct mdss_dp_drv_pdata *dp, int val) { - int state = 0; if (!dp) { DEV_ERR("%s: invalid input\n", __func__); return; } - state = dp->sdev.state; - switch_set_state(&dp->sdev, val); - - DEV_INFO("%s: cable state %s %d\n", __func__, - dp->sdev.state == state ? - "is same" : "switched to", - dp->sdev.state); -} - -static int mdss_dp_register_switch_event(struct mdss_dp_drv_pdata *dp) -{ - int rc = -EINVAL; - - if (!dp) { - DEV_ERR("%s: invalid input\n", __func__); - goto end; - } - - dp->sdev.name = "hdmi"; - rc = switch_dev_register(&dp->sdev); - if (rc) { - DEV_ERR("%s: display switch registration failed\n", __func__); - goto end; - } -end: - return rc; + if (dp && dp->ext_audio_data.intf_ops.hpd) + dp->ext_audio_data.intf_ops.hpd(dp->ext_pdev, + dp->ext_audio_data.type, val); } static int mdss_dp_edid_init(struct mdss_panel_data *pdata) @@ -1170,7 +1261,9 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata) } mdss_dp_send_cable_notification(dp_drv, true); + mdss_dp_set_audio_switch_node(dp_drv, true); dp_drv->dp_initialized = true; + return ret; edid_error: @@ -1421,7 +1514,12 @@ static int mdss_dp_event_handler(struct mdss_panel_data *pdata, mdss_dp_sysfs_create(dp, fbi); mdss_dp_edid_init(pdata); mdss_dp_hdcp_init(pdata); - mdss_dp_register_switch_event(dp); + + rc = mdss_dp_init_ext_disp(dp); + if (rc) + pr_err("failed to initialize ext disp data, ret=%d\n", + rc); + break; case MDSS_EVENT_CHECK_PARAMS: rc = mdss_dp_check_params(dp, arg); @@ -1738,6 +1836,7 @@ static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr) dp_drv->cable_connected = false; mutex_unlock(&dp_drv->pd_msg_mutex); mdss_dp_send_cable_notification(dp_drv, false); + mdss_dp_set_audio_switch_node(dp_drv, false); } static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd, @@ -1998,8 +2097,12 @@ static int mdss_dp_probe(struct platform_device *pdev) probe_err: iounmap(dp_drv->ctrl_io.base); iounmap(dp_drv->phy_io.base); - if (dp_drv) + if (dp_drv) { + if (dp_drv->pd) + usbpd_unregister_svid(dp_drv->pd, + &dp_drv->svid_handler); devm_kfree(&pdev->dev, dp_drv); + } return ret; } diff --git a/drivers/video/fbdev/msm/mdss_dp.h b/drivers/video/fbdev/msm/mdss_dp.h index e29440746478..b724aa655424 100644 --- a/drivers/video/fbdev/msm/mdss_dp.h +++ b/drivers/video/fbdev/msm/mdss_dp.h @@ -333,11 +333,13 @@ struct mdss_dp_drv_pdata { int (*on) (struct mdss_panel_data *pdata); int (*off) (struct mdss_panel_data *pdata); struct platform_device *pdev; + struct platform_device *ext_pdev; struct usbpd *pd; struct usbpd_svid_handler svid_handler; struct dp_alt_mode alt_mode; bool dp_initialized; + struct msm_ext_disp_init_data ext_audio_data; struct mutex emutex; int clk_cnt; diff --git a/drivers/video/fbdev/msm/mdss_dp_util.c b/drivers/video/fbdev/msm/mdss_dp_util.c index f7b27d1e56a1..c501ed3bcd9d 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.c +++ b/drivers/video/fbdev/msm/mdss_dp_util.c @@ -18,6 +18,13 @@ #include "mdss_dp_util.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 mdss_hw mdss_dp_hw = { .hw_ndx = MDSS_HW_EDP, .ptr = NULL, @@ -370,3 +377,163 @@ u32 mdss_dp_usbpd_gen_config_pkt(struct mdss_dp_drv_pdata *dp) pr_debug("DP config = 0x%x\n", config); return config; } + +void mdss_dp_config_audio_acr_ctrl(struct dss_io_data *ctrl_io, + char link_rate) +{ + u32 acr_ctrl = 0; + + switch (link_rate) { + case DP_LINK_RATE_162: + acr_ctrl = 0; + break; + case DP_LINK_RATE_270: + acr_ctrl = 1; + break; + case DP_LINK_RATE_540: + acr_ctrl = 2; + break; + default: + pr_debug("Unknown link rate\n"); + acr_ctrl = 1; + break; + } + + writel_relaxed(acr_ctrl, ctrl_io->base + MMSS_DP_AUDIO_ACR_CTRL); +} + +static void mdss_dp_audio_config_parity_settings(struct dss_io_data *ctrl_io) +{ + u32 value = 0; + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_0); + /* Config header and parity byte 1 */ + value |= ((0x2 << HEADER_BYTE_1_BIT) + | (0x13 << PARITY_BYTE_1_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_STREAM_0); + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_1); + /* Config header and parity byte 2 */ + value |= ((0x28 << HEADER_BYTE_2_BIT) + | (0xf5 << PARITY_BYTE_2_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_STREAM_1); + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_STREAM_1); + /* Config header and parity byte 3 */ + value |= ((0x97 << HEADER_BYTE_3_BIT) + | (0xc2 << PARITY_BYTE_3_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_STREAM_1); + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_0); + /* Config header and parity byte 1 */ + value |= ((0x1 << HEADER_BYTE_1_BIT) + | (0x98 << PARITY_BYTE_1_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_0); + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_1); + /* Config header and parity byte 2 */ + value |= ((0x17 << HEADER_BYTE_2_BIT) + | (0x60 << PARITY_BYTE_2_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_TIMESTAMP_1); + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_0); + /* Config header and parity byte 1 */ + value |= ((0x84 << HEADER_BYTE_1_BIT) + | (0x84 << PARITY_BYTE_1_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_0); + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_1); + /* Config header and parity byte 2 */ + value |= ((0xb1 << HEADER_BYTE_2_BIT) + | (0x4e << PARITY_BYTE_2_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_INFOFRAME_1); + + value = readl_relaxed(ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_0); + /* Config header and parity byte 1 */ + value |= ((0x5 << HEADER_BYTE_1_BIT) + | (0xbe << PARITY_BYTE_1_BIT)); + writel_relaxed(value, ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_0); + + value = readl_relaxed(ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_1); + /* Config header and parity byte 2 */ + value |= ((0x0b << HEADER_BYTE_2_BIT) + | (0xc7 << PARITY_BYTE_2_BIT)); + writel_relaxed(value, ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_1); + + value = readl_relaxed(ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_1); + /* Config header and parity byte 3 */ + value |= ((0x1 << HEADER_BYTE_3_BIT) + | (0x98 << PARITY_BYTE_3_BIT)); + writel_relaxed(value, ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_1); + + writel_relaxed(0x22222222, ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_2); + writel_relaxed(0x22222222, ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_3); + writel_relaxed(0x22222222, ctrl_io->base + + MMSS_DP_AUDIO_COPYMANAGEMENT_4); + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_ISRC_0); + /* Config header and parity byte 1 */ + value |= ((0x6 << HEADER_BYTE_1_BIT) + | (0x35 << PARITY_BYTE_1_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_ISRC_0); + + value = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_ISRC_1); + /* Config header and parity byte 2 */ + value |= ((0x0b << HEADER_BYTE_2_BIT) + | (0xc7 << PARITY_BYTE_2_BIT)); + writel_relaxed(value, ctrl_io->base + MMSS_DP_AUDIO_ISRC_1); + + writel_relaxed(0x33333333, ctrl_io->base + MMSS_DP_AUDIO_ISRC_2); + writel_relaxed(0x33333333, ctrl_io->base + MMSS_DP_AUDIO_ISRC_3); + writel_relaxed(0x33333333, ctrl_io->base + MMSS_DP_AUDIO_ISRC_4); + +} + +void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io) +{ + u32 sdp_cfg = 0; + u32 sdp_cfg2 = 0; + + /* 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); + + writel_relaxed(sdp_cfg, ctrl_io->base + MMSS_DP_SDP_CFG); + + sdp_cfg2 = readl_relaxed(ctrl_io->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); + + writel_relaxed(sdp_cfg2, ctrl_io->base + MMSS_DP_SDP_CFG2); + + mdss_dp_audio_config_parity_settings(ctrl_io); +} + +void mdss_dp_audio_enable(struct dss_io_data *ctrl_io, bool enable) +{ + u32 audio_ctrl = readl_relaxed(ctrl_io->base + MMSS_DP_AUDIO_CFG); + + if (enable) + audio_ctrl |= BIT(0); + else + audio_ctrl &= ~BIT(0); + + writel_relaxed(audio_ctrl, ctrl_io->base + MMSS_DP_AUDIO_CFG); +} diff --git a/drivers/video/fbdev/msm/mdss_dp_util.h b/drivers/video/fbdev/msm/mdss_dp_util.h index a2649b8c1611..96664d1f9954 100644 --- a/drivers/video/fbdev/msm/mdss_dp_util.h +++ b/drivers/video/fbdev/msm/mdss_dp_util.h @@ -56,6 +56,75 @@ #define DP_MAINLINK_READY (0x00000440) #define DP_TU (0x0000044C) +#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_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 (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) + /*DP PHY Register offsets */ #define DP_PHY_REVISION_ID0 (0x00000000) #define DP_PHY_REVISION_ID1 (0x00000004) @@ -162,5 +231,9 @@ void mdss_dp_usbpd_ext_dp_status(struct usbpd_dp_status *dp_status); u32 mdss_dp_usbpd_gen_config_pkt(struct mdss_dp_drv_pdata *dp); void mdss_dp_ctrl_lane_mapping(struct dss_io_data *ctrl_io, struct lane_mapping l_map); +void mdss_dp_config_audio_acr_ctrl(struct dss_io_data *ctrl_io, + char link_rate); +void mdss_dp_audio_setup_sdps(struct dss_io_data *ctrl_io); +void mdss_dp_audio_enable(struct dss_io_data *ctrl_io, bool enable); #endif /* __DP_UTIL_H__ */