drm/msm: change CSC matrix selection logic for CDM block
CDM block is always using a limited quantization range matrix. This can be overridden to use a full range matrix if the sink supports override capability or the mode is a non-CEA mode. Adjust the matrix selection logic to accommodate these conditions. Change-Id: I708412a923fb0d47e798f35ebe14b4c2f1a72fc9 Signed-off-by: Abhinav Kumar <abhinavk@codeaurora.org>
This commit is contained in:
parent
39b5f76de0
commit
7c79cabfdf
8 changed files with 136 additions and 5 deletions
|
@ -2364,6 +2364,36 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector,
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool sde_hdmi_mode_needs_full_range(void *display)
|
||||
{
|
||||
struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
|
||||
struct drm_display_mode *mode;
|
||||
u32 mode_fmt_flags = 0;
|
||||
u32 cea_mode;
|
||||
|
||||
if (!hdmi_display) {
|
||||
SDE_ERROR("invalid input\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
mode = &hdmi_display->mode;
|
||||
/* Cache the format flags before clearing */
|
||||
mode_fmt_flags = mode->flags;
|
||||
/**
|
||||
* Clear the RGB/YUV format flags before calling upstream API
|
||||
* as the API also compares the flags and then returns a mode
|
||||
*/
|
||||
mode->flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK;
|
||||
cea_mode = drm_match_cea_mode(mode);
|
||||
/* Restore the format flags */
|
||||
mode->flags = mode_fmt_flags;
|
||||
|
||||
if (cea_mode > SDE_HDMI_VIC_640x480)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int sde_hdmi_connector_get_modes(struct drm_connector *connector, void *display)
|
||||
{
|
||||
struct sde_hdmi *hdmi_display = (struct sde_hdmi *)display;
|
||||
|
|
|
@ -482,6 +482,14 @@ int sde_hdmi_pre_kickoff(struct drm_connector *connector,
|
|||
void *display,
|
||||
struct msm_display_kickoff_params *params);
|
||||
|
||||
/*
|
||||
* sde_hdmi_mode_needs_full_range - does mode need full range
|
||||
* quantization
|
||||
* @display: Pointer to private display structure
|
||||
* Returns: true or false based on mode
|
||||
*/
|
||||
bool sde_hdmi_mode_needs_full_range(void *display);
|
||||
|
||||
#else /*#ifdef CONFIG_DRM_SDE_HDMI*/
|
||||
|
||||
static inline u32 sde_hdmi_get_num_of_displays(void)
|
||||
|
@ -596,5 +604,10 @@ static inline int sde_hdmi_set_property(struct drm_connector *connector,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline bool sde_hdmi_mode_needs_full_range(void *display)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif /*#else of CONFIG_DRM_SDE_HDMI*/
|
||||
#endif /* _SDE_HDMI_H_ */
|
||||
|
|
|
@ -582,18 +582,49 @@ static void _sde_hdmi_bridge_post_disable(struct drm_bridge *bridge)
|
|||
}
|
||||
|
||||
static void _sde_hdmi_bridge_set_avi_infoframe(struct hdmi *hdmi,
|
||||
const struct drm_display_mode *mode)
|
||||
struct drm_display_mode *mode)
|
||||
{
|
||||
u8 avi_iframe[HDMI_AVI_INFOFRAME_BUFFER_SIZE] = {0};
|
||||
u8 *avi_frame = &avi_iframe[HDMI_INFOFRAME_HEADER_SIZE];
|
||||
u8 checksum;
|
||||
u32 reg_val;
|
||||
u32 mode_fmt_flags = 0;
|
||||
struct hdmi_avi_infoframe info;
|
||||
struct drm_connector *connector;
|
||||
|
||||
if (!hdmi || !mode) {
|
||||
SDE_ERROR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
connector = hdmi->connector;
|
||||
|
||||
if (!connector) {
|
||||
SDE_ERROR("invalid input\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Cache the format flags before clearing */
|
||||
mode_fmt_flags = mode->flags;
|
||||
/**
|
||||
* Clear the RGB/YUV format flags before calling upstream API
|
||||
* as the API also compares the flags and then returns a mode
|
||||
*/
|
||||
mode->flags &= ~SDE_DRM_MODE_FLAG_FMT_MASK;
|
||||
drm_hdmi_avi_infoframe_from_display_mode(&info, mode);
|
||||
/* Restore the format flags */
|
||||
mode->flags = mode_fmt_flags;
|
||||
|
||||
if (mode->private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420)
|
||||
if (mode->private_flags & MSM_MODE_FLAG_COLOR_FORMAT_YCBCR420) {
|
||||
info.colorspace = HDMI_COLORSPACE_YUV420;
|
||||
/**
|
||||
* If sink supports quantization select,
|
||||
* override to full range
|
||||
*/
|
||||
if (connector->yuv_qs)
|
||||
info.ycc_quantization_range =
|
||||
HDMI_YCC_QUANTIZATION_RANGE_FULL;
|
||||
}
|
||||
|
||||
hdmi_avi_infoframe_pack(&info, avi_iframe, sizeof(avi_iframe));
|
||||
checksum = avi_iframe[HDMI_INFOFRAME_HEADER_SIZE - 1];
|
||||
|
|
|
@ -97,6 +97,8 @@
|
|||
#define HDMI_GET_MSB(x)(x >> 8)
|
||||
#define HDMI_GET_LSB(x)(x & 0xff)
|
||||
|
||||
#define SDE_HDMI_VIC_640x480 0x1
|
||||
|
||||
/*
|
||||
* Bits 1:0 in HDMI_HW_DDC_CTRL that dictate how the HDCP 2.2 RxStatus will be
|
||||
* read by the hardware
|
||||
|
|
|
@ -90,6 +90,28 @@ int sde_connector_pre_kickoff(struct drm_connector *connector)
|
|||
return rc;
|
||||
}
|
||||
|
||||
bool sde_connector_mode_needs_full_range(struct drm_connector *connector)
|
||||
{
|
||||
struct sde_connector *c_conn;
|
||||
|
||||
if (!connector) {
|
||||
SDE_ERROR("invalid argument\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
c_conn = to_sde_connector(connector);
|
||||
|
||||
if (!c_conn->display) {
|
||||
SDE_ERROR("invalid argument\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!c_conn->ops.mode_needs_full_range)
|
||||
return false;
|
||||
|
||||
return c_conn->ops.mode_needs_full_range(c_conn->display);
|
||||
}
|
||||
|
||||
static void sde_connector_destroy(struct drm_connector *connector)
|
||||
{
|
||||
struct sde_connector *c_conn;
|
||||
|
|
|
@ -135,6 +135,14 @@ struct sde_connector_ops {
|
|||
int (*pre_kickoff)(struct drm_connector *connector,
|
||||
void *display,
|
||||
struct msm_display_kickoff_params *params);
|
||||
|
||||
/**
|
||||
* mode_needs_full_range - does the mode need full range
|
||||
* quantization
|
||||
* @display: Pointer to private display structure
|
||||
* Returns: true or false based on whether full range is needed
|
||||
*/
|
||||
bool (*mode_needs_full_range)(void *display);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -327,5 +335,12 @@ int sde_connector_get_info(struct drm_connector *connector,
|
|||
*/
|
||||
int sde_connector_pre_kickoff(struct drm_connector *connector);
|
||||
|
||||
/**
|
||||
* sde_connector_mode_needs_full_range - query quantization type
|
||||
* for the connector mode
|
||||
* @connector: Pointer to drm connector object
|
||||
* Returns: true OR false based on connector mode
|
||||
*/
|
||||
bool sde_connector_mode_needs_full_range(struct drm_connector *connector);
|
||||
#endif /* _SDE_CONNECTOR_H_ */
|
||||
|
||||
|
|
|
@ -1417,6 +1417,7 @@ void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
|
|||
struct sde_encoder_virt *sde_enc = NULL;
|
||||
struct sde_hw_cdm *hw_cdm = phys_enc->hw_cdm;
|
||||
struct sde_hw_cdm_cfg *cdm_cfg = &phys_enc->cdm_cfg;
|
||||
struct drm_connector *connector = phys_enc->connector;
|
||||
int ret;
|
||||
u32 csc_type = 0;
|
||||
|
||||
|
@ -1476,10 +1477,26 @@ void sde_encoder_phys_setup_cdm(struct sde_encoder_phys *phys_enc,
|
|||
cdm_cfg->h_cdwn_type,
|
||||
cdm_cfg->v_cdwn_type);
|
||||
|
||||
if (output_type == CDM_CDWN_OUTPUT_HDMI)
|
||||
csc_type = SDE_CSC_RGB2YUV_601FR;
|
||||
else if (output_type == CDM_CDWN_OUTPUT_WB)
|
||||
/**
|
||||
* Choose CSC matrix based on following rules:
|
||||
* 1. If connector supports quantization select,
|
||||
* pick Full-Range for better quality.
|
||||
* 2. If non-CEA mode, then pick Full-Range as per CEA spec
|
||||
* 3. Otherwise, pick Limited-Range as all other CEA modes
|
||||
* need a limited range
|
||||
*/
|
||||
|
||||
if (output_type == CDM_CDWN_OUTPUT_HDMI) {
|
||||
if (connector && connector->yuv_qs)
|
||||
csc_type = SDE_CSC_RGB2YUV_601FR;
|
||||
else if (connector &&
|
||||
sde_connector_mode_needs_full_range(connector))
|
||||
csc_type = SDE_CSC_RGB2YUV_601FR;
|
||||
else
|
||||
csc_type = SDE_CSC_RGB2YUV_601L;
|
||||
} else if (output_type == CDM_CDWN_OUTPUT_WB) {
|
||||
csc_type = SDE_CSC_RGB2YUV_601L;
|
||||
}
|
||||
|
||||
if (hw_cdm && hw_cdm->ops.setup_csc_data) {
|
||||
ret = hw_cdm->ops.setup_csc_data(hw_cdm,
|
||||
|
|
|
@ -594,6 +594,7 @@ static int _sde_kms_setup_displays(struct drm_device *dev,
|
|||
.set_property = sde_hdmi_set_property,
|
||||
.get_property = sde_hdmi_get_property,
|
||||
.pre_kickoff = sde_hdmi_pre_kickoff,
|
||||
.mode_needs_full_range = sde_hdmi_mode_needs_full_range
|
||||
};
|
||||
struct msm_display_info info = {0};
|
||||
struct drm_encoder *encoder;
|
||||
|
|
Loading…
Add table
Reference in a new issue