Commit 5f2e93e6 authored by Alex Bee's avatar Alex Bee Committed by Heiko Stuebner

drm/rockchip: inno_hdmi: Add variant support

In preparation to support RK3128's integration of the controller, this
patch adds a simple variant implementation. They mainly differ in the phy
configuration required, so those are part of the match_data. The values
have been taken from downstream. The pixelclocks in there are meant to be
max-inclusive.
Signed-off-by: default avatarAlex Bee <knaerzche@gmail.com>
Signed-off-by: default avatarHeiko Stuebner <heiko@sntech.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20231222174220.55249-24-knaerzche@gmail.com
parent bb056046
...@@ -25,6 +25,17 @@ ...@@ -25,6 +25,17 @@
#include "inno_hdmi.h" #include "inno_hdmi.h"
struct inno_hdmi_phy_config {
unsigned long pixelclock;
u8 pre_emphasis;
u8 voltage_level_control;
};
struct inno_hdmi_variant {
struct inno_hdmi_phy_config *phy_configs;
struct inno_hdmi_phy_config *default_phy_config;
};
struct inno_hdmi_i2c { struct inno_hdmi_i2c {
struct i2c_adapter adap; struct i2c_adapter adap;
...@@ -46,6 +57,8 @@ struct inno_hdmi { ...@@ -46,6 +57,8 @@ struct inno_hdmi {
struct inno_hdmi_i2c *i2c; struct inno_hdmi_i2c *i2c;
struct i2c_adapter *ddc; struct i2c_adapter *ddc;
const struct inno_hdmi_variant *variant;
}; };
struct inno_hdmi_connector_state { struct inno_hdmi_connector_state {
...@@ -112,6 +125,30 @@ static const char coeff_csc[][24] = { ...@@ -112,6 +125,30 @@ static const char coeff_csc[][24] = {
}, },
}; };
static struct inno_hdmi_phy_config rk3036_hdmi_phy_configs[] = {
{ 74250000, 0x3f, 0xbb },
{ 165000000, 0x6f, 0xbb },
{ ~0UL, 0x00, 0x00 }
};
static int inno_hdmi_find_phy_config(struct inno_hdmi *hdmi,
unsigned long pixelclk)
{
const struct inno_hdmi_phy_config *phy_configs =
hdmi->variant->phy_configs;
int i;
for (i = 0; phy_configs[i].pixelclock != ~0UL; i++) {
if (pixelclk <= phy_configs[i].pixelclock)
return i;
}
DRM_DEV_DEBUG(hdmi->dev, "No phy configuration for pixelclock %lu\n",
pixelclk);
return -EINVAL;
}
static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset) static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset)
{ {
return readl_relaxed(hdmi->regs + (offset) * 0x04); return readl_relaxed(hdmi->regs + (offset) * 0x04);
...@@ -163,12 +200,25 @@ static void inno_hdmi_standby(struct inno_hdmi *hdmi) ...@@ -163,12 +200,25 @@ static void inno_hdmi_standby(struct inno_hdmi *hdmi)
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
}; };
static void inno_hdmi_power_up(struct inno_hdmi *hdmi) static void inno_hdmi_power_up(struct inno_hdmi *hdmi,
unsigned long mpixelclock)
{ {
struct inno_hdmi_phy_config *phy_config;
int ret = inno_hdmi_find_phy_config(hdmi, mpixelclock);
if (ret < 0) {
phy_config = hdmi->variant->default_phy_config;
DRM_DEV_ERROR(hdmi->dev,
"Using default phy configuration for TMDS rate %lu",
mpixelclock);
} else {
phy_config = &hdmi->variant->phy_configs[ret];
}
inno_hdmi_sys_power(hdmi, false); inno_hdmi_sys_power(hdmi, false);
hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, 0x6f); hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, phy_config->pre_emphasis);
hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb); hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->voltage_level_control);
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10); hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x10);
...@@ -405,6 +455,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, ...@@ -405,6 +455,7 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
struct drm_display_mode *mode) struct drm_display_mode *mode)
{ {
struct drm_display_info *display = &hdmi->connector.display_info; struct drm_display_info *display = &hdmi->connector.display_info;
unsigned long mpixelclock = mode->clock * 1000;
/* Mute video and audio output */ /* Mute video and audio output */
hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
...@@ -427,13 +478,13 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi, ...@@ -427,13 +478,13 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
* DCLK_LCDC, so we need to init the TMDS rate to mode pixel * DCLK_LCDC, so we need to init the TMDS rate to mode pixel
* clock rate, and reconfigure the DDC clock. * clock rate, and reconfigure the DDC clock.
*/ */
inno_hdmi_i2c_init(hdmi, mode->clock * 1000); inno_hdmi_i2c_init(hdmi, mpixelclock);
/* Unmute video and audio output */ /* Unmute video and audio output */
hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK, hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE | m_VIDEO_BLACK,
v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0)); v_AUDIO_MUTE(0) | v_VIDEO_MUTE(0));
inno_hdmi_power_up(hdmi); inno_hdmi_power_up(hdmi, mpixelclock);
return 0; return 0;
} }
...@@ -825,6 +876,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, ...@@ -825,6 +876,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
struct platform_device *pdev = to_platform_device(dev); struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = data; struct drm_device *drm = data;
struct inno_hdmi *hdmi; struct inno_hdmi *hdmi;
const struct inno_hdmi_variant *variant;
int irq; int irq;
int ret; int ret;
...@@ -834,6 +886,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master, ...@@ -834,6 +886,12 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
hdmi->dev = dev; hdmi->dev = dev;
variant = of_device_get_match_data(hdmi->dev);
if (!variant)
return -EINVAL;
hdmi->variant = variant;
hdmi->regs = devm_platform_ioremap_resource(pdev, 0); hdmi->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(hdmi->regs)) if (IS_ERR(hdmi->regs))
return PTR_ERR(hdmi->regs); return PTR_ERR(hdmi->regs);
...@@ -927,8 +985,14 @@ static void inno_hdmi_remove(struct platform_device *pdev) ...@@ -927,8 +985,14 @@ static void inno_hdmi_remove(struct platform_device *pdev)
component_del(&pdev->dev, &inno_hdmi_ops); component_del(&pdev->dev, &inno_hdmi_ops);
} }
static const struct inno_hdmi_variant rk3036_inno_hdmi_variant = {
.phy_configs = rk3036_hdmi_phy_configs,
.default_phy_config = &rk3036_hdmi_phy_configs[1],
};
static const struct of_device_id inno_hdmi_dt_ids[] = { static const struct of_device_id inno_hdmi_dt_ids[] = {
{ .compatible = "rockchip,rk3036-inno-hdmi", { .compatible = "rockchip,rk3036-inno-hdmi",
.data = &rk3036_inno_hdmi_variant,
}, },
{}, {},
}; };
......
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