@@ -9,6 +9,7 @@ config DRM_MSM
depends on QCOM_OCMEM || QCOM_OCMEM=n
depends on QCOM_LLCC || QCOM_LLCC=n
depends on QCOM_COMMAND_DB || QCOM_COMMAND_DB=n
+ depends on TYPEC || TYPEC=n
select IOMMU_IO_PGTABLE
select QCOM_MDT_LOADER if ARCH_QCOM
select REGULATOR
@@ -85,6 +85,8 @@ struct dp_display_private {
bool hpd_irq_on;
bool audio_supported;
+ bool use_hw_hpd;
+
struct platform_device *pdev;
struct dentry *root;
@@ -466,11 +468,10 @@ static int dp_display_handle_irq_hpd(struct dp_display_private *dp)
return 0;
}
-static int dp_display_usbpd_attention_cb(struct device *dev)
+static int dp_display_usbpd_attention(struct dp_display_private *dp)
{
int rc = 0;
u32 sink_request;
- struct dp_display_private *dp = dev_get_dp_display_private(dev);
/* check for any test request issued by sink */
rc = dp_link_process_request(dp->link);
@@ -690,7 +691,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
return 0;
}
- ret = dp_display_usbpd_attention_cb(&dp->pdev->dev);
+ ret = dp_display_usbpd_attention(dp);
if (ret == -ECONNRESET) { /* cable unplugged */
dp->core_initialized = false;
}
@@ -709,6 +710,13 @@ static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
dp_audio_put(dp->audio);
}
+static int dp_display_usbpd_attention_cb(struct device *dev)
+{
+ struct dp_display_private *dp = dev_get_dp_display_private(dev);
+
+ return dp_irq_hpd_handle(dp, 0);
+}
+
static int dp_init_sub_modules(struct dp_display_private *dp)
{
int rc = 0;
@@ -731,6 +739,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
goto error;
}
+ dp->use_hw_hpd = !of_property_read_bool(dev->of_node, "mode-switch");
+
dp->parser = dp_parser_get(dp->pdev);
if (IS_ERR(dp->parser)) {
rc = PTR_ERR(dp->parser);
@@ -1135,27 +1145,29 @@ static irqreturn_t dp_display_irq_handler(int irq, void *dev_id)
return IRQ_NONE;
}
- hpd_isr_status = dp_catalog_hpd_get_intr_status(dp->catalog);
+ if (dp->use_hw_hpd) {
+ hpd_isr_status = dp_catalog_hpd_get_intr_status(dp->catalog);
- DRM_DEBUG_DP("hpd isr status=%#x\n", hpd_isr_status);
- if (hpd_isr_status & 0x0F) {
- /* hpd related interrupts */
- if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK)
- dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0);
+ DRM_DEBUG_DP("hpd isr status=%#x\n", hpd_isr_status);
+ if (hpd_isr_status & 0x0F) {
+ /* hpd related interrupts */
+ if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK)
+ dp_add_event(dp, EV_HPD_PLUG_INT, 0, 0);
- if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) {
- /* stop sentinel connect pending checking */
- dp_del_event(dp, EV_CONNECT_PENDING_TIMEOUT);
- dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0);
- }
+ if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) {
+ /* stop sentinel connect pending checking */
+ dp_del_event(dp, EV_CONNECT_PENDING_TIMEOUT);
+ dp_add_event(dp, EV_IRQ_HPD_INT, 0, 0);
+ }
- if (hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) {
- dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
- dp_add_event(dp, EV_HPD_PLUG_INT, 0, 3);
- }
+ if (hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) {
+ dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
+ dp_add_event(dp, EV_HPD_PLUG_INT, 0, 3);
+ }
- if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK)
- dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
+ if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK)
+ dp_add_event(dp, EV_HPD_UNPLUG_INT, 0, 0);
+ }
}
/* DP controller isr */
@@ -7,6 +7,9 @@
#include <linux/slab.h>
#include <linux/device.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_dp.h>
+#include <linux/usb/typec_mux.h>
#include "dp_hpd.h"
@@ -22,6 +25,8 @@ struct dp_hpd_private {
struct device *dev;
struct dp_usbpd_cb *dp_cb;
struct dp_usbpd dp_usbpd;
+ struct typec_mux *mux;
+ bool connected;
};
int dp_hpd_connect(struct dp_usbpd *dp_usbpd, bool hpd)
@@ -47,9 +52,45 @@ int dp_hpd_connect(struct dp_usbpd *dp_usbpd, bool hpd)
return rc;
}
+static int dp_hpd_mux_set(struct typec_mux *mux, struct typec_mux_state *state)
+{
+ struct dp_hpd_private *dp_hpd = typec_mux_get_drvdata(mux);
+ struct dp_usbpd *usbpd = &dp_hpd->dp_usbpd;
+ struct typec_displayport_data *dp_data = state->data;
+ int pin_assign = 0;
+
+ if (dp_data) {
+ pin_assign = DP_CONF_GET_PIN_ASSIGN(dp_data->conf);
+ usbpd->hpd_high = !!(dp_data->status & DP_STATUS_HPD_STATE);
+ usbpd->hpd_irq = !!(dp_data->status & DP_STATUS_IRQ_HPD);
+ usbpd->multi_func = pin_assign == DP_PIN_ASSIGN_C || DP_PIN_ASSIGN_E;
+ }
+
+ if (!pin_assign) {
+ if (dp_hpd->connected) {
+ dp_hpd->connected = false;
+ dp_hpd->dp_cb->disconnect(dp_hpd->dev);
+ }
+ } else if (!dp_hpd->connected) {
+ dp_hpd->connected = true;
+ dp_hpd->dp_cb->configure(dp_hpd->dev);
+ } else {
+ dp_hpd->dp_cb->attention(dp_hpd->dev);
+ }
+
+ return 0;
+}
+
+static void dp_hpd_unregister_typec_mux(void *data)
+{
+ typec_mux_unregister(data);
+}
+
struct dp_usbpd *dp_hpd_get(struct device *dev, struct dp_usbpd_cb *cb)
{
+ struct typec_mux_desc mux_desc = {};
struct dp_hpd_private *dp_hpd;
+ int rc;
if (!cb) {
pr_err("invalid cb data\n");
@@ -65,5 +106,18 @@ struct dp_usbpd *dp_hpd_get(struct device *dev, struct dp_usbpd_cb *cb)
dp_hpd->dp_usbpd.connect = dp_hpd_connect;
+ mux_desc.fwnode = dev->fwnode;
+ mux_desc.set = dp_hpd_mux_set;
+ mux_desc.drvdata = dp_hpd;
+ dp_hpd->mux = typec_mux_register(dev, &mux_desc);
+ if (IS_ERR(dp_hpd->mux)) {
+ dev_err(dev, "unable to register typec mux\n");
+ return ERR_CAST(dp_hpd->mux);
+ }
+
+ rc = devm_add_action_or_reset(dev, dp_hpd_unregister_typec_mux, dp_hpd->mux);
+ if (rc)
+ return ERR_PTR(rc);
+
return &dp_hpd->dp_usbpd;
}
Implement a typec_mux in order to allow a Type-C controller to signal the connection and attention of DisplayPort to the related USB-C port. The remains of support for something along this lines was left in the dp_display as the driver was upstreamed, so these are reused with minimal modifications necessary. When operating in this mode, HPD interrupts has still been observed in the ISR so, in line with the downstream kernel, these are ignored. Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org> --- This applies on top of https://lore.kernel.org/linux-arm-msm/20211001180058.1021913-1-bjorn.andersson@linaro.org/ drivers/gpu/drm/msm/Kconfig | 1 + drivers/gpu/drm/msm/dp/dp_display.c | 52 ++++++++++++++++----------- drivers/gpu/drm/msm/dp/dp_hpd.c | 54 +++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 20 deletions(-)