Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/meson: add mode selection limits against specific SoC revisions

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.2a 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@baylibre.com>
Acked-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
[narmstrong: fixed commit message with HDMI 1.2a instead of HDMI 1.3a]
Link: https://patchwork.freedesktop.org/patch/msgid/20200428092147.13698-1-narmstrong@baylibre.com

+52 -4
+28 -1
drivers/gpu/drm/meson/meson_drv.c
··· 11 11 #include <linux/component.h> 12 12 #include <linux/module.h> 13 13 #include <linux/of_graph.h> 14 + #include <linux/sys_soc.h> 14 15 #include <linux/platform_device.h> 15 16 #include <linux/soc/amlogic/meson-canvas.h> 16 17 ··· 184 183 kfree(ap); 185 184 } 186 185 186 + struct meson_drm_soc_attr { 187 + struct meson_drm_soc_limits limits; 188 + const struct soc_device_attribute *attrs; 189 + }; 190 + 191 + static const struct meson_drm_soc_attr meson_drm_soc_attrs[] = { 192 + /* S805X/S805Y HDMI PLL won't lock for HDMI PHY freq > 1,65GHz */ 193 + { 194 + .limits = { 195 + .max_hdmi_phy_freq = 1650000, 196 + }, 197 + .attrs = (const struct soc_device_attribute []) { 198 + { .soc_id = "GXL (S805*)", }, 199 + { /* sentinel */ }, 200 + } 201 + }, 202 + }; 203 + 187 204 static int meson_drv_bind_master(struct device *dev, bool has_components) 188 205 { 189 206 struct platform_device *pdev = to_platform_device(dev); ··· 210 191 struct drm_device *drm; 211 192 struct resource *res; 212 193 void __iomem *regs; 213 - int ret; 194 + int ret, i; 214 195 215 196 /* Checks if an output connector is available */ 216 197 if (!meson_vpu_has_available_connectors(dev)) { ··· 299 280 ret = drm_vblank_init(drm, 1); 300 281 if (ret) 301 282 goto free_drm; 283 + 284 + /* Assign limits per soc revision/package */ 285 + for (i = 0 ; i < ARRAY_SIZE(meson_drm_soc_attrs) ; ++i) { 286 + if (soc_device_match(meson_drm_soc_attrs[i].attrs)) { 287 + priv->limits = &meson_drm_soc_attrs[i].limits; 288 + break; 289 + } 290 + } 302 291 303 292 /* Remove early framebuffers (ie. simplefb) */ 304 293 meson_remove_framebuffers();
+6
drivers/gpu/drm/meson/meson_drv.h
··· 30 30 struct meson_afbcd_ops *afbcd_ops; 31 31 }; 32 32 33 + struct meson_drm_soc_limits { 34 + unsigned int max_hdmi_phy_freq; 35 + }; 36 + 33 37 struct meson_drm { 34 38 struct device *dev; 35 39 enum vpu_compatible compat; ··· 51 47 struct drm_crtc *crtc; 52 48 struct drm_plane *primary_plane; 53 49 struct drm_plane *overlay_plane; 50 + 51 + const struct meson_drm_soc_limits *limits; 54 52 55 53 /* Components Data */ 56 54 struct {
+1 -1
drivers/gpu/drm/meson/meson_dw_hdmi.c
··· 695 695 dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n", 696 696 __func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); 697 697 698 - return meson_vclk_vic_supported_freq(phy_freq, vclk_freq); 698 + return meson_vclk_vic_supported_freq(priv, phy_freq, vclk_freq); 699 699 } 700 700 701 701 /* Encoder */
+15 -1
drivers/gpu/drm/meson/meson_vclk.c
··· 725 725 /* In DMT mode, path after PLL is always /10 */ 726 726 freq *= 10; 727 727 728 + /* Check against soc revision/package limits */ 729 + if (priv->limits) { 730 + if (priv->limits->max_hdmi_phy_freq && 731 + freq > priv->limits->max_hdmi_phy_freq) 732 + return MODE_CLOCK_HIGH; 733 + } 734 + 728 735 if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od)) 729 736 return MODE_OK; 730 737 ··· 769 762 } 770 763 771 764 enum drm_mode_status 772 - meson_vclk_vic_supported_freq(unsigned int phy_freq, 765 + meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, 773 766 unsigned int vclk_freq) 774 767 { 775 768 int i; 776 769 777 770 DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n", 778 771 phy_freq, vclk_freq); 772 + 773 + /* Check against soc revision/package limits */ 774 + if (priv->limits) { 775 + if (priv->limits->max_hdmi_phy_freq && 776 + phy_freq > priv->limits->max_hdmi_phy_freq) 777 + return MODE_CLOCK_HIGH; 778 + } 779 779 780 780 for (i = 0 ; params[i].pixel_freq ; ++i) { 781 781 DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
+2 -1
drivers/gpu/drm/meson/meson_vclk.h
··· 25 25 enum drm_mode_status 26 26 meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); 27 27 enum drm_mode_status 28 - meson_vclk_vic_supported_freq(unsigned int phy_freq, unsigned int vclk_freq); 28 + meson_vclk_vic_supported_freq(struct meson_drm *priv, unsigned int phy_freq, 29 + unsigned int vclk_freq); 29 30 30 31 void meson_vclk_setup(struct meson_drm *priv, unsigned int target, 31 32 unsigned int phy_freq, unsigned int vclk_freq,