drm/vc4: hdmi: Reset HDMI MISC_CONTROL register
[platform/kernel/linux-rpi.git] / drivers / gpu / drm / vc4 / vc4_hdmi.c
index 9170d94..e16fece 100644 (file)
@@ -38,6 +38,7 @@
 #include <drm/drm_scdc_helper.h>
 #include <linux/clk.h>
 #include <linux/component.h>
+#include <linux/gpio/consumer.h>
 #include <linux/i2c.h>
 #include <linux/of_address.h>
 #include <linux/of_gpio.h>
@@ -78,6 +79,9 @@
 #define VC5_HDMI_VERTB_VSPO_SHIFT              16
 #define VC5_HDMI_VERTB_VSPO_MASK               VC4_MASK(29, 16)
 
+#define VC5_HDMI_MISC_CONTROL_PIXEL_REP_SHIFT  0
+#define VC5_HDMI_MISC_CONTROL_PIXEL_REP_MASK   VC4_MASK(3, 0)
+
 #define VC5_HDMI_SCRAMBLER_CTL_ENABLE          BIT(0)
 
 #define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT     8
@@ -172,9 +176,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
 
        WARN_ON(pm_runtime_resume_and_get(&vc4_hdmi->pdev->dev));
 
-       if (vc4_hdmi->hpd_gpio &&
-           gpiod_get_value_cansleep(vc4_hdmi->hpd_gpio)) {
-               connected = true;
+       if (vc4_hdmi->hpd_gpio) {
+               if (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) {
@@ -848,6 +852,11 @@ static void vc5_hdmi_set_timings(struct vc4_hdmi *vc4_hdmi,
        reg |= gcp_en ? VC5_HDMI_GCP_CONFIG_GCP_ENABLE : 0;
        HDMI_WRITE(HDMI_GCP_CONFIG, reg);
 
+       reg = HDMI_READ(HDMI_MISC_CONTROL);
+       reg &= ~VC5_HDMI_MISC_CONTROL_PIXEL_REP_MASK;
+       reg |= VC4_SET_FIELD(0, VC5_HDMI_MISC_CONTROL_PIXEL_REP);
+       HDMI_WRITE(HDMI_MISC_CONTROL, reg);
+
        HDMI_WRITE(HDMI_CLOCK_STOP, 0);
 }
 
@@ -1382,10 +1391,10 @@ static int vc4_hdmi_audio_prepare(struct device *dev, void *data,
 
        /* Set the MAI threshold */
        HDMI_WRITE(HDMI_MAI_THR,
-                  VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICHIGH) |
-                  VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_PANICLOW) |
-                  VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQHIGH) |
-                  VC4_SET_FIELD(0x10, VC4_HD_MAI_THR_DREQLOW));
+                  VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_PANICHIGH) |
+                  VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_PANICLOW) |
+                  VC4_SET_FIELD(0x06, VC4_HD_MAI_THR_DREQHIGH) |
+                  VC4_SET_FIELD(0x08, VC4_HD_MAI_THR_DREQLOW));
 
        HDMI_WRITE(HDMI_MAI_CONFIG,
                   VC4_HDMI_MAI_CONFIG_BIT_REVERSE |
@@ -1469,12 +1478,12 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
        struct device *dev = &vc4_hdmi->pdev->dev;
        struct platform_device *codec_pdev;
        const __be32 *addr;
-       int index;
+       int index, len;
        int ret;
 
-       if (!of_find_property(dev->of_node, "dmas", NULL)) {
+       if (!of_find_property(dev->of_node, "dmas", &len) || !len) {
                dev_warn(dev,
-                        "'dmas' DT property is missing, no HDMI audio\n");
+                        "'dmas' DT property is missing or empty, no HDMI audio\n");
                return 0;
        }
 
@@ -1522,6 +1531,7 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
                dev_err(dev, "Couldn't register the HDMI codec: %ld\n", PTR_ERR(codec_pdev));
                return PTR_ERR(codec_pdev);
        }
+       vc4_hdmi->audio.codec_pdev = codec_pdev;
 
        dai_link->cpus          = &vc4_hdmi->audio.cpu;
        dai_link->codecs        = &vc4_hdmi->audio.codec;
@@ -1561,6 +1571,12 @@ static int vc4_hdmi_audio_init(struct vc4_hdmi *vc4_hdmi)
 
 }
 
+static void vc4_hdmi_audio_exit(struct vc4_hdmi *vc4_hdmi)
+{
+       platform_device_unregister(vc4_hdmi->audio.codec_pdev);
+       vc4_hdmi->audio.codec_pdev = NULL;
+}
+
 static irqreturn_t vc4_hdmi_hpd_irq_thread(int irq, void *priv)
 {
        struct vc4_hdmi *vc4_hdmi = priv;
@@ -2298,6 +2314,7 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master,
        kfree(vc4_hdmi->hdmi_regset.regs);
        kfree(vc4_hdmi->hd_regset.regs);
 
+       vc4_hdmi_audio_exit(vc4_hdmi);
        vc4_hdmi_cec_exit(vc4_hdmi);
        vc4_hdmi_hotplug_exit(vc4_hdmi);
        vc4_hdmi_connector_destroy(&vc4_hdmi->connector);