|
32 | 32 | #include "intel_display_utils.h" |
33 | 33 | #include "intel_dsb.h" |
34 | 34 | #include "intel_vrr.h" |
| 35 | +#include "skl_universal_plane.h" |
| 36 | +#include "skl_universal_plane_regs.h" |
35 | 37 |
|
36 | 38 | struct intel_color_funcs { |
37 | 39 | int (*color_check)(struct intel_atomic_state *state, |
@@ -87,6 +89,14 @@ struct intel_color_funcs { |
87 | 89 | * Read config other than LUTs and CSCs, before them. Optional. |
88 | 90 | */ |
89 | 91 | void (*get_config)(struct intel_crtc_state *crtc_state); |
| 92 | + |
| 93 | + /* Plane CSC*/ |
| 94 | + void (*load_plane_csc_matrix)(struct intel_dsb *dsb, |
| 95 | + const struct intel_plane_state *plane_state); |
| 96 | + |
| 97 | + /* Plane Pre/Post CSC */ |
| 98 | + void (*load_plane_luts)(struct intel_dsb *dsb, |
| 99 | + const struct intel_plane_state *plane_state); |
90 | 100 | }; |
91 | 101 |
|
92 | 102 | #define CTM_COEFF_SIGN (1ULL << 63) |
@@ -609,6 +619,8 @@ static u16 ctm_to_twos_complement(u64 coeff, int int_bits, int frac_bits) |
609 | 619 | if (CTM_COEFF_NEGATIVE(coeff)) |
610 | 620 | c = -c; |
611 | 621 |
|
| 622 | + int_bits = max(int_bits, 1); |
| 623 | + |
612 | 624 | c = clamp(c, -(s64)BIT(int_bits + frac_bits - 1), |
613 | 625 | (s64)(BIT(int_bits + frac_bits - 1) - 1)); |
614 | 626 |
|
@@ -3836,6 +3848,266 @@ static void icl_read_luts(struct intel_crtc_state *crtc_state) |
3836 | 3848 | } |
3837 | 3849 | } |
3838 | 3850 |
|
| 3851 | +static void |
| 3852 | +xelpd_load_plane_csc_matrix(struct intel_dsb *dsb, |
| 3853 | + const struct intel_plane_state *plane_state) |
| 3854 | +{ |
| 3855 | + struct intel_display *display = to_intel_display(plane_state); |
| 3856 | + const struct drm_plane_state *state = &plane_state->uapi; |
| 3857 | + enum pipe pipe = to_intel_plane(state->plane)->pipe; |
| 3858 | + enum plane_id plane = to_intel_plane(state->plane)->id; |
| 3859 | + const struct drm_property_blob *blob = plane_state->hw.ctm; |
| 3860 | + struct drm_color_ctm_3x4 *ctm; |
| 3861 | + const u64 *input; |
| 3862 | + u16 coeffs[9] = {}; |
| 3863 | + int i, j; |
| 3864 | + |
| 3865 | + if (!icl_is_hdr_plane(display, plane) || !blob) |
| 3866 | + return; |
| 3867 | + |
| 3868 | + ctm = blob->data; |
| 3869 | + input = ctm->matrix; |
| 3870 | + |
| 3871 | + /* |
| 3872 | + * Convert fixed point S31.32 input to format supported by the |
| 3873 | + * hardware. |
| 3874 | + */ |
| 3875 | + for (i = 0, j = 0; i < ARRAY_SIZE(coeffs); i++) { |
| 3876 | + u64 abs_coeff = ((1ULL << 63) - 1) & input[j]; |
| 3877 | + |
| 3878 | + /* |
| 3879 | + * Clamp input value to min/max supported by |
| 3880 | + * hardware. |
| 3881 | + */ |
| 3882 | + abs_coeff = clamp_val(abs_coeff, 0, CTM_COEFF_4_0 - 1); |
| 3883 | + |
| 3884 | + /* sign bit */ |
| 3885 | + if (CTM_COEFF_NEGATIVE(input[j])) |
| 3886 | + coeffs[i] |= 1 << 15; |
| 3887 | + |
| 3888 | + if (abs_coeff < CTM_COEFF_0_125) |
| 3889 | + coeffs[i] |= (3 << 12) | |
| 3890 | + ILK_CSC_COEFF_FP(abs_coeff, 12); |
| 3891 | + else if (abs_coeff < CTM_COEFF_0_25) |
| 3892 | + coeffs[i] |= (2 << 12) | |
| 3893 | + ILK_CSC_COEFF_FP(abs_coeff, 11); |
| 3894 | + else if (abs_coeff < CTM_COEFF_0_5) |
| 3895 | + coeffs[i] |= (1 << 12) | |
| 3896 | + ILK_CSC_COEFF_FP(abs_coeff, 10); |
| 3897 | + else if (abs_coeff < CTM_COEFF_1_0) |
| 3898 | + coeffs[i] |= ILK_CSC_COEFF_FP(abs_coeff, 9); |
| 3899 | + else if (abs_coeff < CTM_COEFF_2_0) |
| 3900 | + coeffs[i] |= (7 << 12) | |
| 3901 | + ILK_CSC_COEFF_FP(abs_coeff, 8); |
| 3902 | + else |
| 3903 | + coeffs[i] |= (6 << 12) | |
| 3904 | + ILK_CSC_COEFF_FP(abs_coeff, 7); |
| 3905 | + |
| 3906 | + /* Skip postoffs */ |
| 3907 | + if (!((j + 2) % 4)) |
| 3908 | + j += 2; |
| 3909 | + else |
| 3910 | + j++; |
| 3911 | + } |
| 3912 | + |
| 3913 | + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 0), |
| 3914 | + coeffs[0] << 16 | coeffs[1]); |
| 3915 | + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 1), |
| 3916 | + coeffs[2] << 16); |
| 3917 | + |
| 3918 | + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 2), |
| 3919 | + coeffs[3] << 16 | coeffs[4]); |
| 3920 | + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 3), |
| 3921 | + coeffs[5] << 16); |
| 3922 | + |
| 3923 | + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 4), |
| 3924 | + coeffs[6] << 16 | coeffs[7]); |
| 3925 | + intel_de_write_dsb(display, dsb, PLANE_CSC_COEFF(pipe, plane, 5), |
| 3926 | + coeffs[8] << 16); |
| 3927 | + |
| 3928 | + intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 0), 0); |
| 3929 | + intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 1), 0); |
| 3930 | + intel_de_write_dsb(display, dsb, PLANE_CSC_PREOFF(pipe, plane, 2), 0); |
| 3931 | + |
| 3932 | + /* |
| 3933 | + * Conversion from S31.32 to S0.12. BIT[12] is the signed bit |
| 3934 | + */ |
| 3935 | + intel_de_write_dsb(display, dsb, |
| 3936 | + PLANE_CSC_POSTOFF(pipe, plane, 0), |
| 3937 | + ctm_to_twos_complement(input[3], 0, 12)); |
| 3938 | + intel_de_write_dsb(display, dsb, |
| 3939 | + PLANE_CSC_POSTOFF(pipe, plane, 1), |
| 3940 | + ctm_to_twos_complement(input[7], 0, 12)); |
| 3941 | + intel_de_write_dsb(display, dsb, |
| 3942 | + PLANE_CSC_POSTOFF(pipe, plane, 2), |
| 3943 | + ctm_to_twos_complement(input[11], 0, 12)); |
| 3944 | +} |
| 3945 | + |
| 3946 | +static void |
| 3947 | +xelpd_program_plane_pre_csc_lut(struct intel_dsb *dsb, |
| 3948 | + const struct intel_plane_state *plane_state) |
| 3949 | +{ |
| 3950 | + struct intel_display *display = to_intel_display(plane_state); |
| 3951 | + const struct drm_plane_state *state = &plane_state->uapi; |
| 3952 | + enum pipe pipe = to_intel_plane(state->plane)->pipe; |
| 3953 | + enum plane_id plane = to_intel_plane(state->plane)->id; |
| 3954 | + const struct drm_color_lut32 *pre_csc_lut = plane_state->hw.degamma_lut->data; |
| 3955 | + u32 i, lut_size; |
| 3956 | + |
| 3957 | + if (icl_is_hdr_plane(display, plane)) { |
| 3958 | + lut_size = 128; |
| 3959 | + |
| 3960 | + intel_de_write_dsb(display, dsb, |
| 3961 | + PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), |
| 3962 | + PLANE_PAL_PREC_AUTO_INCREMENT); |
| 3963 | + |
| 3964 | + if (pre_csc_lut) { |
| 3965 | + for (i = 0; i < lut_size; i++) { |
| 3966 | + u32 lut_val = drm_color_lut32_extract(pre_csc_lut[i].green, 24); |
| 3967 | + |
| 3968 | + intel_de_write_dsb(display, dsb, |
| 3969 | + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), |
| 3970 | + lut_val); |
| 3971 | + } |
| 3972 | + |
| 3973 | + /* Program the max register to clamp values > 1.0. */ |
| 3974 | + /* TODO: Restrict to 0x7ffffff */ |
| 3975 | + do { |
| 3976 | + intel_de_write_dsb(display, dsb, |
| 3977 | + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), |
| 3978 | + (1 << 24)); |
| 3979 | + } while (i++ > 130); |
| 3980 | + } else { |
| 3981 | + for (i = 0; i < lut_size; i++) { |
| 3982 | + u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1); |
| 3983 | + |
| 3984 | + intel_de_write_dsb(display, dsb, |
| 3985 | + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), v); |
| 3986 | + } |
| 3987 | + |
| 3988 | + do { |
| 3989 | + intel_de_write_dsb(display, dsb, |
| 3990 | + PLANE_PRE_CSC_GAMC_DATA_ENH(pipe, plane, 0), |
| 3991 | + 1 << 24); |
| 3992 | + } while (i++ < 130); |
| 3993 | + } |
| 3994 | + |
| 3995 | + intel_de_write_dsb(display, dsb, PLANE_PRE_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0); |
| 3996 | + } |
| 3997 | +} |
| 3998 | + |
| 3999 | +static void |
| 4000 | +xelpd_program_plane_post_csc_lut(struct intel_dsb *dsb, |
| 4001 | + const struct intel_plane_state *plane_state) |
| 4002 | +{ |
| 4003 | + struct intel_display *display = to_intel_display(plane_state); |
| 4004 | + const struct drm_plane_state *state = &plane_state->uapi; |
| 4005 | + enum pipe pipe = to_intel_plane(state->plane)->pipe; |
| 4006 | + enum plane_id plane = to_intel_plane(state->plane)->id; |
| 4007 | + const struct drm_color_lut32 *post_csc_lut = plane_state->hw.gamma_lut->data; |
| 4008 | + u32 i, lut_size, lut_val; |
| 4009 | + |
| 4010 | + if (icl_is_hdr_plane(display, plane)) { |
| 4011 | + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), |
| 4012 | + PLANE_PAL_PREC_AUTO_INCREMENT); |
| 4013 | + /* TODO: Add macro */ |
| 4014 | + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), |
| 4015 | + PLANE_PAL_PREC_AUTO_INCREMENT); |
| 4016 | + if (post_csc_lut) { |
| 4017 | + lut_size = 32; |
| 4018 | + for (i = 0; i < lut_size; i++) { |
| 4019 | + lut_val = drm_color_lut32_extract(post_csc_lut[i].green, 24); |
| 4020 | + |
| 4021 | + intel_de_write_dsb(display, dsb, |
| 4022 | + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), |
| 4023 | + lut_val); |
| 4024 | + } |
| 4025 | + |
| 4026 | + /* Segment 2 */ |
| 4027 | + do { |
| 4028 | + intel_de_write_dsb(display, dsb, |
| 4029 | + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), |
| 4030 | + (1 << 24)); |
| 4031 | + } while (i++ < 34); |
| 4032 | + } else { |
| 4033 | + /*TODO: Add for segment 0 */ |
| 4034 | + lut_size = 32; |
| 4035 | + for (i = 0; i < lut_size; i++) { |
| 4036 | + u32 v = (i * ((1 << 24) - 1)) / (lut_size - 1); |
| 4037 | + |
| 4038 | + intel_de_write_dsb(display, dsb, |
| 4039 | + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), v); |
| 4040 | + } |
| 4041 | + |
| 4042 | + do { |
| 4043 | + intel_de_write_dsb(display, dsb, |
| 4044 | + PLANE_POST_CSC_GAMC_DATA_ENH(pipe, plane, 0), |
| 4045 | + 1 << 24); |
| 4046 | + } while (i++ < 34); |
| 4047 | + } |
| 4048 | + |
| 4049 | + intel_de_write_dsb(display, dsb, PLANE_POST_CSC_GAMC_INDEX_ENH(pipe, plane, 0), 0); |
| 4050 | + intel_de_write_dsb(display, dsb, |
| 4051 | + PLANE_POST_CSC_GAMC_SEG0_INDEX_ENH(pipe, plane, 0), 0); |
| 4052 | + } |
| 4053 | +} |
| 4054 | + |
| 4055 | +static void |
| 4056 | +xelpd_plane_load_luts(struct intel_dsb *dsb, const struct intel_plane_state *plane_state) |
| 4057 | +{ |
| 4058 | + if (plane_state->hw.degamma_lut) |
| 4059 | + xelpd_program_plane_pre_csc_lut(dsb, plane_state); |
| 4060 | + |
| 4061 | + if (plane_state->hw.gamma_lut) |
| 4062 | + xelpd_program_plane_post_csc_lut(dsb, plane_state); |
| 4063 | +} |
| 4064 | + |
| 4065 | +static u32 glk_3dlut_10(const struct drm_color_lut32 *color) |
| 4066 | +{ |
| 4067 | + return REG_FIELD_PREP(LUT_3D_DATA_RED_MASK, drm_color_lut32_extract(color->red, 10)) | |
| 4068 | + REG_FIELD_PREP(LUT_3D_DATA_GREEN_MASK, drm_color_lut32_extract(color->green, 10)) | |
| 4069 | + REG_FIELD_PREP(LUT_3D_DATA_BLUE_MASK, drm_color_lut32_extract(color->blue, 10)); |
| 4070 | +} |
| 4071 | + |
| 4072 | +static void glk_load_lut_3d(struct intel_dsb *dsb, |
| 4073 | + struct intel_crtc *crtc, |
| 4074 | + const struct drm_property_blob *blob) |
| 4075 | +{ |
| 4076 | + struct intel_display *display = to_intel_display(crtc->base.dev); |
| 4077 | + const struct drm_color_lut32 *lut = blob->data; |
| 4078 | + int i, lut_size = drm_color_lut32_size(blob); |
| 4079 | + enum pipe pipe = crtc->pipe; |
| 4080 | + |
| 4081 | + if (!dsb && intel_de_read(display, LUT_3D_CTL(pipe)) & LUT_3D_READY) { |
| 4082 | + drm_err(display->drm, "[CRTC:%d:%s] 3D LUT not ready, not loading LUTs\n", |
| 4083 | + crtc->base.base.id, crtc->base.name); |
| 4084 | + return; |
| 4085 | + } |
| 4086 | + |
| 4087 | + intel_de_write_dsb(display, dsb, LUT_3D_INDEX(pipe), LUT_3D_AUTO_INCREMENT); |
| 4088 | + for (i = 0; i < lut_size; i++) |
| 4089 | + intel_de_write_dsb(display, dsb, LUT_3D_DATA(pipe), glk_3dlut_10(&lut[i])); |
| 4090 | + intel_de_write_dsb(display, dsb, LUT_3D_INDEX(pipe), 0); |
| 4091 | +} |
| 4092 | + |
| 4093 | +static void glk_lut_3d_commit(struct intel_dsb *dsb, struct intel_crtc *crtc, bool enable) |
| 4094 | +{ |
| 4095 | + struct intel_display *display = to_intel_display(crtc); |
| 4096 | + enum pipe pipe = crtc->pipe; |
| 4097 | + u32 val = 0; |
| 4098 | + |
| 4099 | + if (!dsb && intel_de_read(display, LUT_3D_CTL(pipe)) & LUT_3D_READY) { |
| 4100 | + drm_err(display->drm, "[CRTC:%d:%s] 3D LUT not ready, not committing change\n", |
| 4101 | + crtc->base.base.id, crtc->base.name); |
| 4102 | + return; |
| 4103 | + } |
| 4104 | + |
| 4105 | + if (enable) |
| 4106 | + val = LUT_3D_ENABLE | LUT_3D_READY | LUT_3D_BIND_PLANE_1; |
| 4107 | + |
| 4108 | + intel_de_write_dsb(display, dsb, LUT_3D_CTL(pipe), val); |
| 4109 | +} |
| 4110 | + |
3839 | 4111 | static const struct intel_color_funcs chv_color_funcs = { |
3840 | 4112 | .color_check = chv_color_check, |
3841 | 4113 | .color_commit_arm = i9xx_color_commit_arm, |
@@ -3883,6 +4155,8 @@ static const struct intel_color_funcs tgl_color_funcs = { |
3883 | 4155 | .lut_equal = icl_lut_equal, |
3884 | 4156 | .read_csc = icl_read_csc, |
3885 | 4157 | .get_config = skl_get_config, |
| 4158 | + .load_plane_csc_matrix = xelpd_load_plane_csc_matrix, |
| 4159 | + .load_plane_luts = xelpd_plane_load_luts, |
3886 | 4160 | }; |
3887 | 4161 |
|
3888 | 4162 | static const struct intel_color_funcs icl_color_funcs = { |
@@ -3963,6 +4237,67 @@ static const struct intel_color_funcs ilk_color_funcs = { |
3963 | 4237 | .get_config = ilk_get_config, |
3964 | 4238 | }; |
3965 | 4239 |
|
| 4240 | +void intel_color_plane_commit_arm(struct intel_dsb *dsb, |
| 4241 | + const struct intel_plane_state *plane_state) |
| 4242 | +{ |
| 4243 | + struct intel_display *display = to_intel_display(plane_state); |
| 4244 | + struct intel_crtc *crtc = to_intel_crtc(plane_state->uapi.crtc); |
| 4245 | + |
| 4246 | + if (crtc && intel_color_crtc_has_3dlut(display, crtc->pipe)) |
| 4247 | + glk_lut_3d_commit(dsb, crtc, !!plane_state->hw.lut_3d); |
| 4248 | +} |
| 4249 | + |
| 4250 | +static void |
| 4251 | +intel_color_load_plane_csc_matrix(struct intel_dsb *dsb, |
| 4252 | + const struct intel_plane_state *plane_state) |
| 4253 | +{ |
| 4254 | + struct intel_display *display = to_intel_display(plane_state); |
| 4255 | + |
| 4256 | + if (display->funcs.color->load_plane_csc_matrix) |
| 4257 | + display->funcs.color->load_plane_csc_matrix(dsb, plane_state); |
| 4258 | +} |
| 4259 | + |
| 4260 | +static void |
| 4261 | +intel_color_load_plane_luts(struct intel_dsb *dsb, |
| 4262 | + const struct intel_plane_state *plane_state) |
| 4263 | +{ |
| 4264 | + struct intel_display *display = to_intel_display(plane_state); |
| 4265 | + |
| 4266 | + if (display->funcs.color->load_plane_luts) |
| 4267 | + display->funcs.color->load_plane_luts(dsb, plane_state); |
| 4268 | +} |
| 4269 | + |
| 4270 | +bool |
| 4271 | +intel_color_crtc_has_3dlut(struct intel_display *display, enum pipe pipe) |
| 4272 | +{ |
| 4273 | + if (DISPLAY_VER(display) >= 12) |
| 4274 | + return pipe == PIPE_A || pipe == PIPE_B; |
| 4275 | + else |
| 4276 | + return false; |
| 4277 | +} |
| 4278 | + |
| 4279 | +static void |
| 4280 | +intel_color_load_3dlut(struct intel_dsb *dsb, |
| 4281 | + const struct intel_plane_state *plane_state) |
| 4282 | +{ |
| 4283 | + struct intel_display *display = to_intel_display(plane_state); |
| 4284 | + struct intel_crtc *crtc = to_intel_crtc(plane_state->uapi.crtc); |
| 4285 | + |
| 4286 | + if (crtc && intel_color_crtc_has_3dlut(display, crtc->pipe)) |
| 4287 | + glk_load_lut_3d(dsb, crtc, plane_state->hw.lut_3d); |
| 4288 | +} |
| 4289 | + |
| 4290 | +void intel_color_plane_program_pipeline(struct intel_dsb *dsb, |
| 4291 | + const struct intel_plane_state *plane_state) |
| 4292 | +{ |
| 4293 | + if (plane_state->hw.ctm) |
| 4294 | + intel_color_load_plane_csc_matrix(dsb, plane_state); |
| 4295 | + if (plane_state->hw.degamma_lut || plane_state->hw.gamma_lut) |
| 4296 | + intel_color_load_plane_luts(dsb, plane_state); |
| 4297 | + if (plane_state->hw.lut_3d) |
| 4298 | + intel_color_load_3dlut(dsb, plane_state); |
| 4299 | +} |
| 4300 | + |
3966 | 4301 | void intel_color_crtc_init(struct intel_crtc *crtc) |
3967 | 4302 | { |
3968 | 4303 | struct intel_display *display = to_intel_display(crtc); |
|
0 commit comments