drm/rockchip: inno_hdmi: add rk3128 hdmi support

Change-Id: I929880020f4a72e61d21b7af4d73a98da337b10b
Signed-off-by: Huicong Xu <xhc@rock-chips.com>
This commit is contained in:
xuhuicong
2017-10-27 11:20:50 +08:00
committed by Tao Huang
parent 9064923799
commit 4f379e1892
2 changed files with 73 additions and 19 deletions

View File

@@ -4,6 +4,7 @@ Rockchip specific extensions to the Innosilicon HDMI
Required properties:
- compatible:
"rockchip,rk3036-inno-hdmi";
"rockchip,rk3128-inno-hdmi";
- reg:
Physical base address and length of the controller's registers.
- clocks, clock-names:

View File

@@ -64,6 +64,22 @@ struct inno_hdmi_i2c {
struct completion cmp;
};
enum inno_hdmi_dev_type {
RK3036_HDMI,
RK3128_HDMI,
};
struct inno_hdmi_phy_config {
unsigned long mpixelclock;
u8 pre_emphasis; /* pre-emphasis value */
u8 vlev_ctr; /* voltage level control */
};
struct inno_hdmi_plat_data {
enum inno_hdmi_dev_type dev_type;
struct inno_hdmi_phy_config *phy_config;
};
struct inno_hdmi {
struct device *dev;
struct drm_device *drm_dev;
@@ -81,6 +97,7 @@ struct inno_hdmi {
struct i2c_adapter *ddc;
unsigned int tmds_rate;
const struct inno_hdmi_plat_data *plat_data;
struct platform_device *audio_pdev;
bool audio_enable;
@@ -211,17 +228,20 @@ static void inno_hdmi_sys_power(struct inno_hdmi *hdmi, bool enable)
static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode)
{
u8 value;
const struct inno_hdmi_phy_config *phy_config =
hdmi->plat_data->phy_config;
switch (mode) {
case NORMAL:
inno_hdmi_sys_power(hdmi, false);
if (hdmi->tmds_rate > 140000000)
value = 0x6f;
else
value = 0x3f;
hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS, value);
hdmi_writeb(hdmi, HDMI_PHY_DRIVER, 0xbb);
for (; phy_config->mpixelclock != ~0UL; phy_config++)
if (hdmi->tmds_rate <= phy_config->mpixelclock)
break;
if (!phy_config->mpixelclock)
return;
hdmi_writeb(hdmi, HDMI_PHY_PRE_EMPHASIS,
phy_config->pre_emphasis);
hdmi_writeb(hdmi, HDMI_PHY_DRIVER, phy_config->vlev_ctr);
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x15);
hdmi_writeb(hdmi, HDMI_PHY_SYS_CTL, 0x14);
@@ -427,11 +447,12 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
{
int value;
value = BIT(20) | BIT(21);
value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BIT(4) : 0;
value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BIT(5) : 0;
regmap_write(hdmi->regmap, 0x148, value);
if (hdmi->plat_data->dev_type == RK3036_HDMI) {
value = BIT(20) | BIT(21);
value |= mode->flags & DRM_MODE_FLAG_PHSYNC ? BIT(4) : 0;
value |= mode->flags & DRM_MODE_FLAG_PVSYNC ? BIT(5) : 0;
regmap_write(hdmi->regmap, 0x148, value);
}
/* Set detail external video timing polarity and interlace mode */
value = v_EXTERANL_VIDEO(1);
value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
@@ -1039,11 +1060,47 @@ static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
return adap;
}
static struct inno_hdmi_phy_config rk3036_hdmi_phy_config[] = {
/* pixelclk pre-emp vlev */
{ 74250000, 0x3f, 0xbb },
{ 165000000, 0x6f, 0xbb },
{ ~0UL, 0x00, 0x00 }
};
static struct inno_hdmi_phy_config rk3128_hdmi_phy_config[] = {
/* pixelclk pre-emp vlev */
{ 74250000, 0x3f, 0xaa },
{ 165000000, 0x5f, 0xaa },
{ ~0UL, 0x00, 0x00 }
};
static const struct inno_hdmi_plat_data rk3036_hdmi_drv_data = {
.dev_type = RK3036_HDMI,
.phy_config = rk3036_hdmi_phy_config,
};
static const struct inno_hdmi_plat_data rk3128_hdmi_drv_data = {
.dev_type = RK3128_HDMI,
.phy_config = rk3128_hdmi_phy_config,
};
static const struct of_device_id inno_hdmi_dt_ids[] = {
{ .compatible = "rockchip,rk3036-inno-hdmi",
.data = &rk3036_hdmi_drv_data,
},
{ .compatible = "rockchip,rk3128-inno-hdmi",
.data = &rk3128_hdmi_drv_data,
},
{},
};
MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids);
static int inno_hdmi_bind(struct device *dev, struct device *master,
void *data)
{
struct platform_device *pdev = to_platform_device(dev);
struct drm_device *drm = data;
const struct of_device_id *match;
struct inno_hdmi *hdmi;
struct resource *iores;
int irq;
@@ -1056,6 +1113,9 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
hdmi->dev = dev;
hdmi->drm_dev = drm;
match = of_match_node(inno_hdmi_dt_ids, pdev->dev.of_node);
hdmi->plat_data = match->data;
iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!iores)
return -ENXIO;
@@ -1177,13 +1237,6 @@ static int inno_hdmi_remove(struct platform_device *pdev)
return 0;
}
static const struct of_device_id inno_hdmi_dt_ids[] = {
{ .compatible = "rockchip,rk3036-inno-hdmi",
},
{},
};
MODULE_DEVICE_TABLE(of, inno_hdmi_dt_ids);
static struct platform_driver inno_hdmi_driver = {
.probe = inno_hdmi_probe,
.remove = inno_hdmi_remove,