diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c index 63fe2d612941..ca3227125421 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.c +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include #include @@ -150,6 +152,9 @@ static void cdn_dp_clk_disable(struct cdn_dp_device *dp) static int cdn_dp_get_port_lanes(struct cdn_dp_port *port) { + if (port->hpd_gpio && !gpiod_get_value_cansleep(port->hpd_gpio)) + return 0; + return phy_get_bus_width(port->phy); } @@ -776,6 +781,15 @@ static const struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = { static int cdn_dp_encoder_late_register(struct drm_encoder *encoder) { struct cdn_dp_device *dp = encoder_to_dp(encoder); + int i; + + for (i = 0; i < dp->ports; i++) { + if (!dp->port[i]) + continue; + + if (dp->port[i]->hpd_gpio) + enable_irq(dp->port[i]->hpd_irq); + } dp->registered = true; schedule_delayed_work(&dp->event_work, 0); @@ -786,6 +800,15 @@ static int cdn_dp_encoder_late_register(struct drm_encoder *encoder) static void cdn_dp_encoder_early_unregister(struct drm_encoder *encoder) { struct cdn_dp_device *dp = encoder_to_dp(encoder); + int i; + + for (i = 0; i < dp->ports; i++) { + if (!dp->port[i]) + continue; + + if (dp->port[i]->hpd_gpio) + disable_irq(dp->port[i]->hpd_irq); + } dp->registered = false; barrier(); @@ -1033,6 +1056,16 @@ out: return ret; } +static irqreturn_t cdn_dp_hpd_irq_handler(int irq, void *arg) +{ + struct cdn_dp_port *port = arg; + struct cdn_dp_device *dp = port->dp; + + schedule_delayed_work(&dp->event_work, 0); + + return IRQ_HANDLED; +} + static void cdn_dp_pd_event_work(struct work_struct *work) { struct cdn_dp_device *dp = container_of(to_delayed_work(work), struct cdn_dp_device, @@ -1309,6 +1342,36 @@ static int cdn_dp_probe(struct platform_device *pdev) return -EINVAL; } + for (i = 0; i < dp->ports; i++) { + if (!dp->port[i]) + continue; + + port = dp->port[i]; + port->hpd_gpio = devm_gpiod_get_index_optional(dev, "hpd", i, GPIOD_IN); + if (IS_ERR(port->hpd_gpio)) { + DRM_DEV_ERROR(dev, "failed to get port%d hpd gpio\n", i); + return PTR_ERR(port->hpd_gpio); + } + + if (port->hpd_gpio) { + port->hpd_irq = gpiod_to_irq(port->hpd_gpio); + + if (port->hpd_irq < 0) { + DRM_DEV_ERROR(dev, "failed to get port%d hpd irq\n", i); + return port->hpd_irq; + } + + ret = devm_request_irq(dev, port->hpd_irq, cdn_dp_hpd_irq_handler, + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING | + IRQF_NO_AUTOEN, "cdn-dp-hpd", port); + if (ret) { + DRM_DEV_ERROR(dev, "failed to request HPD interrupt\n"); + return ret; + } + } + } + mutex_init(&dp->lock); dev_set_drvdata(dev, dp); diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h index 2d7f2c1fbc51..0efcce4b8125 100644 --- a/drivers/gpu/drm/rockchip/cdn-dp-core.h +++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h @@ -58,6 +58,9 @@ struct cdn_dp_port { u8 lanes; bool phy_enabled; u8 id; + + struct gpio_desc *hpd_gpio; + int hpd_irq; }; struct cdn_dp_device {