The CEC clock divider computed in vc4_hdmi_cec_update_clk_div() is written unmasked into the 12-bit DIV_CLK_CNT field of the CEC_CNTRL_1 register. On BCM2835, the CEC clock is obtained by dividing the HSM clock, which in turn is scaled to 101% of the pixel clock. For HSM clock rates above 163.8 MHz, the divider exceeds the field limit (4095), corrupting the adjacent CEC_ADDR field and truncating the effective divider, which breaks CEC entirely.
The BCM2835 maximum pixel clock of 162 MHz yields an HSM clock of 163.62 MHz, so the overflow cannot currently be triggered. Clamp the divider to the field maximum. This is a prerequisite for raising the BCM2835 maximum pixel clock to 165 MHz, which pushes the HSM clock up to 166.65 MHz. The CEC bit clock will then run up to ~1.75% faster than the nominal 40 kHz, i.e. ~40.7 kHz, which is still within the CEC bit-timing tolerances. Reported-by: Sashiko <[email protected]> Closes: https://lore.kernel.org/all/[email protected]/ Signed-off-by: Cristian Ciocaltea <[email protected]> --- drivers/gpu/drm/vc4/vc4_hdmi.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 2451ff85e759..0a95e14792e8 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -231,9 +231,14 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) /* * Set the clock divider: the hsm_clock rate and this divider - * setting will give a 40 kHz CEC clock. + * setting will give a 40 kHz CEC clock. Clamp the divider to + * its 12-bit field to avoid corrupting CEC_ADDR; for HSM rates + * above 163.8 MHz, the CEC clock runs marginally faster, but + * still within CEC timing tolerances. */ - clk_cnt = cec_rate / CEC_CLOCK_FREQ; + clk_cnt = min_t(unsigned long, cec_rate / CEC_CLOCK_FREQ, + VC4_HDMI_CEC_DIV_CLK_CNT_MASK >> + VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT); value |= clk_cnt << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT; HDMI_WRITE(HDMI_CEC_CNTRL_1, value); -- 2.55.0
