Commit 8976eeee authored by Neil Armstrong's avatar Neil Armstrong

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: default avatarNeil Armstrong <narmstrong@baylibre.com>
Acked-by: default avatarMartin 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
parent e7f12054
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/component.h> #include <linux/component.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_graph.h> #include <linux/of_graph.h>
#include <linux/sys_soc.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/soc/amlogic/meson-canvas.h> #include <linux/soc/amlogic/meson-canvas.h>
...@@ -183,6 +184,24 @@ static void meson_remove_framebuffers(void) ...@@ -183,6 +184,24 @@ static void meson_remove_framebuffers(void)
kfree(ap); 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) static int meson_drv_bind_master(struct device *dev, bool has_components)
{ {
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
...@@ -191,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) ...@@ -191,7 +210,7 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
struct drm_device *drm; struct drm_device *drm;
struct resource *res; struct resource *res;
void __iomem *regs; void __iomem *regs;
int ret; int ret, i;
/* Checks if an output connector is available */ /* Checks if an output connector is available */
if (!meson_vpu_has_available_connectors(dev)) { if (!meson_vpu_has_available_connectors(dev)) {
...@@ -281,6 +300,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components) ...@@ -281,6 +300,14 @@ static int meson_drv_bind_master(struct device *dev, bool has_components)
if (ret) if (ret)
goto free_drm; 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) */ /* Remove early framebuffers (ie. simplefb) */
meson_remove_framebuffers(); meson_remove_framebuffers();
......
...@@ -30,6 +30,10 @@ struct meson_drm_match_data { ...@@ -30,6 +30,10 @@ struct meson_drm_match_data {
struct meson_afbcd_ops *afbcd_ops; struct meson_afbcd_ops *afbcd_ops;
}; };
struct meson_drm_soc_limits {
unsigned int max_hdmi_phy_freq;
};
struct meson_drm { struct meson_drm {
struct device *dev; struct device *dev;
enum vpu_compatible compat; enum vpu_compatible compat;
...@@ -48,6 +52,8 @@ struct meson_drm { ...@@ -48,6 +52,8 @@ struct meson_drm {
struct drm_plane *primary_plane; struct drm_plane *primary_plane;
struct drm_plane *overlay_plane; struct drm_plane *overlay_plane;
const struct meson_drm_soc_limits *limits;
/* Components Data */ /* Components Data */
struct { struct {
bool osd1_enabled; bool osd1_enabled;
......
...@@ -695,7 +695,7 @@ dw_hdmi_mode_valid(struct drm_connector *connector, ...@@ -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", dev_dbg(connector->dev->dev, "%s: vclk:%d phy=%d venc=%d hdmi=%d\n",
__func__, phy_freq, vclk_freq, venc_freq, hdmi_freq); __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 */ /* Encoder */
......
...@@ -725,6 +725,13 @@ meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq) ...@@ -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 */ /* In DMT mode, path after PLL is always /10 */
freq *= 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)) if (meson_hdmi_pll_find_params(priv, freq, &m, &frac, &od))
return MODE_OK; return MODE_OK;
...@@ -762,7 +769,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv, ...@@ -762,7 +769,7 @@ static void meson_hdmi_pll_generic_set(struct meson_drm *priv,
} }
enum drm_mode_status 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) unsigned int vclk_freq)
{ {
int i; int i;
...@@ -770,6 +777,13 @@ meson_vclk_vic_supported_freq(unsigned int phy_freq, ...@@ -770,6 +777,13 @@ meson_vclk_vic_supported_freq(unsigned int phy_freq,
DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n", DRM_DEBUG_DRIVER("phy_freq = %d vclk_freq = %d\n",
phy_freq, vclk_freq); 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) { for (i = 0 ; params[i].pixel_freq ; ++i) {
DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n", DRM_DEBUG_DRIVER("i = %d pixel_freq = %d alt = %d\n",
i, params[i].pixel_freq, i, params[i].pixel_freq,
......
...@@ -25,7 +25,8 @@ enum { ...@@ -25,7 +25,8 @@ enum {
enum drm_mode_status enum drm_mode_status
meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq); meson_vclk_dmt_supported_freq(struct meson_drm *priv, unsigned int freq);
enum drm_mode_status 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, void meson_vclk_setup(struct meson_drm *priv, unsigned int target,
unsigned int phy_freq, unsigned int vclk_freq, unsigned int phy_freq, unsigned int vclk_freq,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment