Merge branch 'drm-dwhdmi-devel' of git://ftp.arm.linux.org.uk/~rmk/linux-arm into drm-next
This set of patches adjust the setup of the HDMI CTS/N values for audio support to be compliant with the work-around given in the iMX6 errata documentation as part of the preparation for integrating audio support for this driver, and also update the HDMI phy configuration for Rockchip devices to improve the HDMI eye pattern. * 'drm-dwhdmi-devel' of git://ftp.arm.linux.org.uk/~rmk/linux-arm: drm: rockchip/dw_hdmi-rockchip: improve for HDMI electrical test drm: bridge/dw_hdmi: separate VLEVCTRL settting into platform driver drm: bridge/dw_hdmi: fixed codec style drm: bridge/dw_hdmi: adjust n/cts setting order drm: bridge/dw_hdmi: protect n/cts setting with a mutex drm: bridge/dw_hdmi: combine hdmi_set_clock_regenerator_n() and hdmi_regenerate_cts() Conflicts: drivers/gpu/drm/imx/dw_hdmi-imx.c
This commit is contained in:
Коммит
52139bdea1
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/hdmi.h>
|
#include <linux/hdmi.h>
|
||||||
|
#include <linux/mutex.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
|
|
||||||
#include <drm/drm_of.h>
|
#include <drm/drm_of.h>
|
||||||
|
@ -126,6 +127,7 @@ struct dw_hdmi {
|
||||||
struct i2c_adapter *ddc;
|
struct i2c_adapter *ddc;
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
|
|
||||||
|
struct mutex audio_mutex;
|
||||||
unsigned int sample_rate;
|
unsigned int sample_rate;
|
||||||
int ratio;
|
int ratio;
|
||||||
|
|
||||||
|
@ -177,26 +179,23 @@ static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
|
||||||
hdmi_modb(hdmi, data << shift, mask, reg);
|
hdmi_modb(hdmi, data << shift, mask, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
|
static void hdmi_set_cts_n(struct dw_hdmi *hdmi, unsigned int cts,
|
||||||
unsigned int value)
|
unsigned int n)
|
||||||
{
|
|
||||||
hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
|
|
||||||
hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
|
|
||||||
hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
|
|
||||||
|
|
||||||
/* nshift factor = 0 */
|
|
||||||
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
|
|
||||||
{
|
{
|
||||||
/* Must be set/cleared first */
|
/* Must be set/cleared first */
|
||||||
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||||
|
|
||||||
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
|
/* nshift factor = 0 */
|
||||||
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
|
hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
|
||||||
|
|
||||||
hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
|
||||||
HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
|
||||||
|
hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
|
||||||
|
hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
|
||||||
|
|
||||||
|
hdmi_writeb(hdmi, (n >> 16) & 0x0f, HDMI_AUD_N3);
|
||||||
|
hdmi_writeb(hdmi, (n >> 8) & 0xff, HDMI_AUD_N2);
|
||||||
|
hdmi_writeb(hdmi, n & 0xff, HDMI_AUD_N1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
|
static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
|
||||||
|
@ -355,18 +354,21 @@ static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
|
||||||
__func__, hdmi->sample_rate, hdmi->ratio,
|
__func__, hdmi->sample_rate, hdmi->ratio,
|
||||||
pixel_clk, clk_n, clk_cts);
|
pixel_clk, clk_n, clk_cts);
|
||||||
|
|
||||||
hdmi_set_clock_regenerator_n(hdmi, clk_n);
|
hdmi_set_cts_n(hdmi, clk_cts, clk_n);
|
||||||
hdmi_regenerate_cts(hdmi, clk_cts);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
|
static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
|
||||||
{
|
{
|
||||||
|
mutex_lock(&hdmi->audio_mutex);
|
||||||
hdmi_set_clk_regenerator(hdmi, 74250000);
|
hdmi_set_clk_regenerator(hdmi, 74250000);
|
||||||
|
mutex_unlock(&hdmi->audio_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
|
static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
|
||||||
{
|
{
|
||||||
|
mutex_lock(&hdmi->audio_mutex);
|
||||||
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
|
hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
|
||||||
|
mutex_unlock(&hdmi->audio_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -753,10 +755,10 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
|
||||||
{
|
{
|
||||||
unsigned res_idx, i;
|
unsigned res_idx, i;
|
||||||
u8 val, msec;
|
u8 val, msec;
|
||||||
const struct dw_hdmi_mpll_config *mpll_config =
|
const struct dw_hdmi_plat_data *plat_data = hdmi->plat_data;
|
||||||
hdmi->plat_data->mpll_cfg;
|
const struct dw_hdmi_mpll_config *mpll_config = plat_data->mpll_cfg;
|
||||||
const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr;
|
const struct dw_hdmi_curr_ctrl *curr_ctrl = plat_data->cur_ctr;
|
||||||
const struct dw_hdmi_sym_term *sym_term = hdmi->plat_data->sym_term;
|
const struct dw_hdmi_phy_config *phy_config = plat_data->phy_config;
|
||||||
|
|
||||||
if (prep)
|
if (prep)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -827,18 +829,18 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
|
||||||
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
|
hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
|
||||||
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
|
hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
|
||||||
|
|
||||||
for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
|
for (i = 0; phy_config[i].mpixelclock != (~0UL); i++)
|
||||||
if (hdmi->hdmi_data.video_mode.mpixelclock <=
|
if (hdmi->hdmi_data.video_mode.mpixelclock <=
|
||||||
sym_term[i].mpixelclock)
|
phy_config[i].mpixelclock)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* RESISTANCE TERM 133Ohm Cfg */
|
/* RESISTANCE TERM 133Ohm Cfg */
|
||||||
hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */
|
hdmi_phy_i2c_write(hdmi, phy_config[i].term, 0x19); /* TXTERM */
|
||||||
/* PREEMP Cgf 0.00 */
|
/* PREEMP Cgf 0.00 */
|
||||||
hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
|
hdmi_phy_i2c_write(hdmi, phy_config[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
|
||||||
|
|
||||||
/* TX/CK LVL 10 */
|
/* TX/CK LVL 10 */
|
||||||
hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
|
hdmi_phy_i2c_write(hdmi, phy_config[i].vlev_ctr, 0x0E); /* VLEVCTRL */
|
||||||
|
|
||||||
/* REMOVE CLK TERM */
|
/* REMOVE CLK TERM */
|
||||||
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
|
hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
|
||||||
|
|
||||||
|
@ -1569,6 +1571,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master,
|
||||||
hdmi->ratio = 100;
|
hdmi->ratio = 100;
|
||||||
hdmi->encoder = encoder;
|
hdmi->encoder = encoder;
|
||||||
|
|
||||||
|
mutex_init(&hdmi->audio_mutex);
|
||||||
|
|
||||||
of_property_read_u32(np, "reg-io-width", &val);
|
of_property_read_u32(np, "reg-io-width", &val);
|
||||||
|
|
||||||
switch (val) {
|
switch (val) {
|
||||||
|
|
|
@ -75,10 +75,10 @@ static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct dw_hdmi_sym_term imx_sym_term[] = {
|
static const struct dw_hdmi_phy_config imx_phy_config[] = {
|
||||||
/*pixelclk symbol term*/
|
/*pixelclk symbol term vlev */
|
||||||
{ 148500000, 0x800d, 0x0005 },
|
{ 148500000, 0x800d, 0x0005, 0x01ad},
|
||||||
{ ~0UL, 0x0000, 0x0000 }
|
{ ~0UL, 0x0000, 0x0000, 0x0000}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
|
static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
|
||||||
|
@ -163,7 +163,7 @@ static enum drm_mode_status imx6dl_hdmi_mode_valid(struct drm_connector *con,
|
||||||
static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
|
static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
|
||||||
.mpll_cfg = imx_mpll_cfg,
|
.mpll_cfg = imx_mpll_cfg,
|
||||||
.cur_ctr = imx_cur_ctr,
|
.cur_ctr = imx_cur_ctr,
|
||||||
.sym_term = imx_sym_term,
|
.phy_config = imx_phy_config,
|
||||||
.dev_type = IMX6Q_HDMI,
|
.dev_type = IMX6Q_HDMI,
|
||||||
.mode_valid = imx6q_hdmi_mode_valid,
|
.mode_valid = imx6q_hdmi_mode_valid,
|
||||||
};
|
};
|
||||||
|
@ -171,7 +171,7 @@ static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
|
||||||
static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
|
static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
|
||||||
.mpll_cfg = imx_mpll_cfg,
|
.mpll_cfg = imx_mpll_cfg,
|
||||||
.cur_ctr = imx_cur_ctr,
|
.cur_ctr = imx_cur_ctr,
|
||||||
.sym_term = imx_sym_term,
|
.phy_config = imx_phy_config,
|
||||||
.dev_type = IMX6DL_HDMI,
|
.dev_type = IMX6DL_HDMI,
|
||||||
.mode_valid = imx6dl_hdmi_mode_valid,
|
.mode_valid = imx6dl_hdmi_mode_valid,
|
||||||
};
|
};
|
||||||
|
|
|
@ -133,12 +133,12 @@ static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct dw_hdmi_sym_term rockchip_sym_term[] = {
|
static const struct dw_hdmi_phy_config rockchip_phy_config[] = {
|
||||||
/*pixelclk symbol term*/
|
/*pixelclk symbol term vlev*/
|
||||||
{ 74250000, 0x8009, 0x0004 },
|
{ 74250000, 0x8009, 0x0004, 0x0272},
|
||||||
{ 148500000, 0x8029, 0x0004 },
|
{ 148500000, 0x802b, 0x0004, 0x028d},
|
||||||
{ 297000000, 0x8039, 0x0005 },
|
{ 297000000, 0x8039, 0x0005, 0x028d},
|
||||||
{ ~0UL, 0x0000, 0x0000 }
|
{ ~0UL, 0x0000, 0x0000, 0x0000}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
|
static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
|
||||||
|
@ -230,7 +230,7 @@ static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
|
||||||
.mode_valid = dw_hdmi_rockchip_mode_valid,
|
.mode_valid = dw_hdmi_rockchip_mode_valid,
|
||||||
.mpll_cfg = rockchip_mpll_cfg,
|
.mpll_cfg = rockchip_mpll_cfg,
|
||||||
.cur_ctr = rockchip_cur_ctr,
|
.cur_ctr = rockchip_cur_ctr,
|
||||||
.sym_term = rockchip_sym_term,
|
.phy_config = rockchip_phy_config,
|
||||||
.dev_type = RK3288_HDMI,
|
.dev_type = RK3288_HDMI,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -38,17 +38,18 @@ struct dw_hdmi_curr_ctrl {
|
||||||
u16 curr[DW_HDMI_RES_MAX];
|
u16 curr[DW_HDMI_RES_MAX];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dw_hdmi_sym_term {
|
struct dw_hdmi_phy_config {
|
||||||
unsigned long mpixelclock;
|
unsigned long mpixelclock;
|
||||||
u16 sym_ctr; /*clock symbol and transmitter control*/
|
u16 sym_ctr; /*clock symbol and transmitter control*/
|
||||||
u16 term; /*transmission termination value*/
|
u16 term; /*transmission termination value*/
|
||||||
|
u16 vlev_ctr; /* voltage level control */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dw_hdmi_plat_data {
|
struct dw_hdmi_plat_data {
|
||||||
enum dw_hdmi_devtype dev_type;
|
enum dw_hdmi_devtype dev_type;
|
||||||
const struct dw_hdmi_mpll_config *mpll_cfg;
|
const struct dw_hdmi_mpll_config *mpll_cfg;
|
||||||
const struct dw_hdmi_curr_ctrl *cur_ctr;
|
const struct dw_hdmi_curr_ctrl *cur_ctr;
|
||||||
const struct dw_hdmi_sym_term *sym_term;
|
const struct dw_hdmi_phy_config *phy_config;
|
||||||
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
|
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
|
||||||
struct drm_display_mode *mode);
|
struct drm_display_mode *mode);
|
||||||
};
|
};
|
||||||
|
|
Загрузка…
Ссылка в новой задаче