mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 02:50:49 +09:00
drm: bridge: dw-hdmi: set ddc scl clock rate according to dts
To set dw hdmi i2c bus adapter scl clock rate, we introduce two device
tree parameter, ddc-i2c-scl-high-time-ns and ddc-i2c-scl-low-time-ns.
ddc-i2c-scl-high-time-ns: how many ns SCL hold high
ddc-i2c-scl-low-time-ns: how many ns SCL hold low
After measurement, 50KHz scl clock rate recommended configuration is:
&hdmi {
ddc-i2c-scl-high-time-ns = <9625>;
ddc-i2c-scl-low-time-ns = <10000>;
};
100KHz recommended configuration is:
&hdmi {
ddc-i2c-scl-high-time-ns = <4708>;
ddc-i2c-scl-low-time-ns = <4916>;
};
If dts parameter is not available, the default scl rate is 100KHz.
Change-Id: I6f6b0bf1694ab59e70da789ead99e15a53c93e4d
Signed-off-by: Zheng Yang <zhengyang@rock-chips.com>
This commit is contained in:
@@ -194,6 +194,9 @@ struct dw_hdmi_i2c {
|
||||
u8 slave_reg;
|
||||
bool is_regaddr;
|
||||
bool is_segment;
|
||||
|
||||
unsigned int scl_high_ns;
|
||||
unsigned int scl_low_ns;
|
||||
};
|
||||
|
||||
struct dw_hdmi_phy_data {
|
||||
@@ -380,6 +383,49 @@ static void init_hpd_work(struct dw_hdmi *hdmi)
|
||||
INIT_DELAYED_WORK(&hdmi->work, repo_hpd_event);
|
||||
}
|
||||
|
||||
static void dw_hdmi_i2c_set_divs(struct dw_hdmi *hdmi)
|
||||
{
|
||||
unsigned long clk_rate_khz;
|
||||
unsigned long low_ns, high_ns;
|
||||
unsigned long div_low, div_high;
|
||||
|
||||
/* Standard-mode */
|
||||
if (hdmi->i2c->scl_high_ns < 4000)
|
||||
high_ns = 4708;
|
||||
else
|
||||
high_ns = hdmi->i2c->scl_high_ns;
|
||||
|
||||
if (hdmi->i2c->scl_low_ns < 4700)
|
||||
low_ns = 4916;
|
||||
else
|
||||
low_ns = hdmi->i2c->scl_low_ns;
|
||||
|
||||
/* Adjust to avoid overflow */
|
||||
clk_rate_khz = DIV_ROUND_UP(clk_get_rate(hdmi->isfr_clk), 1000);
|
||||
|
||||
div_low = (clk_rate_khz * low_ns) / 1000000;
|
||||
if ((clk_rate_khz * low_ns) % 1000000)
|
||||
div_low++;
|
||||
|
||||
div_high = (clk_rate_khz * high_ns) / 1000000;
|
||||
if ((clk_rate_khz * high_ns) % 1000000)
|
||||
div_high++;
|
||||
|
||||
/* Maximum divider supported by hw is 0xffff */
|
||||
if (div_low > 0xffff)
|
||||
div_low = 0xffff;
|
||||
|
||||
if (div_high > 0xffff)
|
||||
div_high = 0xffff;
|
||||
|
||||
hdmi_writeb(hdmi, div_high & 0xff, HDMI_I2CM_SS_SCL_HCNT_0_ADDR);
|
||||
hdmi_writeb(hdmi, (div_high >> 8) & 0xff,
|
||||
HDMI_I2CM_SS_SCL_HCNT_1_ADDR);
|
||||
hdmi_writeb(hdmi, div_low & 0xff, HDMI_I2CM_SS_SCL_LCNT_0_ADDR);
|
||||
hdmi_writeb(hdmi, (div_low >> 8) & 0xff,
|
||||
HDMI_I2CM_SS_SCL_LCNT_1_ADDR);
|
||||
}
|
||||
|
||||
static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi)
|
||||
{
|
||||
hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
|
||||
@@ -410,6 +456,8 @@ static void dw_hdmi_i2c_init(struct dw_hdmi *hdmi)
|
||||
|
||||
/* set SDA high level holding time */
|
||||
hdmi_writeb(hdmi, 0x48, HDMI_I2CM_SDA_HOLD);
|
||||
|
||||
dw_hdmi_i2c_set_divs(hdmi);
|
||||
}
|
||||
|
||||
static bool dw_hdmi_i2c_unwedge(struct dw_hdmi *hdmi)
|
||||
@@ -3577,7 +3625,8 @@ static void dw_hdmi_init_hw(struct dw_hdmi *hdmi)
|
||||
* Even if we are using a separate i2c adapter doing this doesn't
|
||||
* hurt.
|
||||
*/
|
||||
dw_hdmi_i2c_init(hdmi);
|
||||
if (hdmi->i2c)
|
||||
dw_hdmi_i2c_init(hdmi);
|
||||
|
||||
if (hdmi->phy.ops->setup_hpd)
|
||||
hdmi->phy.ops->setup_hpd(hdmi, hdmi->phy.data);
|
||||
@@ -3906,7 +3955,6 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
init_hpd_work(hdmi);
|
||||
dw_hdmi_init_hw(hdmi);
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
@@ -3950,8 +3998,20 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
|
||||
hdmi->ddc = dw_hdmi_i2c_adapter(hdmi);
|
||||
if (IS_ERR(hdmi->ddc))
|
||||
hdmi->ddc = NULL;
|
||||
/*
|
||||
* Read high and low time from device tree. If not available use
|
||||
* the default timing scl clock rate is about 99.6KHz.
|
||||
*/
|
||||
if (of_property_read_u32(np, "ddc-i2c-scl-high-time-ns",
|
||||
&hdmi->i2c->scl_high_ns))
|
||||
hdmi->i2c->scl_high_ns = 4708;
|
||||
if (of_property_read_u32(np, "ddc-i2c-scl-low-time-ns",
|
||||
&hdmi->i2c->scl_low_ns))
|
||||
hdmi->i2c->scl_low_ns = 4916;
|
||||
}
|
||||
|
||||
dw_hdmi_init_hw(hdmi);
|
||||
|
||||
hdmi->bridge.driver_private = hdmi;
|
||||
hdmi->bridge.funcs = &dw_hdmi_bridge_funcs;
|
||||
hdmi->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID
|
||||
|
||||
Reference in New Issue
Block a user