diff --git a/config/gki_crowdisp.conf b/config/gki_crowdisp.conf index ccae67ab..98c9476d 100644 --- a/config/gki_crowdisp.conf +++ b/config/gki_crowdisp.conf @@ -14,3 +14,5 @@ export CONFIG_DISPLAY_BUILD=m export CONFIG_HDCP_QSEECOM=y export CONFIG_DRM_SDE_VM=y export CONFIG_QCOM_SPEC_SYNC=y +export CONFIG_QCOM_WCD939X_I2C=y +export CONFIG_QCOM_FSA4480_I2C=y diff --git a/config/gki_crowdispconf.h b/config/gki_crowdispconf.h index 25edefc9..e4a44582 100644 --- a/config/gki_crowdispconf.h +++ b/config/gki_crowdispconf.h @@ -20,3 +20,5 @@ #define CONFIG_HDCP_QSEECOM 1 #define CONFIG_DRM_SDE_VM 1 #define CONFIG_QCOM_SPEC_SYNC 1 +#define CONFIG_QCOM_WCD939X_I2C 1 +#define CONFIG_QCOM_FSA4480_I2C 1 diff --git a/config/gki_kalamadisp.conf b/config/gki_kalamadisp.conf index 56465736..5058638b 100644 --- a/config/gki_kalamadisp.conf +++ b/config/gki_kalamadisp.conf @@ -15,3 +15,4 @@ export CONFIG_HDCP_QSEECOM=y export CONFIG_DRM_SDE_VM=y export CONFIG_QTI_HW_FENCE=y export CONFIG_QCOM_SPEC_SYNC=y +export CONFIG_QCOM_FSA4480_I2C=y diff --git a/config/gki_kalamadispconf.h b/config/gki_kalamadispconf.h index 5b5bfbce..f88dec0d 100644 --- a/config/gki_kalamadispconf.h +++ b/config/gki_kalamadispconf.h @@ -23,3 +23,4 @@ #define CONFIG_DRM_SDE_VM 1 #define CONFIG_QTI_HW_FENCE 1 #define CONFIG_QCOM_SPEC_SYNC 1 +#define CONFIG_QCOM_FSA4480_I2C 1 diff --git a/msm/dp/dp_aux.c b/msm/dp/dp_aux.c index aad6f718..efb1ccc4 100644 --- a/msm/dp/dp_aux.c +++ b/msm/dp/dp_aux.c @@ -1,12 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-only /* - * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ -#include #include +#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C) +#include +#endif +#if IS_ENABLED(CONFIG_QCOM_WCD939X_I2C) +#include +#endif + #include "dp_aux.h" #include "dp_hpd.h" #include "dp_debug.h" @@ -755,7 +761,8 @@ static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, mutex_unlock(&aux->mutex); } -static int dp_aux_configure_aux_switch(struct dp_aux *dp_aux, +#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C) +static int dp_aux_configure_fsa_switch(struct dp_aux *dp_aux, bool enable, int orientation) { struct dp_aux_private *aux; @@ -795,15 +802,69 @@ static int dp_aux_configure_aux_switch(struct dp_aux *dp_aux, enable, orientation, event); rc = fsa4480_switch_event(aux->aux_switch_node, event); + if (rc) DP_AUX_ERR(dp_aux, "failed to configure fsa4480 i2c device (%d)\n", rc); end: return rc; } +#endif + +#if IS_ENABLED(CONFIG_QCOM_WCD939X_I2C) +static int dp_aux_configure_wcd_switch(struct dp_aux *dp_aux, + bool enable, int orientation) +{ + struct dp_aux_private *aux; + int rc = 0; + enum wcd_usbss_cable_status status = WCD_USBSS_CABLE_DISCONNECT; + enum wcd_usbss_cable_types event = WCD_USBSS_DP_AUX_CC1; + + if (!dp_aux) { + DP_AUX_ERR(dp_aux, "invalid input\n"); + rc = -EINVAL; + goto end; + } + + aux = container_of(dp_aux, struct dp_aux_private, dp_aux); + + if (!aux->aux_switch_node) { + DP_AUX_DEBUG(dp_aux, "undefined wcd939x switch handle\n"); + rc = -EINVAL; + goto end; + } + + if (enable) { + status = WCD_USBSS_CABLE_CONNECT; + + switch (orientation) { + case ORIENTATION_CC1: + event = WCD_USBSS_DP_AUX_CC1; + break; + case ORIENTATION_CC2: + event = WCD_USBSS_DP_AUX_CC2; + break; + default: + DP_AUX_ERR(dp_aux, "invalid orientation\n"); + rc = -EINVAL; + goto end; + } + } + + DP_AUX_DEBUG(dp_aux, "enable=%d, orientation=%d, event=%d\n", + enable, orientation, event); + + rc = wcd_usbss_switch_update(event, status); + + if (rc) + DP_AUX_ERR(dp_aux, "failed to configure wcd939x i2c device (%d)\n", rc); +end: + return rc; +} +#endif struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, struct dp_parser *parser, struct device_node *aux_switch, - struct dp_aux_bridge *aux_bridge) + struct dp_aux_bridge *aux_bridge, enum dp_aux_switch_type switch_type) { int rc = 0; struct dp_aux_private *aux; @@ -841,7 +902,24 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, dp_aux->reconfig = dp_aux_reconfig; dp_aux->abort = dp_aux_abort_transaction; dp_aux->set_sim_mode = dp_aux_set_sim_mode; - dp_aux->aux_switch = dp_aux_configure_aux_switch; + + /*Condition to avoid allocating function pointers for aux bypass mode*/ + if (switch_type != DP_AUX_SWITCH_BYPASS) { +#if IS_ENABLED(CONFIG_QCOM_FSA4480_I2C) + if (switch_type == DP_AUX_SWITCH_FSA4480) { + dp_aux->switch_configure = dp_aux_configure_fsa_switch; + dp_aux->switch_register_notifier = fsa4480_reg_notifier; + dp_aux->switch_unregister_notifier = fsa4480_unreg_notifier; + } +#endif +#if IS_ENABLED(CONFIG_QCOM_WCD939X_I2C) + if (switch_type == DP_AUX_SWITCH_WCD939x) { + dp_aux->switch_configure = dp_aux_configure_wcd_switch; + dp_aux->switch_register_notifier = wcd_usbss_reg_notifier; + dp_aux->switch_unregister_notifier = wcd_usbss_unreg_notifier; + } +#endif + } return dp_aux; error: diff --git a/msm/dp/dp_aux.h b/msm/dp/dp_aux.h index 4a922d55..d3778b11 100644 --- a/msm/dp/dp_aux.h +++ b/msm/dp/dp_aux.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2022, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. */ @@ -26,6 +26,12 @@ #define DP_STATE_AUX_TIMEOUT BIT(12) #define DP_STATE_PLL_LOCKED BIT(13) +enum dp_aux_switch_type { + DP_AUX_SWITCH_BYPASS, + DP_AUX_SWITCH_FSA4480, + DP_AUX_SWITCH_WCD939x, +}; + enum dp_aux_error { DP_AUX_ERR_NONE = 0, DP_AUX_ERR_ADDR = -1, @@ -52,14 +58,15 @@ struct dp_aux { void (*deinit)(struct dp_aux *aux); void (*reconfig)(struct dp_aux *aux); void (*abort)(struct dp_aux *aux, bool abort); - void (*set_sim_mode)(struct dp_aux *aux, - struct dp_aux_bridge *sim_bridge); - int (*aux_switch)(struct dp_aux *aux, bool enable, int orientation); + void (*set_sim_mode)(struct dp_aux *aux, struct dp_aux_bridge *sim_bridge); + int (*switch_configure)(struct dp_aux *aux, bool enable, int orientation); + int (*switch_register_notifier)(struct notifier_block *nb, struct device_node *node); + int (*switch_unregister_notifier)(struct notifier_block *nb, struct device_node *node); }; struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog, struct dp_parser *parser, struct device_node *aux_switch, - struct dp_aux_bridge *aux_bridge); + struct dp_aux_bridge *aux_bridge, enum dp_aux_switch_type switch_type); void dp_aux_put(struct dp_aux *aux); #endif /*__DP_AUX_H_*/ diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 065c8ed0..f2e45c3c 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include @@ -169,6 +168,7 @@ struct dp_display_private { enum drm_connector_status cached_connector_status; enum dp_display_states state; + enum dp_aux_switch_type switch_type; struct platform_device *pdev; struct device_node *aux_switch_node; @@ -1221,8 +1221,8 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp) dp->debug->max_pclk_khz); if (!dp->debug->sim_mode && !dp->no_aux_switch && !dp->parser->gpio_aux_switch - && dp->aux_switch_node) { - rc = dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); + && dp->aux_switch_node && dp->aux->switch_configure) { + rc = dp->aux->switch_configure(dp->aux, true, dp->hpd->orientation); if (rc) { mutex_unlock(&dp->session_lock); return rc; @@ -1400,7 +1400,7 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp, bool skip_w return rc; } -static int dp_display_fsa4480_callback(struct notifier_block *self, +static int dp_display_aux_switch_callback(struct notifier_block *self, unsigned long event, void *data) { return 0; @@ -1416,9 +1416,12 @@ static int dp_display_init_aux_switch(struct dp_display_private *dp) if (dp->aux_switch_ready) return rc; + if (!dp->aux->switch_register_notifier) + return rc; + SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY); - nb.notifier_call = dp_display_fsa4480_callback; + nb.notifier_call = dp_display_aux_switch_callback; nb.priority = 0; /* @@ -1426,7 +1429,7 @@ static int dp_display_init_aux_switch(struct dp_display_private *dp) * Bootup DP with cable connected usecase can hit this scenario. */ for (retry = 0; retry < max_retries; retry++) { - rc = fsa4480_reg_notifier(&nb, dp->aux_switch_node); + rc = dp->aux->switch_register_notifier(&nb, dp->aux_switch_node); if (rc == 0) { DP_DEBUG("registered notifier successfully\n"); dp->aux_switch_ready = true; @@ -1443,7 +1446,8 @@ static int dp_display_init_aux_switch(struct dp_display_private *dp) return rc; } - fsa4480_unreg_notifier(&nb, dp->aux_switch_node); + if (dp->aux->switch_unregister_notifier) + dp->aux->switch_unregister_notifier(&nb, dp->aux_switch_node); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, rc); return rc; @@ -1466,12 +1470,12 @@ static int dp_display_usbpd_configure_cb(struct device *dev) } if (!dp->debug->sim_mode && !dp->no_aux_switch - && !dp->parser->gpio_aux_switch && dp->aux_switch_node) { + && !dp->parser->gpio_aux_switch && dp->aux_switch_node && dp->aux->switch_configure) { rc = dp_display_init_aux_switch(dp); if (rc) return rc; - rc = dp->aux->aux_switch(dp->aux, true, dp->hpd->orientation); + rc = dp->aux->switch_configure(dp->aux, true, dp->hpd->orientation); if (rc) return rc; } @@ -1709,8 +1713,8 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev) dp->aux->abort(dp->aux, true); if (!dp->debug->sim_mode && !dp->no_aux_switch - && !dp->parser->gpio_aux_switch) - dp->aux->aux_switch(dp->aux, false, ORIENTATION_NONE); + && !dp->parser->gpio_aux_switch && dp->aux->switch_configure) + dp->aux->switch_configure(dp->aux, false, ORIENTATION_NONE); dp_display_disconnect_sync(dp); @@ -2158,8 +2162,15 @@ static int dp_init_sub_modules(struct dp_display_private *dp) dp->no_aux_switch = true; } + if (!strcmp(dp->aux_switch_node->name, "fsa4480")) + dp->switch_type = DP_AUX_SWITCH_FSA4480; + else if (!strcmp(dp->aux_switch_node->name, "wcd939x_i2c")) + dp->switch_type = DP_AUX_SWITCH_WCD939x; + else + dp->switch_type = DP_AUX_SWITCH_BYPASS; + dp->aux = dp_aux_get(dev, &dp->catalog->aux, dp->parser, - dp->aux_switch_node, dp->aux_bridge); + dp->aux_switch_node, dp->aux_bridge, dp->switch_type); if (IS_ERR(dp->aux)) { rc = PTR_ERR(dp->aux); DP_ERR("failed to initialize aux, rc = %d\n", rc);