From 2bff3a2f0d53f774d0296c54eccfb6d71997a546 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 10 May 2021 12:25:55 +0200 Subject: [PATCH 1/4] pinctrl: bcm2835: Disable interrupts for the banks > 0 It appears that the interrupts for all the banks but the first one are not working properly. Disable them for now. Signed-off-by: Maxime Ripard --- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index c5d88157f4b289..b0dd126661ec48 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -351,6 +351,28 @@ static int bcm2835_gpio_direction_output(struct gpio_chip *chip, return pinctrl_gpio_direction_output(chip->base + offset); } +static int bcm2835_gpio_irq_map(struct irq_domain *d, + unsigned int irq, + irq_hw_number_t hwirq) +{ + unsigned bank = GPIO_REG_OFFSET(hwirq); + + /* + * FIXME: It appears that the interrupts in any bank but the + * first are not working. + */ + if (bank) + return -EINVAL; + + return gpiochip_irq_map(d, irq, hwirq); +} + +static const struct irq_domain_ops bcm2835_irq_domain_ops = { + .map = bcm2835_gpio_irq_map, + .unmap = gpiochip_irq_unmap, + .xlate = irq_domain_xlate_twocell, +}; + static const struct gpio_chip bcm2835_gpio_chip = { .label = MODULE_NAME, .owner = THIS_MODULE, @@ -1258,6 +1280,7 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) girq = &pc->gpio_chip.irq; girq->chip = &bcm2835_gpio_irq_chip; + girq->domain_ops = &bcm2835_irq_domain_ops; girq->parent_handler = bcm2835_gpio_irq_handler; girq->num_parents = BCM2835_NUM_IRQS; girq->parents = devm_kcalloc(dev, BCM2835_NUM_IRQS, From 50b1e711602fd72bb6003ca8aef97220718b5a4d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 29 Apr 2021 14:24:39 +0200 Subject: [PATCH 2/4] drm/vc4: hdmi: Fix error path of hpd-gpios If the of_get_named_gpio_flags call fails in vc4_hdmi_bind, we jump to the err_unprepare_hsm label. That label will then call pm_runtime_disable and put_device on the DDC device. We just retrieved the DDC device, so the latter is definitely justified. However at that point we still haven't called pm_runtime_enable, so the call to pm_runtime_disable is not supposed to be there. Fixes: 10ee275cb12f ("drm/vc4: prepare for CEC support") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index f75c176dde098d..3955dd09832a22 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2767,7 +2767,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) &hpd_gpio_flags); if (vc4_hdmi->hpd_gpio < 0) { ret = vc4_hdmi->hpd_gpio; - goto err_unprepare_hsm; + goto err_put_ddc; } vc4_hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; @@ -2828,8 +2828,8 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi_connector_destroy(&vc4_hdmi->connector); err_destroy_encoder: drm_encoder_cleanup(encoder); -err_unprepare_hsm: pm_runtime_disable(dev); +err_put_ddc: put_device(&vc4_hdmi->ddc->dev); return ret; From 0ed33147c135ab808e8519cd93078517443fea12 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 29 Apr 2021 15:27:14 +0200 Subject: [PATCH 3/4] drm/vc4: hdmi: Convert to gpiod The new gpiod interface takes care of parsing the GPIO flags and to return the logical value when accessing an active-low GPIO, so switching to it simplifies a lot the driver. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 22 ++++++---------------- drivers/gpu/drm/vc4/vc4_hdmi.h | 3 +-- 2 files changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 3955dd09832a22..d4739c41aad2c7 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -484,9 +484,8 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force) WARN_ON(clk_prepare_enable(vc4_hdmi->hsm_clock)); if (vc4_hdmi->hpd_gpio) { - if (gpio_get_value_cansleep(vc4_hdmi->hpd_gpio) ^ - vc4_hdmi->hpd_active_low) - connected = true; + if (gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) + connected = true; } else if (drm_probe_ddc(vc4_hdmi->ddc)) { connected = true; } else if (HDMI_READ(HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED) { @@ -2720,7 +2719,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) struct vc4_hdmi *vc4_hdmi; struct drm_encoder *encoder; struct device_node *ddc_node; - u32 value; int ret; vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL); @@ -2759,18 +2757,10 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) /* Only use the GPIO HPD pin if present in the DT, otherwise * we'll use the HDMI core's register. */ - if (of_find_property(dev->of_node, "hpd-gpios", &value)) { - enum of_gpio_flags hpd_gpio_flags; - - vc4_hdmi->hpd_gpio = of_get_named_gpio_flags(dev->of_node, - "hpd-gpios", 0, - &hpd_gpio_flags); - if (vc4_hdmi->hpd_gpio < 0) { - ret = vc4_hdmi->hpd_gpio; - goto err_put_ddc; - } - - vc4_hdmi->hpd_active_low = hpd_gpio_flags & OF_GPIO_ACTIVE_LOW; + vc4_hdmi->hpd_gpio = devm_gpiod_get_optional(dev, "hpd", GPIOD_IN); + if (IS_ERR(vc4_hdmi->hpd_gpio)) { + ret = PTR_ERR(vc4_hdmi->hpd_gpio); + goto err_put_ddc; } vc4_hdmi->disable_wifi_frequencies = diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 67c372d743cb68..78651ab61fa84c 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -153,8 +153,7 @@ struct vc4_hdmi { /* VC5 Only */ void __iomem *rm_regs; - int hpd_gpio; - bool hpd_active_low; + struct gpio_desc *hpd_gpio; /* * On some systems (like the RPi4), some modes are in the same From 14167a22a713fba88f5bc7f75ff5d7f03ae37188 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 6 May 2021 17:36:59 +0200 Subject: [PATCH 4/4] drm/vc4: hdmi: Support Hotplug interrupt over GPIO The HPD GPIO can be used on some RPi (2B, 3B+). However, and while it works fine on the 3B+, it looks like on the 2B irq over gpios doesn't work yet. Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index d4739c41aad2c7..a2bcc9564e3b37 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2197,6 +2197,21 @@ static int vc4_hdmi_hotplug_init(struct vc4_hdmi *vc4_hdmi) if (ret) return ret; + connector->polled = DRM_CONNECTOR_POLL_HPD; + } else if (vc4_hdmi->hpd_gpio) { + int irq = gpiod_to_irq(vc4_hdmi->hpd_gpio); + if (irq < 0) + return 0; + + ret = devm_request_threaded_irq(dev, irq, + NULL, vc4_hdmi_hpd_irq_thread, + IRQF_ONESHOT | + IRQF_TRIGGER_RISING | + IRQF_TRIGGER_FALLING, + "vc4 hdmi hpd", vc4_hdmi); + if (ret) + return ret; + connector->polled = DRM_CONNECTOR_POLL_HPD; }