Commit 57b5482b authored by Ville Syrjälä's avatar Ville Syrjälä

drm/i915: Introduce intel_csc_matrix struct

Introduce a structure that can hold our CSC matrices. In there
we shall have the preoffsets, postoffsets, and coefficients,
all in platform specific format (at least for now).

We shall start by converting the ilk+ code to make use of
the new structure. chv will come later.
Signed-off-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230329135002.3096-3-ville.syrjala@linux.intel.comReviewed-by: default avatarAnkit Nautiyal <ankit.k.nautiyal@intel.com>
parent 404c3acd
...@@ -120,40 +120,42 @@ struct intel_color_funcs { ...@@ -120,40 +120,42 @@ struct intel_color_funcs {
#define ILK_CSC_COEFF_LIMITED_RANGE ((235 - 16) << (12 - 8)) /* exponent 0 */ #define ILK_CSC_COEFF_LIMITED_RANGE ((235 - 16) << (12 - 8)) /* exponent 0 */
#define ILK_CSC_POSTOFF_LIMITED_RANGE (16 << (12 - 8)) #define ILK_CSC_POSTOFF_LIMITED_RANGE (16 << (12 - 8))
/* Nop pre/post offsets */ static const struct intel_csc_matrix ilk_csc_matrix_identity = {
static const u16 ilk_csc_off_zero[3] = {}; .preoff = {},
.coeff = {
/* Identity matrix */
static const u16 ilk_csc_coeff_identity[9] = {
ILK_CSC_COEFF_1_0, 0, 0, ILK_CSC_COEFF_1_0, 0, 0,
0, ILK_CSC_COEFF_1_0, 0, 0, ILK_CSC_COEFF_1_0, 0,
0, 0, ILK_CSC_COEFF_1_0, 0, 0, ILK_CSC_COEFF_1_0,
}; },
.postoff = {},
/* Limited range RGB post offsets */
static const u16 ilk_csc_postoff_limited_range[3] = {
ILK_CSC_POSTOFF_LIMITED_RANGE,
ILK_CSC_POSTOFF_LIMITED_RANGE,
ILK_CSC_POSTOFF_LIMITED_RANGE,
}; };
/* Full range RGB -> limited range RGB matrix */ /* Full range RGB -> limited range RGB matrix */
static const u16 ilk_csc_coeff_limited_range[9] = { static const struct intel_csc_matrix ilk_csc_matrix_limited_range = {
.preoff = {},
.coeff = {
ILK_CSC_COEFF_LIMITED_RANGE, 0, 0, ILK_CSC_COEFF_LIMITED_RANGE, 0, 0,
0, ILK_CSC_COEFF_LIMITED_RANGE, 0, 0, ILK_CSC_COEFF_LIMITED_RANGE, 0,
0, 0, ILK_CSC_COEFF_LIMITED_RANGE, 0, 0, ILK_CSC_COEFF_LIMITED_RANGE,
},
.postoff = {
ILK_CSC_POSTOFF_LIMITED_RANGE,
ILK_CSC_POSTOFF_LIMITED_RANGE,
ILK_CSC_POSTOFF_LIMITED_RANGE,
},
}; };
/* BT.709 full range RGB -> limited range YCbCr matrix */ /* BT.709 full range RGB -> limited range YCbCr matrix */
static const u16 ilk_csc_coeff_rgb_to_ycbcr[9] = { static const struct intel_csc_matrix ilk_csc_matrix_rgb_to_ycbcr = {
.preoff = {},
.coeff = {
0x1e08, 0x9cc0, 0xb528, 0x1e08, 0x9cc0, 0xb528,
0x2ba8, 0x09d8, 0x37e8, 0x2ba8, 0x09d8, 0x37e8,
0xbce8, 0x9ad8, 0x1e08, 0xbce8, 0x9ad8, 0x1e08,
}; },
.postoff = {
/* Limited range YCbCr post offsets */
static const u16 ilk_csc_postoff_rgb_to_ycbcr[3] = {
0x0800, 0x0100, 0x0800, 0x0800, 0x0100, 0x0800,
},
}; };
static bool lut_is_legacy(const struct drm_property_blob *lut) static bool lut_is_legacy(const struct drm_property_blob *lut)
...@@ -188,69 +190,66 @@ static u64 *ctm_mult_by_limited(u64 *result, const u64 *input) ...@@ -188,69 +190,66 @@ static u64 *ctm_mult_by_limited(u64 *result, const u64 *input)
} }
static void ilk_update_pipe_csc(struct intel_crtc *crtc, static void ilk_update_pipe_csc(struct intel_crtc *crtc,
const u16 preoff[3], const struct intel_csc_matrix *csc)
const u16 coeff[9],
const u16 postoff[3])
{ {
struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe; enum pipe pipe = crtc->pipe;
intel_de_write_fw(i915, PIPE_CSC_PREOFF_HI(pipe), preoff[0]); intel_de_write_fw(i915, PIPE_CSC_PREOFF_HI(pipe), csc->preoff[0]);
intel_de_write_fw(i915, PIPE_CSC_PREOFF_ME(pipe), preoff[1]); intel_de_write_fw(i915, PIPE_CSC_PREOFF_ME(pipe), csc->preoff[1]);
intel_de_write_fw(i915, PIPE_CSC_PREOFF_LO(pipe), preoff[2]); intel_de_write_fw(i915, PIPE_CSC_PREOFF_LO(pipe), csc->preoff[2]);
intel_de_write_fw(i915, PIPE_CSC_COEFF_RY_GY(pipe), intel_de_write_fw(i915, PIPE_CSC_COEFF_RY_GY(pipe),
coeff[0] << 16 | coeff[1]); csc->coeff[0] << 16 | csc->coeff[1]);
intel_de_write_fw(i915, PIPE_CSC_COEFF_BY(pipe), coeff[2] << 16); intel_de_write_fw(i915, PIPE_CSC_COEFF_BY(pipe),
csc->coeff[2] << 16);
intel_de_write_fw(i915, PIPE_CSC_COEFF_RU_GU(pipe), intel_de_write_fw(i915, PIPE_CSC_COEFF_RU_GU(pipe),
coeff[3] << 16 | coeff[4]); csc->coeff[3] << 16 | csc->coeff[4]);
intel_de_write_fw(i915, PIPE_CSC_COEFF_BU(pipe), coeff[5] << 16); intel_de_write_fw(i915, PIPE_CSC_COEFF_BU(pipe),
csc->coeff[5] << 16);
intel_de_write_fw(i915, PIPE_CSC_COEFF_RV_GV(pipe), intel_de_write_fw(i915, PIPE_CSC_COEFF_RV_GV(pipe),
coeff[6] << 16 | coeff[7]); csc->coeff[6] << 16 | csc->coeff[7]);
intel_de_write_fw(i915, PIPE_CSC_COEFF_BV(pipe), coeff[8] << 16); intel_de_write_fw(i915, PIPE_CSC_COEFF_BV(pipe),
csc->coeff[8] << 16);
if (DISPLAY_VER(i915) >= 7) { if (DISPLAY_VER(i915) < 7)
intel_de_write_fw(i915, PIPE_CSC_POSTOFF_HI(pipe), return;
postoff[0]);
intel_de_write_fw(i915, PIPE_CSC_POSTOFF_ME(pipe), intel_de_write_fw(i915, PIPE_CSC_POSTOFF_HI(pipe), csc->postoff[0]);
postoff[1]); intel_de_write_fw(i915, PIPE_CSC_POSTOFF_ME(pipe), csc->postoff[1]);
intel_de_write_fw(i915, PIPE_CSC_POSTOFF_LO(pipe), intel_de_write_fw(i915, PIPE_CSC_POSTOFF_LO(pipe), csc->postoff[2]);
postoff[2]);
}
} }
static void icl_update_output_csc(struct intel_crtc *crtc, static void icl_update_output_csc(struct intel_crtc *crtc,
const u16 preoff[3], const struct intel_csc_matrix *csc)
const u16 coeff[9],
const u16 postoff[3])
{ {
struct drm_i915_private *i915 = to_i915(crtc->base.dev); struct drm_i915_private *i915 = to_i915(crtc->base.dev);
enum pipe pipe = crtc->pipe; enum pipe pipe = crtc->pipe;
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_HI(pipe), preoff[0]); intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_HI(pipe), csc->preoff[0]);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_ME(pipe), preoff[1]); intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_ME(pipe), csc->preoff[1]);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_LO(pipe), preoff[2]); intel_de_write_fw(i915, PIPE_CSC_OUTPUT_PREOFF_LO(pipe), csc->preoff[2]);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe), intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RY_GY(pipe),
coeff[0] << 16 | coeff[1]); csc->coeff[0] << 16 | csc->coeff[1]);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BY(pipe), intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BY(pipe),
coeff[2] << 16); csc->coeff[2] << 16);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe), intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RU_GU(pipe),
coeff[3] << 16 | coeff[4]); csc->coeff[3] << 16 | csc->coeff[4]);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BU(pipe), intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BU(pipe),
coeff[5] << 16); csc->coeff[5] << 16);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe), intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_RV_GV(pipe),
coeff[6] << 16 | coeff[7]); csc->coeff[6] << 16 | csc->coeff[7]);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BV(pipe), intel_de_write_fw(i915, PIPE_CSC_OUTPUT_COEFF_BV(pipe),
coeff[8] << 16); csc->coeff[8] << 16);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe), postoff[0]); intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_HI(pipe), csc->postoff[0]);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe), postoff[1]); intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_ME(pipe), csc->postoff[1]);
intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), postoff[2]); intel_de_write_fw(i915, PIPE_CSC_OUTPUT_POSTOFF_LO(pipe), csc->postoff[2]);
} }
static bool ilk_limited_range(const struct intel_crtc_state *crtc_state) static bool ilk_limited_range(const struct intel_crtc_state *crtc_state)
...@@ -294,13 +293,20 @@ static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state) ...@@ -294,13 +293,20 @@ static bool ilk_csc_limited_range(const struct intel_crtc_state *crtc_state)
} }
static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state, static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state,
u16 coeffs[9], bool limited_color_range) struct intel_csc_matrix *csc,
bool limited_color_range)
{ {
const struct drm_color_ctm *ctm = crtc_state->hw.ctm->data; const struct drm_color_ctm *ctm = crtc_state->hw.ctm->data;
const u64 *input; const u64 *input;
u64 temp[9]; u64 temp[9];
int i; int i;
/* for preoff/postoff */
if (limited_color_range)
*csc = ilk_csc_matrix_limited_range;
else
*csc = ilk_csc_matrix_identity;
if (limited_color_range) if (limited_color_range)
input = ctm_mult_by_limited(temp, ctm->matrix); input = ctm_mult_by_limited(temp, ctm->matrix);
else else
...@@ -319,28 +325,28 @@ static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state, ...@@ -319,28 +325,28 @@ static void ilk_csc_convert_ctm(const struct intel_crtc_state *crtc_state,
*/ */
abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1); abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1);
coeffs[i] = 0; csc->coeff[i] = 0;
/* sign bit */ /* sign bit */
if (CTM_COEFF_NEGATIVE(input[i])) if (CTM_COEFF_NEGATIVE(input[i]))
coeffs[i] |= 1 << 15; csc->coeff[i] |= 1 << 15;
if (abs_coeff < CTM_COEFF_0_125) if (abs_coeff < CTM_COEFF_0_125)
coeffs[i] |= (3 << 12) | csc->coeff[i] |= (3 << 12) |
ILK_CSC_COEFF_FP(abs_coeff, 12); ILK_CSC_COEFF_FP(abs_coeff, 12);
else if (abs_coeff < CTM_COEFF_0_25) else if (abs_coeff < CTM_COEFF_0_25)
coeffs[i] |= (2 << 12) | csc->coeff[i] |= (2 << 12) |
ILK_CSC_COEFF_FP(abs_coeff, 11); ILK_CSC_COEFF_FP(abs_coeff, 11);
else if (abs_coeff < CTM_COEFF_0_5) else if (abs_coeff < CTM_COEFF_0_5)
coeffs[i] |= (1 << 12) | csc->coeff[i] |= (1 << 12) |
ILK_CSC_COEFF_FP(abs_coeff, 10); ILK_CSC_COEFF_FP(abs_coeff, 10);
else if (abs_coeff < CTM_COEFF_1_0) else if (abs_coeff < CTM_COEFF_1_0)
coeffs[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9); csc->coeff[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9);
else if (abs_coeff < CTM_COEFF_2_0) else if (abs_coeff < CTM_COEFF_2_0)
coeffs[i] |= (7 << 12) | csc->coeff[i] |= (7 << 12) |
ILK_CSC_COEFF_FP(abs_coeff, 8); ILK_CSC_COEFF_FP(abs_coeff, 8);
else else
coeffs[i] |= (6 << 12) | csc->coeff[i] |= (6 << 12) |
ILK_CSC_COEFF_FP(abs_coeff, 7); ILK_CSC_COEFF_FP(abs_coeff, 7);
} }
} }
...@@ -352,21 +358,15 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state) ...@@ -352,21 +358,15 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state)
bool limited_color_range = ilk_csc_limited_range(crtc_state); bool limited_color_range = ilk_csc_limited_range(crtc_state);
if (crtc_state->hw.ctm) { if (crtc_state->hw.ctm) {
u16 coeff[9]; struct intel_csc_matrix tmp;
ilk_csc_convert_ctm(crtc_state, coeff, limited_color_range); ilk_csc_convert_ctm(crtc_state, &tmp, limited_color_range);
ilk_update_pipe_csc(crtc, ilk_csc_off_zero, coeff,
limited_color_range ? ilk_update_pipe_csc(crtc, &tmp);
ilk_csc_postoff_limited_range :
ilk_csc_off_zero);
} else if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) { } else if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) {
ilk_update_pipe_csc(crtc, ilk_csc_off_zero, ilk_update_pipe_csc(crtc, &ilk_csc_matrix_rgb_to_ycbcr);
ilk_csc_coeff_rgb_to_ycbcr,
ilk_csc_postoff_rgb_to_ycbcr);
} else if (limited_color_range) { } else if (limited_color_range) {
ilk_update_pipe_csc(crtc, ilk_csc_off_zero, ilk_update_pipe_csc(crtc, &ilk_csc_matrix_limited_range);
ilk_csc_coeff_limited_range,
ilk_csc_postoff_limited_range);
} else if (crtc_state->csc_enable) { } else if (crtc_state->csc_enable) {
/* /*
* On GLK both pipe CSC and degamma LUT are controlled * On GLK both pipe CSC and degamma LUT are controlled
...@@ -376,9 +376,7 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state) ...@@ -376,9 +376,7 @@ static void ilk_load_csc_matrix(const struct intel_crtc_state *crtc_state)
*/ */
drm_WARN_ON(&i915->drm, !IS_GEMINILAKE(i915)); drm_WARN_ON(&i915->drm, !IS_GEMINILAKE(i915));
ilk_update_pipe_csc(crtc, ilk_csc_off_zero, ilk_update_pipe_csc(crtc, &ilk_csc_matrix_identity);
ilk_csc_coeff_identity,
ilk_csc_off_zero);
} }
} }
...@@ -387,21 +385,17 @@ static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state) ...@@ -387,21 +385,17 @@ static void icl_load_csc_matrix(const struct intel_crtc_state *crtc_state)
struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc); struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
if (crtc_state->hw.ctm) { if (crtc_state->hw.ctm) {
u16 coeff[9]; struct intel_csc_matrix tmp;
ilk_csc_convert_ctm(crtc_state, &tmp, false);
ilk_csc_convert_ctm(crtc_state, coeff, false); ilk_update_pipe_csc(crtc, &tmp);
ilk_update_pipe_csc(crtc, ilk_csc_off_zero,
coeff, ilk_csc_off_zero);
} }
if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) { if (crtc_state->output_format != INTEL_OUTPUT_FORMAT_RGB) {
icl_update_output_csc(crtc, ilk_csc_off_zero, icl_update_output_csc(crtc, &ilk_csc_matrix_rgb_to_ycbcr);
ilk_csc_coeff_rgb_to_ycbcr,
ilk_csc_postoff_rgb_to_ycbcr);
} else if (crtc_state->limited_color_range) { } else if (crtc_state->limited_color_range) {
icl_update_output_csc(crtc, ilk_csc_off_zero, icl_update_output_csc(crtc, &ilk_csc_matrix_limited_range);
ilk_csc_coeff_limited_range,
ilk_csc_postoff_limited_range);
} }
} }
......
...@@ -980,6 +980,12 @@ struct intel_link_m_n { ...@@ -980,6 +980,12 @@ struct intel_link_m_n {
u32 link_n; u32 link_n;
}; };
struct intel_csc_matrix {
u16 coeff[9];
u16 preoff[3];
u16 postoff[3];
};
struct intel_crtc_state { struct intel_crtc_state {
/* /*
* uapi (drm) state. This is the software state shown to userspace. * uapi (drm) state. This is the software state shown to userspace.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment