On Wed, 14 Oct 2026 at 02:03, Cristian Ciocaltea <[email protected]> wrote: > > 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]>
Reviewed-by: Dave Stevenson <[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 >
