The Amlogic S805X/Y uses the same die as the S905X, but with more
limited graphics capabilities.

This adds a soc version detection adding specific limitations on the HDMI
mode selections.

Here, we limit to HDMI 1.3a max HDMI PHY clock frequency.

Changes sinces v1:
- Moved frequency check in the vclk code, and also checks DMT modes

Signed-off-by: Neil Armstrong <narmstr...@baylibre.com>
---
 drivers/gpu/drm/meson/meson_drv.c     | 29 ++++++++++++++++++++++++++-
 drivers/gpu/drm/meson/meson_drv.h     |  6 ++++++
 drivers/gpu/drm/meson/meson_dw_hdmi.c |  2 +-
 drivers/gpu/drm/meson/meson_vclk.c    | 16 ++++++++++++++-
 drivers/gpu/drm/meson/meson_vclk.h    |  3 ++-
 5 files changed, 52 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/meson/meson_drv.c 
b/drivers/gpu/drm/meson/meson_drv.c
index 6f29fab79952..621f6de0f076 100644
--- a/drivers/gpu/drm/meson/meson_drv.c
+++ b/drivers/gpu/drm/meson/meson_drv.c
@@ -11,6 +11,7 @@
 #include <linux/component.h>
 #include <linux/module.h>
 #include <linux/of_graph.h>
+#include <linux/sys_soc.h>
 #include <linux/platform_device.h>
 #include <linux/soc/amlogic/meson-canvas.h>
 
@@ -183,6 +184,24 @@ static void meson_remove_framebuffers(void)
        kfree(ap);
 }
 
+struct meson_drm_soc_attr {
+       struct meson_drm_soc_limits limits;
+       const struct soc_device_attribute *attrs;
+};
+
+static const struct meson_drm_soc_attr meson_drm_soc_attrs[] = {
+       /* S805X/S805Y HDMI PLL won't lock for HDMI PHY freq > 1,65GHz */
+       {
+               .limits = {
+                       .max_hdmi_phy_freq = 1650000,
+               },
+               .attrs = (const struct soc_device_attribute []) {
+                       { .soc_id = "GXL (S805*)", },
+                       { /* sentinel */ },
+               }
+       },
+};
+
 static int meson_drv_bind_master(struct device *dev, bool has_components)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -191,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool 
has_components)
        struct drm_device *drm;
        struct resource *res;
        void __iomem *regs;
-       int ret;
+       int ret, i;
 
        /* Checks if an output connector is available */
        if (!meson_vpu_has_available_connectors(dev)) {
@@ -281,6 +300,14 @@ static int meson_drv_bind_master(struct device *dev, bool 
has_components)
        if (ret)
                goto free_drm;
 
+       /* Assign limits per soc revision/package */
+       for (i = 0 ; i < ARRAY_SIZE(meson_drm_soc_attrs) ; ++i) {
+               if (soc_device_match(meson_drm_soc_attrs[i].attrs)) {
+                       priv->limits = &meson_drm_soc_attrs[i].limits;
+                       break;
+               }
+       }
+
        /* Remove early framebuffers (ie. simplefb) */
        meson_remove_framebuffers();
 
diff --git a/drivers/gpu/drm/meson/meson_drv.h 
b/drivers/gpu/drm/meson/meson_drv.h
index 04fdf3826643..5b23704a80d6 100644
--- a/drivers/gpu/drm/meson/meson_drv.h
+++ b/drivers/gpu/drm/meson/meson_drv.h
@@ -30,6 +30,10 @@ struct meson_drm_match_data {
        struct meson_afbcd_ops *afbcd_ops;
 };
 
+struct meson_drm_soc_limits {
+       unsigned int max_hdmi_phy_freq;
+};
+
 struct meson_drm {
        struct device *dev;
        enum vpu_compatible compat;
@@ -48,6 +52,8 @@ struct meson_drm {
        struct drm_plane *primary_plane;
        struct drm_plane *overlay_plane;
 
+       const struct meson_drm_soc_limits *limits;
+
        /* Components Data */
        struct {
                bool osd1_enabled;
diff --git a/drivers/gpu/drm/meson/meson_dw_hdmi.c 
b/drivers/gpu/drm/meson/meson_dw_hdmi.c
index e8c94915a4fc..5be963e9db05 100644
--- a/drivers/gpu/drm/meson/meson_dw_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_dw_hdmi.c
@@ -695,7 +695,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector,
        dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
                __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq);
 
-       return meson_vclk_vic_supported_freq(phy_freq, vclk_freq);
+       return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq);
 }
 
 /* Encoder */
diff --git a/drivers/gpu/drm/meson/meson_vclk.c 
b/drivers/gpu/drm/meson/meson_vclk.c
index fdf26dac9fa8..0eb86943a358 100644
--- a/drivers/gpu/drm/meson/meson_vclk.c
+++ b/drivers/gpu/drm/meson/meson_vclk.c
@@ -725,6 +725,13 @@ meson_vclk_dmt_supported_freq(struct meson_drm *priv, 
unsigned int freq)
        /* In DMT mode, path after PLL is always /10 */
        freq *= 10;
 
+       /* Check against soc revision/package limits */
+       if (priv->limits) {
+               if (priv->limits->max_hdmi_phy_freq &&
+                   freq > priv->limits->max_hdmi_phy_freq)
+                       return MODE_CLOCK_HIGH;
+       }
+
        if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
                return MODE_OK;
 
@@ -762,7 +769,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm 
*priv,
 }
 
 enum drm_mode_status
-meson_vclk_vic_supported_freq(unsigned int phy_freq,
+meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq,
                              unsigned int vclk_freq)
 {
        int i;
@@ -770,6 +777,13 @@ meson_vclk_vic_supported_freq(unsigned int phy_freq,
        DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n",
                         phy_freq, vclk_freq);
 
+       /* Check against soc revision/package limits */
+       if (priv->limits) {
+               if (priv->limits->max_hdmi_phy_freq &&
+                   phy_freq > priv->limits->max_hdmi_phy_freq)
+                       return MODE_CLOCK_HIGH;
+       }
+
        for (i = 0 ; params[i].pixel_freq ; ++i) {
                DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
                                 i, params[i].pixel_freq,
diff --git a/drivers/gpu/drm/meson/meson_vclk.h 
b/drivers/gpu/drm/meson/meson_vclk.h
index aed0ab2efa71..60617aaf18dd 100644
--- a/drivers/gpu/drm/meson/meson_vclk.h
+++ b/drivers/gpu/drm/meson/meson_vclk.h
@@ -25,7 +25,8 @@ enum {
 enum drm_mode_status
 meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
 enum drm_mode_status
-meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq);
+meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq,
+                             unsigned int vclk_freq);
 
 void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
                      unsigned int phy_freq, unsigned int vclk_freq,
-- 
2.22.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to