Skip to content
Snippets Groups Projects
Unverified Commit d8f4c4a7 authored by AngeloGioacchino Del Regno's avatar AngeloGioacchino Del Regno
Browse files

hdmi fixes and tests

parent 3b17c742
No related branches found
No related tags found
No related merge requests found
Pipeline #131359 failed
......@@ -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;
}
......
......@@ -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");
......
......@@ -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;
if (hdmi && hdmi->bridge.encoder && hdmi->bridge.encoder->dev)
drm_helper_hpd_irq_event(hdmi->bridge.encoder->dev);
/* No crtc attached means no outputs to reset, don't do anything! */
if (!crtc) {
pr_err("NO CRTC NO RESET :-)\n");
return 0;
}
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)) {
mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, false);
ret = IRQ_WAKE_THREAD;
}
/* Handle Hotplug Detection interrupts */
if (irq_sta & HPD_PORD_HWIRQS) {
/*
* Clear all 32 + 19 interrupts in CLR00 and CLR01: this is important
* to avoid unwanted retriggering of any interrupts
* Disable the HPD/PORD IRQs now and until thread done to
* avoid interrupt storm that could happen with bad cables
*/
regmap_write(hdmi->regs, TOP_INT_CLR00, GENMASK(31, 0));
regmap_write(hdmi->regs, TOP_INT_CLR01, GENMASK(18, 0));
mtk_hdmi_v2_enable_hpd_pord_irq(hdmi, false);
ret = IRQ_WAKE_THREAD;
/* 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,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment