Re: [PATCH v2] drm/meson: add mode selection limits against specific SoC revisions

From: Neil Armstrong
Date: Tue May 05 2020 - 04:33:32 EST


On 28/04/2020 11:21, Neil Armstrong wrote:
> 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 <narmstrong@xxxxxxxxxxxx>
> ---
> 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,
>

Applied to drm-misc-next with commit log fixup