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);