#include <linux/clk.h>
#include <linux/component.h>
#include <linux/gpio/consumer.h>
+#include <linux/extcon-provider.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
pm_runtime_put(&vc4_hdmi->pdev->dev);
+#ifdef CONFIG_EXTCON
+ if (status != vc4_hdmi->status) {
+ extcon_set_state_sync(vc4_hdmi->edev, EXTCON_DISP_HDMI,
+ (status == connector_status_connected ?
+ true : false));
+ vc4_hdmi->status = status;
+ }
+#endif
+
return status;
}
ret = drm_add_edid_modes(connector, edid);
kfree(edid);
- if (!vc4->hvs->vc5_hdmi_enable_scrambling) {
+ if (!vc4->hvs->vc5_hdmi_enable_hdmi_20) {
struct drm_device *drm = connector->dev;
const struct drm_display_mode *mode;
static enum drm_mode_status
vc4_hdmi_encoder_clock_valid(const struct vc4_hdmi *vc4_hdmi,
+ const struct drm_display_mode *mode,
unsigned long long clock)
{
const struct drm_connector *connector = &vc4_hdmi->connector;
if (clock > vc4_hdmi->variant->max_pixel_clock)
return MODE_CLOCK_HIGH;
- if (!vc4->hvs->vc5_hdmi_enable_scrambling && clock > HDMI_14_MAX_TMDS_CLK)
+ if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK)
+ return MODE_CLOCK_HIGH;
+
+ /* 4096x2160@60 is not reliable without overclocking core */
+ if (!vc4->hvs->vc5_hdmi_enable_4096by2160 &&
+ mode->hdisplay > 3840 && mode->vdisplay >= 2160 &&
+ drm_mode_vrefresh(mode) >= 50)
return MODE_CLOCK_HIGH;
if (info->max_tmds_clock && clock > (info->max_tmds_clock * 1000))
unsigned long long clock;
clock = vc4_hdmi_encoder_compute_mode_clock(mode, bpc, fmt);
- if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, clock) != MODE_OK)
+ if (vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode, clock) != MODE_OK)
return -EINVAL;
vc4_state->pixel_rate = clock;
struct drm_connector *connector = &vc4_hdmi->connector;
struct drm_connector_state *old_conn_state = drm_atomic_get_old_connector_state(conn_state->state, connector);
struct vc4_hdmi_connector_state *old_vc4_state = conn_state_to_vc4_hdmi_conn_state(old_conn_state);
- struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
unsigned long long pixel_rate = mode->clock * 1000;
unsigned long long tmds_rate;
int ret;
return -EINVAL;
}
- /* 4096x2160@60 is not reliable without overclocking core */
- if (mode->hdisplay > 3840 && mode->vdisplay >= 2160 &&
- drm_mode_vrefresh(mode) >= 50 &&
- !vc4->hvs->vc5_hdmi_enable_4096by2160)
- return -EINVAL;
-
/*
* The 1440p@60 pixel rate is in the same range than the first
* WiFi channel (between 2.4GHz and 2.422GHz with 22MHz
const struct drm_display_mode *mode)
{
struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- const struct drm_connector *connector = &vc4_hdmi->connector;
- struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
if (vc4_hdmi->variant->unsupported_odd_h_timings &&
!(mode->flags & DRM_MODE_FLAG_DBLCLK) &&
(mode->hsync_end % 2) || (mode->htotal % 2)))
return MODE_H_ILLEGAL;
- if (mode->hdisplay > 3840 && mode->vdisplay >= 2160 &&
- drm_mode_vrefresh(mode) >= 50 &&
- !vc4->hvs->vc5_hdmi_enable_4096by2160)
- return MODE_CLOCK_HIGH;
-
- return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode->clock * 1000);
+ return vc4_hdmi_encoder_clock_valid(vc4_hdmi, mode, mode->clock * 1000);
}
static const struct drm_encoder_helper_funcs vc4_hdmi_encoder_helper_funcs = {
put_device(&vc4_hdmi->ddc->dev);
}
+#ifdef CONFIG_EXTCON
+static const unsigned int vc4_hdmi_extcon_cable[] = {
+ EXTCON_DISP_HDMI,
+ EXTCON_NONE,
+};
+#endif
+
static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
{
const struct vc4_hdmi_variant *variant = of_device_get_match_data(dev);
if (ret)
return ret;
+#ifdef CONFIG_EXTCON
+ vc4_hdmi->status = connector_status_disconnected;
+
+ /* Initialize extcon device */
+ vc4_hdmi->edev = devm_extcon_dev_allocate(dev, vc4_hdmi_extcon_cable);
+ if (IS_ERR(vc4_hdmi->edev)) {
+ dev_err(dev, "failed to allocate memory for extcon\n");
+ return PTR_ERR(vc4_hdmi->edev);
+ }
+
+ ret = devm_extcon_dev_register(dev, vc4_hdmi->edev);
+ if (ret) {
+ dev_err(dev, "failed to register extcon device\n");
+ return ret;
+ }
+#endif
+
/* Only use the GPIO HPD pin if present in the DT, otherwise
* we'll use the HDMI core's register.
*/