diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README
index 708ebaac9c..d50d694c9e 100644
--- a/arch/arm/boot/dts/overlays/README
+++ b/arch/arm/boot/dts/overlays/README
@@ -2504,7 +2504,7 @@ Params: gpio_pin Output GPIO (default 18)
Name: qca7000
-Info: I2SE's Evaluation Board for PLC Stamp micro
+Info: in-tech's Evaluation Board for PLC Stamp micro
Load: dtoverlay=qca7000,=
Params: int_pin GPIO pin for interrupt signal (default 23)
diff --git a/arch/arm/boot/dts/overlays/qca7000-overlay.dts b/arch/arm/boot/dts/overlays/qca7000-overlay.dts
index 9a451202a2..f695f36024 100644
--- a/arch/arm/boot/dts/overlays/qca7000-overlay.dts
+++ b/arch/arm/boot/dts/overlays/qca7000-overlay.dts
@@ -1,5 +1,5 @@
-// Overlay for the Qualcomm Atheros QCA7000 on I2SE's PLC Stamp micro EVK
-// Visit: https://www.i2se.com/product/plc-stamp-micro-evk for details
+// Overlay for the Qualcomm Atheros QCA7000 on PLC Stamp micro EVK
+// Visit: https://in-tech-smartcharging.com/products/evaluation-tools/plc-stamp-micro-2-evaluation-board for details
/dts-v1/;
/plugin/;
diff --git a/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts b/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts
index e013884709..5b12d02c37 100644
--- a/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts
+++ b/arch/arm/boot/dts/overlays/rpi-poe-plus-overlay.dts
@@ -17,3 +17,7 @@ rpi_poe_power_supply: rpi-poe-power-supply@0 {
};
};
};
+
+&fan0 {
+ cooling-levels = <0 32 64 128 255>;
+};
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index e7e1ee2aa3..3d3540a4d7 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -795,6 +795,85 @@ void drm_kms_helper_poll_fini(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
+static bool
+_drm_connector_helper_hpd_irq_event(struct drm_connector *connector,
+ bool notify)
+{
+ struct drm_device *dev = connector->dev;
+ enum drm_connector_status old_status;
+ u64 old_epoch_counter;
+ bool changed = false;
+
+ /* Only handle HPD capable connectors. */
+ drm_WARN_ON(dev, !(connector->polled & DRM_CONNECTOR_POLL_HPD));
+
+ drm_WARN_ON(dev, !mutex_is_locked(&dev->mode_config.mutex));
+
+ old_status = connector->status;
+ old_epoch_counter = connector->epoch_counter;
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old epoch counter %llu\n",
+ connector->base.id,
+ connector->name,
+ old_epoch_counter);
+
+ connector->status = drm_helper_probe_detect(connector, NULL,
+ false);
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
+ connector->base.id,
+ connector->name,
+ drm_get_connector_status_name(old_status),
+ drm_get_connector_status_name(connector->status));
+
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New epoch counter %llu\n",
+ connector->base.id,
+ connector->name,
+ connector->epoch_counter);
+
+ /*
+ * Check if epoch counter had changed, meaning that we need
+ * to send a uevent.
+ */
+ if (old_epoch_counter != connector->epoch_counter)
+ changed = true;
+
+ if (changed && notify) {
+ drm_kms_helper_hotplug_event(dev);
+ DRM_DEBUG_KMS("Sent hotplug event\n");
+ }
+
+ return changed;
+}
+
+/**
+ * drm_connector_helper_hpd_irq_event - hotplug processing
+ * @connector: drm_connector
+ *
+ * Drivers can use this helper function to run a detect cycle on a connector
+ * which has the DRM_CONNECTOR_POLL_HPD flag set in its &polled member.
+ *
+ * This helper function is useful for drivers which can track hotplug
+ * interrupts for a single connector.
+ *
+ * This function must be called from process context with no mode
+ * setting locks held.
+ *
+ * Note that a connector can be both polled and probed from the hotplug
+ * handler, in case the hotplug interrupt is known to be unreliable.
+ */
+bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector)
+{
+ struct drm_device *dev = connector->dev;
+ bool changed;
+
+ mutex_lock(&dev->mode_config.mutex);
+ changed = _drm_connector_helper_hpd_irq_event(connector, true);
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return changed;
+}
+EXPORT_SYMBOL(drm_connector_helper_hpd_irq_event);
+
/**
* drm_helper_hpd_irq_event - hotplug processing
* @dev: drm_device
@@ -822,9 +901,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
{
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
- enum drm_connector_status old_status;
bool changed = false;
- u64 old_epoch_counter;
if (!dev->mode_config.poll_enabled)
return false;
@@ -832,37 +909,9 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
mutex_lock(&dev->mode_config.mutex);
drm_connector_list_iter_begin(dev, &conn_iter);
drm_for_each_connector_iter(connector, &conn_iter) {
- /* Only handle HPD capable connectors. */
- if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
- continue;
-
- old_status = connector->status;
-
- old_epoch_counter = connector->epoch_counter;
-
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old epoch counter %llu\n", connector->base.id,
- connector->name,
- old_epoch_counter);
-
- connector->status = drm_helper_probe_detect(connector, NULL, false);
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
- connector->base.id,
- connector->name,
- drm_get_connector_status_name(old_status),
- drm_get_connector_status_name(connector->status));
-
- DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New epoch counter %llu\n",
- connector->base.id,
- connector->name,
- connector->epoch_counter);
-
- /*
- * Check if epoch counter had changed, meaning that we need
- * to send a uevent.
- */
- if (old_epoch_counter != connector->epoch_counter)
+ if (_drm_connector_helper_hpd_irq_event(connector,
+ false))
changed = true;
-
}
drm_connector_list_iter_end(&conn_iter);
mutex_unlock(&dev->mode_config.mutex);
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 3838606072..207ff08485 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -96,6 +96,7 @@
# define VC4_HD_M_SW_RST BIT(2)
# define VC4_HD_M_ENABLE BIT(0)
+#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
@@ -182,8 +183,6 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
if (vc4_hdmi->hpd_gpio &&
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) {
connected = true;
}
@@ -1190,7 +1189,7 @@ static u32 vc5_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixe
* pixel clock, but HSM ends up being the limiting factor.
*/
- return max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
+ return max_t(unsigned long, HSM_MIN_CLOCK_FREQ, (pixel_rate / 100) * 101);
}
static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
@@ -2313,6 +2312,32 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
vc4_hdmi->disable_4kp60 = true;
}
+ /*
+ * If we boot without any cable connected to the HDMI connector,
+ * the firmware will skip the HSM initialization and leave it
+ * with a rate of 0, resulting in a bus lockup when we're
+ * accessing the registers even if it's enabled.
+ *
+ * Let's put a sensible default at runtime_resume so that we
+ * don't end up in this situation.
+ *
+ * Strictly speaking we should be using clk_set_min_rate.
+ * However, the clk-bcm2835 clock driver favors clock rates
+ * under the expected rate, which in the case where we set the
+ * minimum clock rate will be rejected by the clock framework.
+ *
+ * However, even for the two HDMI controllers found on the
+ * BCM2711, using clk_set_rate doesn't cause any issue. Indeed,
+ * the bind callbacks are called in sequence, and before the DRM
+ * device is registered and therefore a mode is set. As such,
+ * we're not at risk of having the first controller set a
+ * different mode and then the second overriding the HSM clock
+ * frequency in its bind.
+ */
+ ret = clk_set_rate(vc4_hdmi->hsm_clock, HSM_MIN_CLOCK_FREQ);
+ if (ret)
+ goto err_put_ddc;
+
if (vc4_hdmi->variant->reset)
vc4_hdmi->variant->reset(vc4_hdmi);