diff --git a/drivers/gpu/drm/display/drm_hdmi_state_helper.c b/drivers/gpu/drm/display/drm_hdmi_state_helper.c index c205f37da1e12b11c384670db83e43613e031340..ccbfe084d6ffbcf9b5599a9234347f4a7bb6c3e1 100644 --- a/drivers/gpu/drm/display/drm_hdmi_state_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_state_helper.c @@ -99,25 +99,25 @@ sink_supports_format_bpc(const struct drm_connector *connector, * VIC1), the bpc must be 8. */ if (vic == 1 && bpc != 8) { - drm_dbg_kms(dev, "VIC1 requires a bpc of 8, got %u\n", bpc); + drm_info(dev, "VIC1 requires a bpc of 8, got %u\n", bpc); return false; } if (!info->is_hdmi && (format != HDMI_COLORSPACE_RGB || bpc != 8)) { - drm_dbg_kms(dev, "DVI Monitors require an RGB output at 8 bpc\n"); + drm_info(dev, "DVI Monitors require an RGB output at 8 bpc\n"); return false; } if (!(connector->hdmi.supported_formats & BIT(format))) { - drm_dbg_kms(dev, "%s format unsupported by the connector.\n", + drm_info(dev, "%s format unsupported by the connector.\n", drm_hdmi_connector_get_output_format_name(format)); return false; } switch (format) { case HDMI_COLORSPACE_RGB: - drm_dbg_kms(dev, "RGB Format, checking the constraints.\n"); + drm_info(dev, "RGB Format, checking the constraints.\n"); /* * In some cases, like when the EDID readout fails, or @@ -127,38 +127,40 @@ sink_supports_format_bpc(const struct drm_connector *connector, * supported so we can keep things going and light up * the display. */ - if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444)) + if (!(info->color_formats & DRM_COLOR_FORMAT_RGB444)) { drm_warn(dev, "HDMI Sink doesn't support RGB, something's wrong.\n"); + return false; + } if (bpc == 10 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_30)) { - drm_dbg_kms(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); + drm_info(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); return false; } if (bpc == 12 && !(info->edid_hdmi_rgb444_dc_modes & DRM_EDID_HDMI_DC_36)) { - drm_dbg_kms(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); + drm_info(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); return false; } - drm_dbg_kms(dev, "RGB format supported in that configuration.\n"); + drm_info(dev, "RGB format supported in that configuration.\n"); return true; case HDMI_COLORSPACE_YUV420: /* TODO: YUV420 is unsupported at the moment. */ - drm_dbg_kms(dev, "YUV420 format isn't supported yet.\n"); + drm_info(dev, "YUV420 format isn't supported yet.\n"); return false; case HDMI_COLORSPACE_YUV422: - drm_dbg_kms(dev, "YUV422 format, checking the constraints.\n"); + drm_info(dev, "YUV422 format, checking the constraints.\n"); if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR422)) { - drm_dbg_kms(dev, "Sink doesn't support YUV422.\n"); + drm_info(dev, "Sink doesn't support YUV422.\n"); return false; } if (bpc > 12) { - drm_dbg_kms(dev, "YUV422 only supports 12 bpc or lower.\n"); + drm_info(dev, "YUV422 only supports 12 bpc or lower.\n"); return false; } @@ -168,34 +170,34 @@ sink_supports_format_bpc(const struct drm_connector *connector, * don't need to check the Deep Color bits in the EDIDs here. */ - drm_dbg_kms(dev, "YUV422 format supported in that configuration.\n"); + drm_info(dev, "YUV422 format supported in that configuration.\n"); return true; case HDMI_COLORSPACE_YUV444: - drm_dbg_kms(dev, "YUV444 format, checking the constraints.\n"); + drm_info(dev, "YUV444 format, checking the constraints.\n"); if (!(info->color_formats & DRM_COLOR_FORMAT_YCBCR444)) { - drm_dbg_kms(dev, "Sink doesn't support YUV444.\n"); + drm_info(dev, "Sink doesn't support YUV444.\n"); return false; } if (bpc == 10 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_30)) { - drm_dbg_kms(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); + drm_info(dev, "10 BPC but sink doesn't support Deep Color 30.\n"); return false; } if (bpc == 12 && !(info->edid_hdmi_ycbcr444_dc_modes & DRM_EDID_HDMI_DC_36)) { - drm_dbg_kms(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); + drm_info(dev, "12 BPC but sink doesn't support Deep Color 36.\n"); return false; } - drm_dbg_kms(dev, "YUV444 format supported in that configuration.\n"); + drm_info(dev, "YUV444 format supported in that configuration.\n"); return true; } - drm_dbg_kms(dev, "Unsupported pixel format.\n"); + drm_info(dev, "Unsupported pixel format.\n"); return false; } @@ -253,11 +255,11 @@ hdmi_try_format_bpc(const struct drm_connector *connector, struct drm_device *dev = connector->dev; int ret; - drm_dbg_kms(dev, "Trying %s output format\n", + drm_info(dev, "Trying %s output format\n", drm_hdmi_connector_get_output_format_name(fmt)); if (!sink_supports_format_bpc(connector, info, mode, fmt, bpc)) { - drm_dbg_kms(dev, "%s output format not supported with %u bpc\n", + drm_info(dev, "%s output format not supported with %u bpc\n", drm_hdmi_connector_get_output_format_name(fmt), bpc); return false; @@ -265,13 +267,13 @@ hdmi_try_format_bpc(const struct drm_connector *connector, ret = hdmi_compute_clock(connector, conn_state, mode, bpc, fmt); if (ret) { - drm_dbg_kms(dev, "Couldn't compute clock for %s output format and %u bpc\n", + drm_info(dev, "Couldn't compute clock for %s output format and %u bpc\n", drm_hdmi_connector_get_output_format_name(fmt), bpc); return false; } - drm_dbg_kms(dev, "%s output format supported with %u (TMDS char rate: %llu Hz)\n", + drm_info(dev, "%s output format supported with %u (TMDS char rate: %llu Hz)\n", drm_hdmi_connector_get_output_format_name(fmt), bpc, conn_state->hdmi.tmds_char_rate); @@ -295,7 +297,7 @@ hdmi_compute_format(const struct drm_connector *connector, return 0; } - drm_dbg_kms(dev, "Failed. No Format Supported for that bpc count.\n"); + drm_info(dev, "Failed. No Format Supported for that bpc count.\n"); return -EINVAL; } @@ -313,7 +315,7 @@ hdmi_compute_config(const struct drm_connector *connector, int ret; for (bpc = max_bpc; bpc >= 8; bpc -= 2) { - drm_dbg_kms(dev, "Trying with a %d bpc output\n", bpc); + drm_info(dev, "Trying with a %d bpc output\n", bpc); ret = hdmi_compute_format(connector, conn_state, mode, bpc); if (ret) @@ -321,7 +323,7 @@ hdmi_compute_config(const struct drm_connector *connector, conn_state->hdmi.output_bpc = bpc; - drm_dbg_kms(dev, + drm_info(dev, "Mode %ux%u @ %uHz: Found configuration: bpc: %u, fmt: %s, clock: %llu\n", mode->hdisplay, mode->vdisplay, drm_mode_vrefresh(mode), conn_state->hdmi.output_bpc, @@ -561,16 +563,16 @@ static int clear_device_infoframe(struct drm_connector *connector, struct drm_device *dev = connector->dev; int ret; - drm_dbg_kms(dev, "Clearing infoframe type 0x%x\n", type); + drm_info(dev, "Clearing infoframe type 0x%x\n", type); if (!funcs || !funcs->clear_infoframe) { - drm_dbg_kms(dev, "Function not implemented, bailing.\n"); + drm_info(dev, "Function not implemented, bailing.\n"); return 0; } ret = funcs->clear_infoframe(connector, type); if (ret) { - drm_dbg_kms(dev, "Call failed: %d\n", ret); + drm_info(dev, "Call failed: %d\n", ret); return ret; } @@ -598,10 +600,10 @@ static int write_device_infoframe(struct drm_connector *connector, int ret; int len; - drm_dbg_kms(dev, "Writing infoframe type %x\n", frame->any.type); + drm_info(dev, "Writing infoframe type %x\n", frame->any.type); if (!funcs || !funcs->write_infoframe) { - drm_dbg_kms(dev, "Function not implemented, bailing.\n"); + drm_info(dev, "Function not implemented, bailing.\n"); return -EINVAL; } @@ -611,7 +613,7 @@ static int write_device_infoframe(struct drm_connector *connector, ret = funcs->write_infoframe(connector, frame->any.type, buffer, len); if (ret) { - drm_dbg_kms(dev, "Call failed: %d\n", ret); + drm_info(dev, "Call failed: %d\n", ret); return ret; } diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c index 00a638a3caf4f2e7242ecb07fd399887fbaa99c5..a6f7315e059cf7a0b38211ef5b5530899394df65 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_common.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_common.c @@ -422,6 +422,8 @@ struct mtk_hdmi *mtk_hdmi_common_probe(struct platform_device *pdev) hdmi->bridge.product = "On-Chip HDMI"; hdmi->bridge.interlace_allowed = ver_conf->interlace_allowed; + hdmi->bridge.supported_formats = BIT(HDMI_COLORSPACE_RGB) | BIT(HDMI_COLORSPACE_YUV444); + ret = devm_drm_bridge_add(dev, &hdmi->bridge); if (ret) return dev_err_ptr_probe(dev, ret, "Failed to add bridge\n"); diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c index b411282d33e6fb249163e6245251141858ec69b1..1c798ee42597c6e9294e834f79c62ba72a41c642 100644 --- a/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c +++ b/drivers/gpu/drm/mediatek/mtk_hdmi_v2.c @@ -29,6 +29,7 @@ #include <drm/display/drm_hdmi_helper.h> #include <drm/display/drm_hdmi_state_helper.h> #include <drm/display/drm_scdc_helper.h> +#include <drm/drm_drv.h> #include <drm/drm_edid.h> #include <drm/drm_print.h> #include <drm/drm_probe_helper.h> @@ -259,22 +260,21 @@ static int mtk_hdmi_v2_setup_audio_infoframe(struct mtk_hdmi *hdmi) return 0; } -static inline void mtk_hdmi_v2_hw_reset_av_mute_regs(struct mtk_hdmi *hdmi) -{ - /* GCP packet */ - regmap_clear_bits(hdmi->regs, TOP_CFG01, CP_CLR_MUTE_EN | CP_SET_MUTE_EN); - regmap_clear_bits(hdmi->regs, TOP_INFO_RPT, CP_RPT_EN); - regmap_clear_bits(hdmi->regs, TOP_INFO_EN, CP_EN | CP_EN_WR); -} - static inline void mtk_hdmi_v2_hw_gcp_avmute(struct mtk_hdmi *hdmi, bool mute) { - mtk_hdmi_v2_hw_reset_av_mute_regs(hdmi); + u32 val; - if (mute) - regmap_set_bits(hdmi->regs, TOP_CFG01, CP_SET_MUTE_EN); - else - regmap_set_bits(hdmi->regs, TOP_CFG01, CP_CLR_MUTE_EN); + regmap_read(hdmi->regs, TOP_CFG01, &val); + val &= ~(CP_CLR_MUTE_EN | CP_SET_MUTE_EN); + + if (mute) { + val |= CP_SET_MUTE_EN; + val &= ~CP_CLR_MUTE_EN; + } else { + val |= CP_CLR_MUTE_EN; + val &= ~CP_SET_MUTE_EN; + } + regmap_write(hdmi->regs, TOP_CFG01, val); regmap_set_bits(hdmi->regs, TOP_INFO_RPT, CP_RPT_EN); regmap_set_bits(hdmi->regs, TOP_INFO_EN, CP_EN | CP_EN_WR); @@ -686,7 +686,10 @@ static void mtk_hdmi_v2_change_video_resolution(struct mtk_hdmi *hdmi) regmap_write(hdmi->regs, HDCP_TOP_CTRL, 0); - /* Enable HDCP reauthentication interrupt */ + /* + * Enable HDCP reauthentication interrupt: the HW uses this internally + * for the HPD state machine even if HDCP encryption is not enabled. + */ regmap_set_bits(hdmi->regs, TOP_INT_ENABLE00, HDCP2X_RX_REAUTH_REQ_DDCM_INT); /* Enable hotplug and pord interrupts */ @@ -781,14 +784,32 @@ static void mtk_hdmi_v2_clk_disable(struct mtk_hdmi *hdmi) clk_disable_unprepare(hdmi->clk[MTK_HDMI_V2_CLK_HDCP_SEL]); } -static void mtk_hdmi_hpd_event(enum hdmi_hpd_state hpd, struct device *dev) +static int mtk_hdmi_v2_reset_link(struct drm_bridge *bridge) { - struct mtk_hdmi *hdmi = dev_get_drvdata(dev); + struct drm_encoder *encoder = bridge->encoder; + struct drm_crtc *crtc = encoder->crtc; + struct drm_device *dev = encoder->dev; + struct drm_modeset_acquire_ctx ctx; + int ret; + + /* No crtc attached means no outputs to reset, don't do anything! */ + if (!crtc) { + pr_err("NO CRTC NO RESET :-)\n"); + return 0; + } - if (hdmi && hdmi->bridge.encoder && hdmi->bridge.encoder->dev) - drm_helper_hpd_irq_event(hdmi->bridge.encoder->dev); +pr_err("HDMI RESET LINK\n"); + + DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, ret); + + ret = drm_atomic_helper_reset_crtc(crtc, &ctx); + + DRM_MODESET_LOCK_ALL_END(dev, ctx, ret); + + return ret; } + static enum hdmi_hpd_state mtk_hdmi_v2_hpd_pord_status(struct mtk_hdmi *hdmi) { u8 hpd_pin_sta, pord_pin_sta; @@ -798,6 +819,21 @@ static enum hdmi_hpd_state mtk_hdmi_v2_hpd_pord_status(struct mtk_hdmi *hdmi) hpd_pin_sta = FIELD_GET(HPD_PIN_STA, hpd_status); pord_pin_sta = FIELD_GET(PORD_PIN_STA, hpd_status); + /* + * Inform that the cable is plugged in (hpd_pin_sta) so that the + * sink can be powered on by switching the 5V VBUS as required by + * the HDMI spec for reading EDID and for HDMI Audio registers to + * be accessible. + * + * PORD detection succeeds only when the cable is plugged in and + * the sink is powered on: reaching that state means that the + * communication with the sink can be started. + * + * Please note that when the cable is plugged out the HPD pin will + * be the first one to fall, while PORD may still be in rise state + * for a few more milliseconds, so we decide HDMI_PLUG_OUT without + * checking PORD at all (we check only HPD falling for that). + */ if (hpd_pin_sta && pord_pin_sta) return HDMI_PLUG_IN_AND_SINK_POWER_ON; else if (hpd_pin_sta) @@ -814,22 +850,19 @@ static irqreturn_t mtk_hdmi_v2_isr(int irq, void *arg) regmap_read(hdmi->regs, TOP_INT_STA00, &irq_sta); - /* Handle Hotplug Detection interrupt */ - if (irq_sta & (HTPLG_R_INT | HTPLG_F_INT | PORD_F_INT | PORD_R_INT)) { + /* Handle Hotplug Detection interrupts */ + if (irq_sta & HPD_PORD_HWIRQS) { + /* + * Disable the HPD/PORD IRQs now and until thread done to + * avoid interrupt storm that could happen with bad cables + */ mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, false); ret = IRQ_WAKE_THREAD; - } - - /* - * Clear all 32 + 19 interrupts in CLR00 and CLR01: this is important - * to avoid unwanted retriggering of any interrupts - */ - regmap_write(hdmi->regs, TOP_INT_CLR00, GENMASK(31, 0)); - regmap_write(hdmi->regs, TOP_INT_CLR01, GENMASK(18, 0)); - /* Restore interrupt clearing registers to zero */ - regmap_write(hdmi->regs, TOP_INT_CLR00, 0); - regmap_write(hdmi->regs, TOP_INT_CLR01, 0); + /* Clear HPD/PORD irqs to avoid unwanted retriggering */ + regmap_write(hdmi->regs, TOP_INT_CLR00, HPD_PORD_HWIRQS); + regmap_write(hdmi->regs, TOP_INT_CLR00, 0);; + } return ret; } @@ -840,8 +873,12 @@ static irqreturn_t __mtk_hdmi_v2_isr_thread(struct mtk_hdmi *hdmi) hpd = mtk_hdmi_v2_hpd_pord_status(hdmi); if (hpd != hdmi->hpd) { + struct drm_encoder *encoder = hdmi->bridge.encoder; + hdmi->hpd = hpd; - mtk_hdmi_hpd_event(hpd, hdmi->dev); + + if (encoder && encoder->dev) + drm_helper_hpd_irq_event(hdmi->bridge.encoder->dev); } mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, true); @@ -1049,10 +1086,38 @@ static void mtk_hdmi_v2_bridge_post_disable(struct drm_bridge *bridge, mtk_hdmi_v2_disable(hdmi); } + +static void mtk_hdmi_v2_hpd_notify(struct drm_bridge *bridge, + enum drm_connector_status status) +{ + //struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge); + +// if (status == connector_status_connected) +// mtk_hdmi_v2_reset_link(bridge); + + return; +} + static enum drm_connector_status mtk_hdmi_v2_bridge_detect(struct drm_bridge *bridge) { struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge); + switch (hdmi->hpd) { + default: + case HDMI_PLUG_IN_ONLY: +pr_err("UNKNOWN CONNECTOR STATUS\n"); + //return connector_status_unknown; + return connector_status_disconnected; + case HDMI_PLUG_OUT: +pr_err("PLUGOUT CONNECTOR STATUS\n"); + return connector_status_disconnected; + case HDMI_PLUG_IN_AND_SINK_POWER_ON: +pr_err("PLUGIN SINK POWERON CONNECTOR STATUS\n"); + return connector_status_connected; + } + + + return hdmi->hpd != HDMI_PLUG_OUT ? connector_status_connected : connector_status_disconnected; } @@ -1293,6 +1358,7 @@ static const struct drm_bridge_funcs mtk_v2_hdmi_bridge_funcs = { .edid_read = mtk_hdmi_v2_bridge_edid_read, .hpd_enable = mtk_hdmi_v2_hpd_enable, .hpd_disable = mtk_hdmi_v2_hpd_disable, + .hpd_notify = mtk_hdmi_v2_hpd_notify, .hdmi_tmds_char_rate_valid = mtk_hdmi_v2_hdmi_tmds_char_rate_valid, .hdmi_clear_infoframe = mtk_hdmi_v2_hdmi_clear_infoframe, .hdmi_write_infoframe = mtk_hdmi_v2_hdmi_write_infoframe, @@ -1420,13 +1486,26 @@ static int mtk_hdmi_v2_probe(struct platform_device *pdev) hdmi->hpd = HDMI_PLUG_OUT; + /* Disable all HW interrupts at probe stage */ + mtk_hdmi_v2_hwirq_disable(hdmi); + /* - * Disable all HW interrupts at probe stage and install the ISR - * but keep it disabled, as the rest of the interrupts setup is - * done in the .bridge_attach() callback, which will enable both - * the right HW IRQs and the ISR. + * In case bootloader leaves HDMI enabled before booting, make + * sure that any interrupt that was left is cleared by setting + * all bits in the INT_CLR registers for all 32+19 interrupts. + */ + regmap_write(hdmi->regs, TOP_INT_CLR00, GENMASK(31, 0)); + regmap_write(hdmi->regs, TOP_INT_CLR01, GENMASK(18, 0)); + + /* Restore interrupt clearing registers to zero */ + regmap_write(hdmi->regs, TOP_INT_CLR00, 0); + regmap_write(hdmi->regs, TOP_INT_CLR01, 0); + + /* + * Install the ISR but keep it disabled: as the interrupts are + * being set up in the .bridge_attach() callback which will + * enable both the right HW IRQs and the ISR. */ - mtk_hdmi_v2_hwirq_disable(hdmi); irq_set_status_flags(hdmi->irq, IRQ_NOAUTOEN); ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq, mtk_hdmi_v2_isr, mtk_hdmi_v2_isr_thread,