drm/rockchip: dw-hdmi: Support hdmi quantization range setting
Adding hdmi quantization range switching function. The current version use default quant range, subsequent version will keep consistent with the kernel Setting. Change-Id: Ibb93f7c08d72322caa15f12b1d6e1f901371b27b Signed-off-by: Algea Cao <algea.cao@rock-chips.com>
This commit is contained in:
parent
af4fa70793
commit
b5016cf2d5
|
|
@ -2748,6 +2748,24 @@ static void drm_parse_hdmi_forum_vsdb(struct hdmi_edid_data *data,
|
||||||
drm_parse_ycbcr420_deep_color_info(data, hf_vsdb);
|
drm_parse_ycbcr420_deep_color_info(data, hf_vsdb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_default_rgb_quant_range - default RGB quantization range
|
||||||
|
* @mode: display mode
|
||||||
|
*
|
||||||
|
* Determine the default RGB quantization range for the mode,
|
||||||
|
* as specified in CEA-861.
|
||||||
|
*
|
||||||
|
* Return: The default RGB quantization range for the mode
|
||||||
|
*/
|
||||||
|
enum hdmi_quantization_range
|
||||||
|
drm_default_rgb_quant_range(struct drm_display_mode *mode)
|
||||||
|
{
|
||||||
|
/* All CEA modes other than VIC 1 use limited quantization range. */
|
||||||
|
return drm_match_cea_mode(mode) > 1 ?
|
||||||
|
HDMI_QUANTIZATION_RANGE_LIMITED :
|
||||||
|
HDMI_QUANTIZATION_RANGE_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
static void drm_parse_hdmi_deep_color_info(struct hdmi_edid_data *data,
|
static void drm_parse_hdmi_deep_color_info(struct hdmi_edid_data *data,
|
||||||
const u8 *hdmi)
|
const u8 *hdmi)
|
||||||
{
|
{
|
||||||
|
|
@ -5157,6 +5175,50 @@ static int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* drm_hdmi_avi_infoframe_quant_range() - fill the HDMI AVI infoframe
|
||||||
|
* quantization range information
|
||||||
|
* @frame: HDMI AVI infoframe
|
||||||
|
* @rgb_quant_range: RGB quantization range (Q)
|
||||||
|
* @rgb_quant_range_selectable: Sink support selectable RGB quantization range (QS)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
|
||||||
|
struct drm_display_mode *mode,
|
||||||
|
enum hdmi_quantization_range rgb_quant_range,
|
||||||
|
bool rgb_quant_range_selectable)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* CEA-861:
|
||||||
|
* "A Source shall not send a non-zero Q value that does not correspond
|
||||||
|
* to the default RGB Quantization Range for the transmitted Picture
|
||||||
|
* unless the Sink indicates support for the Q bit in a Video
|
||||||
|
* Capabilities Data Block."
|
||||||
|
*
|
||||||
|
* HDMI 2.0 recommends sending non-zero Q when it does match the
|
||||||
|
* default RGB quantization range for the mode, even when QS=0.
|
||||||
|
*/
|
||||||
|
if (rgb_quant_range_selectable ||
|
||||||
|
rgb_quant_range == drm_default_rgb_quant_range(mode))
|
||||||
|
frame->quantization_range = rgb_quant_range;
|
||||||
|
else
|
||||||
|
frame->quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* CEA-861-F:
|
||||||
|
* "When transmitting any RGB colorimetry, the Source should set the
|
||||||
|
* YQ-field to match the RGB Quantization Range being transmitted
|
||||||
|
* (e.g., when Limited Range RGB, set YQ=0 or when Full Range RGB,
|
||||||
|
* set YQ=1) and the Sink shall ignore the YQ-field."
|
||||||
|
*/
|
||||||
|
if (rgb_quant_range == HDMI_QUANTIZATION_RANGE_LIMITED)
|
||||||
|
frame->ycc_quantization_range =
|
||||||
|
HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
|
||||||
|
else
|
||||||
|
frame->ycc_quantization_range =
|
||||||
|
HDMI_YCC_QUANTIZATION_RANGE_FULL;
|
||||||
|
}
|
||||||
|
|
||||||
static enum hdmi_3d_structure
|
static enum hdmi_3d_structure
|
||||||
s3d_structure_from_display_mode(const struct drm_display_mode *mode)
|
s3d_structure_from_display_mode(const struct drm_display_mode *mode)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -111,6 +111,12 @@ static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
|
||||||
{ 0x6756, 0x78ab, 0x2000, 0x0200 }
|
{ 0x6756, 0x78ab, 0x2000, 0x0200 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const u16 csc_coeff_full_to_limited[3][4] = {
|
||||||
|
{ 0x36f7, 0x0000, 0x0000, 0x0040 },
|
||||||
|
{ 0x0000, 0x36f7, 0x0000, 0x0040 },
|
||||||
|
{ 0x0000, 0x0000, 0x36f7, 0x0040 }
|
||||||
|
};
|
||||||
|
|
||||||
struct hdmi_vmode {
|
struct hdmi_vmode {
|
||||||
bool mdataenablepolarity;
|
bool mdataenablepolarity;
|
||||||
|
|
||||||
|
|
@ -125,6 +131,7 @@ struct hdmi_data_info {
|
||||||
unsigned int enc_out_bus_format;
|
unsigned int enc_out_bus_format;
|
||||||
unsigned int enc_in_encoding;
|
unsigned int enc_in_encoding;
|
||||||
unsigned int enc_out_encoding;
|
unsigned int enc_out_encoding;
|
||||||
|
unsigned int quant_range;
|
||||||
unsigned int pix_repet_factor;
|
unsigned int pix_repet_factor;
|
||||||
struct hdmi_vmode video_mode;
|
struct hdmi_vmode video_mode;
|
||||||
};
|
};
|
||||||
|
|
@ -327,8 +334,26 @@ static int hdmi_bus_fmt_color_depth(unsigned int bus_format)
|
||||||
|
|
||||||
static int is_color_space_conversion(struct dw_hdmi *hdmi)
|
static int is_color_space_conversion(struct dw_hdmi *hdmi)
|
||||||
{
|
{
|
||||||
return hdmi->hdmi_data.enc_in_bus_format !=
|
struct drm_display_mode *mode =
|
||||||
hdmi->hdmi_data.enc_out_bus_format;
|
hdmi->edid_data.preferred_mode;
|
||||||
|
bool is_cea_default;
|
||||||
|
|
||||||
|
is_cea_default = (drm_match_cea_mode(mode) > 1) &&
|
||||||
|
(hdmi->hdmi_data.quant_range ==
|
||||||
|
HDMI_QUANTIZATION_RANGE_DEFAULT);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* When output is rgb limited range or default range with
|
||||||
|
* cea mode, csc should be enabled.
|
||||||
|
*/
|
||||||
|
if (hdmi->hdmi_data.enc_in_bus_format !=
|
||||||
|
hdmi->hdmi_data.enc_out_bus_format ||
|
||||||
|
((hdmi->hdmi_data.quant_range == HDMI_QUANTIZATION_RANGE_LIMITED ||
|
||||||
|
is_cea_default) &&
|
||||||
|
hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_color_space_decimation(struct dw_hdmi *hdmi)
|
static int is_color_space_decimation(struct dw_hdmi *hdmi)
|
||||||
|
|
@ -1139,16 +1164,22 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
|
||||||
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
|
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
u32 csc_scale = 1;
|
u32 csc_scale = 1;
|
||||||
|
int enc_out_rgb, enc_in_rgb;
|
||||||
|
|
||||||
|
enc_out_rgb = hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format);
|
||||||
|
enc_in_rgb = hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_in_bus_format);
|
||||||
|
|
||||||
if (is_color_space_conversion(hdmi)) {
|
if (is_color_space_conversion(hdmi)) {
|
||||||
if (hdmi_bus_fmt_is_rgb(hdmi->hdmi_data.enc_out_bus_format)) {
|
if (enc_out_rgb == enc_in_rgb) {
|
||||||
|
csc_coeff = &csc_coeff_full_to_limited;
|
||||||
|
csc_scale = 0;
|
||||||
|
} else if (enc_out_rgb) {
|
||||||
if (hdmi->hdmi_data.enc_out_encoding ==
|
if (hdmi->hdmi_data.enc_out_encoding ==
|
||||||
V4L2_YCBCR_ENC_601)
|
V4L2_YCBCR_ENC_601)
|
||||||
csc_coeff = &csc_coeff_rgb_out_eitu601;
|
csc_coeff = &csc_coeff_rgb_out_eitu601;
|
||||||
else
|
else
|
||||||
csc_coeff = &csc_coeff_rgb_out_eitu709;
|
csc_coeff = &csc_coeff_rgb_out_eitu709;
|
||||||
} else if (hdmi_bus_fmt_is_rgb(
|
} else if (enc_in_rgb) {
|
||||||
hdmi->hdmi_data.enc_in_bus_format)) {
|
|
||||||
if (hdmi->hdmi_data.enc_out_encoding ==
|
if (hdmi->hdmi_data.enc_out_encoding ==
|
||||||
V4L2_YCBCR_ENC_601)
|
V4L2_YCBCR_ENC_601)
|
||||||
csc_coeff = &csc_coeff_rgb_in_eitu601;
|
csc_coeff = &csc_coeff_rgb_in_eitu601;
|
||||||
|
|
@ -1513,6 +1544,8 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||||
struct hdmi_avi_infoframe frame;
|
struct hdmi_avi_infoframe frame;
|
||||||
u8 val;
|
u8 val;
|
||||||
bool is_hdmi2 = false;
|
bool is_hdmi2 = false;
|
||||||
|
enum hdmi_quantization_range rgb_quant_range =
|
||||||
|
hdmi->hdmi_data.quant_range;
|
||||||
|
|
||||||
if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) ||
|
if (hdmi_bus_fmt_is_yuv420(hdmi->hdmi_data.enc_out_bus_format) ||
|
||||||
hdmi->edid_data.display_info.hdmi.scdc.supported)
|
hdmi->edid_data.display_info.hdmi.scdc.supported)
|
||||||
|
|
@ -1520,6 +1553,12 @@ static void hdmi_config_AVI(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
|
||||||
/* Initialise info frame from DRM mode */
|
/* Initialise info frame from DRM mode */
|
||||||
drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2);
|
drm_hdmi_avi_infoframe_from_display_mode(&frame, mode, is_hdmi2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore monitor selectable quantization, use quantization set
|
||||||
|
* by the user
|
||||||
|
*/
|
||||||
|
drm_hdmi_avi_infoframe_quant_range(&frame, mode, rgb_quant_range,
|
||||||
|
true);
|
||||||
if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
|
if (hdmi_bus_fmt_is_yuv444(hdmi->hdmi_data.enc_out_bus_format))
|
||||||
frame.colorspace = HDMI_COLORSPACE_YUV444;
|
frame.colorspace = HDMI_COLORSPACE_YUV444;
|
||||||
else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
|
else if (hdmi_bus_fmt_is_yuv422(hdmi->hdmi_data.enc_out_bus_format))
|
||||||
|
|
@ -2034,6 +2073,13 @@ static int dw_hdmi_setup(struct dw_hdmi *hdmi,
|
||||||
hdmi->plat_data->input_bus_encoding;
|
hdmi->plat_data->input_bus_encoding;
|
||||||
else
|
else
|
||||||
hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
|
hdmi->hdmi_data.enc_in_encoding = V4L2_YCBCR_ENC_DEFAULT;
|
||||||
|
|
||||||
|
if (hdmi->plat_data->get_quant_range)
|
||||||
|
hdmi->hdmi_data.quant_range =
|
||||||
|
hdmi->plat_data->get_quant_range(data);
|
||||||
|
else
|
||||||
|
hdmi->hdmi_data.quant_range = HDMI_QUANTIZATION_RANGE_DEFAULT;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to the dw-hdmi specification 6.4.2
|
* According to the dw-hdmi specification 6.4.2
|
||||||
* vp_pr_cd[3:0]:
|
* vp_pr_cd[3:0]:
|
||||||
|
|
|
||||||
|
|
@ -847,6 +847,8 @@ bool drm_detect_hdmi_monitor(struct edid *edid);
|
||||||
bool drm_detect_monitor_audio(struct edid *edid);
|
bool drm_detect_monitor_audio(struct edid *edid);
|
||||||
int do_cea_modes(struct hdmi_edid_data *data, const u8 *db, u8 len);
|
int do_cea_modes(struct hdmi_edid_data *data, const u8 *db, u8 len);
|
||||||
int drm_do_get_edid(struct ddc_adapter *adap, u8 *edid);
|
int drm_do_get_edid(struct ddc_adapter *adap, u8 *edid);
|
||||||
|
enum hdmi_quantization_range
|
||||||
|
drm_default_rgb_quant_range(struct drm_display_mode *mode);
|
||||||
u8 drm_scdc_readb(struct ddc_adapter *adap, u8 offset,
|
u8 drm_scdc_readb(struct ddc_adapter *adap, u8 offset,
|
||||||
u8 *value);
|
u8 *value);
|
||||||
u8 drm_scdc_writeb(struct ddc_adapter *adap, u8 offset,
|
u8 drm_scdc_writeb(struct ddc_adapter *adap, u8 offset,
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,7 @@ struct dw_hdmi_plat_data {
|
||||||
unsigned long (*get_output_bus_format)(void *data);
|
unsigned long (*get_output_bus_format)(void *data);
|
||||||
unsigned long (*get_enc_in_encoding)(void *data);
|
unsigned long (*get_enc_in_encoding)(void *data);
|
||||||
unsigned long (*get_enc_out_encoding)(void *data);
|
unsigned long (*get_enc_out_encoding)(void *data);
|
||||||
|
unsigned long (*get_quant_range)(void *data);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __IMX_HDMI_H__ */
|
#endif /* __IMX_HDMI_H__ */
|
||||||
|
|
|
||||||
|
|
@ -322,6 +322,11 @@ int
|
||||||
drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
||||||
struct drm_display_mode *mode,
|
struct drm_display_mode *mode,
|
||||||
bool is_hdmi2_sink);
|
bool is_hdmi2_sink);
|
||||||
|
void
|
||||||
|
drm_hdmi_avi_infoframe_quant_range(struct hdmi_avi_infoframe *frame,
|
||||||
|
struct drm_display_mode *mode,
|
||||||
|
enum hdmi_quantization_range rgb_quant_range,
|
||||||
|
bool rgb_quant_range_selectable);
|
||||||
u8 drm_match_cea_mode(struct drm_display_mode *to_match);
|
u8 drm_match_cea_mode(struct drm_display_mode *to_match);
|
||||||
|
|
||||||
#endif /* _DRM_HDMI_H */
|
#endif /* _DRM_HDMI_H */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue