Message ID | 20240521-kms-hdmi-connector-state-v14-9-51950db4fedb@kernel.org (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | drm/connector: Create HDMI Connector infrastructure | expand |
On Tue, May 21, 2024 at 12:13:42PM +0200, Maxime Ripard wrote: > A lot of HDMI drivers have some variation of the formula to calculate > the TMDS character rate from a mode, but few of them actually take all > parameters into account. > > Let's create a helper to provide that rate taking all parameters into > account. > > Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com> > Signed-off-by: Maxime Ripard <mripard@kernel.org> > --- > drivers/gpu/drm/display/drm_hdmi_helper.c | 57 +++++++++++++++++++++++++++++++ > include/drm/display/drm_hdmi_helper.h | 4 +++ > 2 files changed, 61 insertions(+) > > diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c > index faf5e9efa7d3..679eb3e81393 100644 > --- a/drivers/gpu/drm/display/drm_hdmi_helper.c > +++ b/drivers/gpu/drm/display/drm_hdmi_helper.c > @@ -193,5 +193,62 @@ void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, > } > > frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA; > } > EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); > + > +/** > + * drm_hdmi_compute_mode_clock() - Computes the TMDS Character Rate > + * @mode: Display mode to compute the clock for > + * @bpc: Bits per character > + * @fmt: Output Pixel Format used > + * > + * Returns the TMDS Character Rate for a given mode, bpc count and output format. > + * > + * RETURNS: > + * The TMDS Character Rate, in Hertz, or 0 on error. > + */ > +unsigned long long > +drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode, > + unsigned int bpc, enum hdmi_colorspace fmt) > +{ > + unsigned long long clock = mode->clock * 1000ULL; > + unsigned int vic = drm_match_cea_mode(mode); > + > + /* > + * CTA-861-G Spec, section 5.4 - Color Coding and Quantization > + * mandates that VIC 1 always uses 8 bpc. > + */ > + if (vic == 1 && bpc != 8) > + return 0; > + > + if (fmt == HDMI_COLORSPACE_YUV422) { > + /* > + * HDMI 1.4b Spec, section 6.2.3 - Pixel Encoding Requirements This is probably 6.2.4, but it doesn't specify that it is 36-bit _only_. > + * specifies that YUV422 is 36-bit only. > + */ > + if (bpc != 12) > + return 0; 6.5.1 allows using less than 12 bits (If fewer than 12 bits are used...). So I think it would be more correct to allow less than 12 bpc, but we'd still have to use 8 for the matter of the calculating the clock. > + > + /* > + * HDMI 1.0 Spec, section 6.5 - Pixel Encoding > + * specifies that YUV422 requires two 12-bits components per > + * pixel clock, which is equivalent in our calculation to three > + * 8-bits components > + */ > + bpc = 8; > + } > + > + /* > + * HDMI 2.0 Spec, Section 7.1 - YCbCr 4:2:0 Pixel Encoding > + * specifies that YUV420 encoding is carried at a TMDS Character Rate > + * equal to half the pixel clock rate. > + */ > + if (fmt == HDMI_COLORSPACE_YUV420) > + clock = clock / 2; > + > + if (mode->flags & DRM_MODE_FLAG_DBLCLK) > + clock = clock * 2; > + > + return DIV_ROUND_CLOSEST_ULL(clock * bpc, 8); > +} > +EXPORT_SYMBOL(drm_hdmi_compute_mode_clock); > diff --git a/include/drm/display/drm_hdmi_helper.h b/include/drm/display/drm_hdmi_helper.h > index 76d234826e22..57e3b18c15ec 100644 > --- a/include/drm/display/drm_hdmi_helper.h > +++ b/include/drm/display/drm_hdmi_helper.h > @@ -22,6 +22,10 @@ drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, > const struct drm_connector_state *conn_state); > > void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, > const struct drm_connector_state *conn_state); > > +unsigned long long > +drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode, > + unsigned int bpc, enum hdmi_colorspace fmt); > + > #endif > > -- > 2.45.0 >
diff --git a/drivers/gpu/drm/display/drm_hdmi_helper.c b/drivers/gpu/drm/display/drm_hdmi_helper.c index faf5e9efa7d3..679eb3e81393 100644 --- a/drivers/gpu/drm/display/drm_hdmi_helper.c +++ b/drivers/gpu/drm/display/drm_hdmi_helper.c @@ -193,5 +193,62 @@ void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, } frame->itc = conn_state->content_type != DRM_MODE_CONTENT_TYPE_NO_DATA; } EXPORT_SYMBOL(drm_hdmi_avi_infoframe_content_type); + +/** + * drm_hdmi_compute_mode_clock() - Computes the TMDS Character Rate + * @mode: Display mode to compute the clock for + * @bpc: Bits per character + * @fmt: Output Pixel Format used + * + * Returns the TMDS Character Rate for a given mode, bpc count and output format. + * + * RETURNS: + * The TMDS Character Rate, in Hertz, or 0 on error. + */ +unsigned long long +drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode, + unsigned int bpc, enum hdmi_colorspace fmt) +{ + unsigned long long clock = mode->clock * 1000ULL; + unsigned int vic = drm_match_cea_mode(mode); + + /* + * CTA-861-G Spec, section 5.4 - Color Coding and Quantization + * mandates that VIC 1 always uses 8 bpc. + */ + if (vic == 1 && bpc != 8) + return 0; + + if (fmt == HDMI_COLORSPACE_YUV422) { + /* + * HDMI 1.4b Spec, section 6.2.3 - Pixel Encoding Requirements + * specifies that YUV422 is 36-bit only. + */ + if (bpc != 12) + return 0; + + /* + * HDMI 1.0 Spec, section 6.5 - Pixel Encoding + * specifies that YUV422 requires two 12-bits components per + * pixel clock, which is equivalent in our calculation to three + * 8-bits components + */ + bpc = 8; + } + + /* + * HDMI 2.0 Spec, Section 7.1 - YCbCr 4:2:0 Pixel Encoding + * specifies that YUV420 encoding is carried at a TMDS Character Rate + * equal to half the pixel clock rate. + */ + if (fmt == HDMI_COLORSPACE_YUV420) + clock = clock / 2; + + if (mode->flags & DRM_MODE_FLAG_DBLCLK) + clock = clock * 2; + + return DIV_ROUND_CLOSEST_ULL(clock * bpc, 8); +} +EXPORT_SYMBOL(drm_hdmi_compute_mode_clock); diff --git a/include/drm/display/drm_hdmi_helper.h b/include/drm/display/drm_hdmi_helper.h index 76d234826e22..57e3b18c15ec 100644 --- a/include/drm/display/drm_hdmi_helper.h +++ b/include/drm/display/drm_hdmi_helper.h @@ -22,6 +22,10 @@ drm_hdmi_infoframe_set_hdr_metadata(struct hdmi_drm_infoframe *frame, const struct drm_connector_state *conn_state); void drm_hdmi_avi_infoframe_content_type(struct hdmi_avi_infoframe *frame, const struct drm_connector_state *conn_state); +unsigned long long +drm_hdmi_compute_mode_clock(const struct drm_display_mode *mode, + unsigned int bpc, enum hdmi_colorspace fmt); + #endif