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_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,
|
||||
const u8 *hdmi)
|
||||
{
|
||||
|
|
@ -5157,6 +5175,50 @@ static int hdmi_vendor_infoframe_init(struct hdmi_vendor_infoframe *frame)
|
|||
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
|
||||
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 }
|
||||
};
|
||||
|
||||
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 {
|
||||
bool mdataenablepolarity;
|
||||
|
||||
|
|
@ -125,6 +131,7 @@ struct hdmi_data_info {
|
|||
unsigned int enc_out_bus_format;
|
||||
unsigned int enc_in_encoding;
|
||||
unsigned int enc_out_encoding;
|
||||
unsigned int quant_range;
|
||||
unsigned int pix_repet_factor;
|
||||
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)
|
||||
{
|
||||
return hdmi->hdmi_data.enc_in_bus_format !=
|
||||
hdmi->hdmi_data.enc_out_bus_format;
|
||||
struct drm_display_mode *mode =
|
||||
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)
|
||||
|
|
@ -1139,16 +1164,22 @@ static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
|
|||
const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
|
||||
unsigned i;
|
||||
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 (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 ==
|
||||
V4L2_YCBCR_ENC_601)
|
||||
csc_coeff = &csc_coeff_rgb_out_eitu601;
|
||||
else
|
||||
csc_coeff = &csc_coeff_rgb_out_eitu709;
|
||||
} else if (hdmi_bus_fmt_is_rgb(
|
||||
hdmi->hdmi_data.enc_in_bus_format)) {
|
||||
} else if (enc_in_rgb) {
|
||||
if (hdmi->hdmi_data.enc_out_encoding ==
|
||||
V4L2_YCBCR_ENC_601)
|
||||
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;
|
||||
u8 val;
|
||||
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) ||
|
||||
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 */
|
||||
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))
|
||||
frame.colorspace = HDMI_COLORSPACE_YUV444;
|
||||
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;
|
||||
else
|
||||
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
|
||||
* 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);
|
||||
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);
|
||||
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 *value);
|
||||
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_enc_in_encoding)(void *data);
|
||||
unsigned long (*get_enc_out_encoding)(void *data);
|
||||
unsigned long (*get_quant_range)(void *data);
|
||||
};
|
||||
|
||||
#endif /* __IMX_HDMI_H__ */
|
||||
|
|
|
|||
|
|
@ -322,6 +322,11 @@ int
|
|||
drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
|
||||
struct drm_display_mode *mode,
|
||||
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);
|
||||
|
||||
#endif /* _DRM_HDMI_H */
|
||||
|
|
|
|||
Loading…
Reference in New Issue