diff options
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/dcn10')
23 files changed, 13475 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/Makefile b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile new file mode 100644 index 000000000000..5469bdfe19f3 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/Makefile @@ -0,0 +1,33 @@ +# +# Copyright 2017 Advanced Micro Devices, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# +# Makefile for DCN. + +DCN10 = dcn10_resource.o dcn10_ipp.o dcn10_hw_sequencer.o \ + dcn10_dpp.o dcn10_opp.o dcn10_optc.o \ + dcn10_hubp.o dcn10_mpc.o \ + dcn10_dpp_dscl.o dcn10_dpp_cm.o dcn10_cm_common.o \ + dcn10_hubbub.o + +AMD_DAL_DCN10 = $(addprefix $(AMDDALPATH)/dc/dcn10/,$(DCN10)) + +AMD_DISPLAY_FILES += $(AMD_DAL_DCN10) diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c new file mode 100644 index 000000000000..53ba3600ee6a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c @@ -0,0 +1,415 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#include "dc.h" +#include "reg_helper.h" +#include "dcn10_dpp.h" + +#include "dcn10_cm_common.h" +#include "custom_float.h" + +#define REG(reg) reg + +#define CTX \ + ctx + +#undef FN +#define FN(reg_name, field_name) \ + reg->shifts.field_name, reg->masks.field_name + +void cm_helper_program_color_matrices( + struct dc_context *ctx, + const uint16_t *regval, + const struct color_matrices_reg *reg) +{ + uint32_t cur_csc_reg; + unsigned int i = 0; + + for (cur_csc_reg = reg->csc_c11_c12; + cur_csc_reg <= reg->csc_c33_c34; + cur_csc_reg++) { + + const uint16_t *regval0 = &(regval[2 * i]); + const uint16_t *regval1 = &(regval[(2 * i) + 1]); + + REG_SET_2(cur_csc_reg, 0, + csc_c11, *regval0, + csc_c12, *regval1); + + i++; + } + +} + +void cm_helper_program_xfer_func( + struct dc_context *ctx, + const struct pwl_params *params, + const struct xfer_func_reg *reg) +{ + uint32_t reg_region_cur; + unsigned int i = 0; + + REG_SET_2(reg->start_cntl_b, 0, + exp_region_start, params->arr_points[0].custom_float_x, + exp_resion_start_segment, 0); + REG_SET_2(reg->start_cntl_g, 0, + exp_region_start, params->arr_points[0].custom_float_x, + exp_resion_start_segment, 0); + REG_SET_2(reg->start_cntl_r, 0, + exp_region_start, params->arr_points[0].custom_float_x, + exp_resion_start_segment, 0); + + REG_SET(reg->start_slope_cntl_b, 0, + field_region_linear_slope, params->arr_points[0].custom_float_slope); + REG_SET(reg->start_slope_cntl_g, 0, + field_region_linear_slope, params->arr_points[0].custom_float_slope); + REG_SET(reg->start_slope_cntl_r, 0, + field_region_linear_slope, params->arr_points[0].custom_float_slope); + + REG_SET(reg->start_end_cntl1_b, 0, + field_region_end, params->arr_points[1].custom_float_x); + REG_SET_2(reg->start_end_cntl2_b, 0, + field_region_end_slope, params->arr_points[1].custom_float_slope, + field_region_end_base, params->arr_points[1].custom_float_y); + + REG_SET(reg->start_end_cntl1_g, 0, + field_region_end, params->arr_points[1].custom_float_x); + REG_SET_2(reg->start_end_cntl2_g, 0, + field_region_end_slope, params->arr_points[1].custom_float_slope, + field_region_end_base, params->arr_points[1].custom_float_y); + + REG_SET(reg->start_end_cntl1_r, 0, + field_region_end, params->arr_points[1].custom_float_x); + REG_SET_2(reg->start_end_cntl2_r, 0, + field_region_end_slope, params->arr_points[1].custom_float_slope, + field_region_end_base, params->arr_points[1].custom_float_y); + + for (reg_region_cur = reg->region_start; + reg_region_cur <= reg->region_end; + reg_region_cur++) { + + const struct gamma_curve *curve0 = &(params->arr_curve_points[2 * i]); + const struct gamma_curve *curve1 = &(params->arr_curve_points[(2 * i) + 1]); + + REG_SET_4(reg_region_cur, 0, + exp_region0_lut_offset, curve0->offset, + exp_region0_num_segments, curve0->segments_num, + exp_region1_lut_offset, curve1->offset, + exp_region1_num_segments, curve1->segments_num); + + i++; + } + +} + + + +bool cm_helper_convert_to_custom_float( + struct pwl_result_data *rgb_resulted, + struct curve_points *arr_points, + uint32_t hw_points_num, + bool fixpoint) +{ + struct custom_float_format fmt; + + struct pwl_result_data *rgb = rgb_resulted; + + uint32_t i = 0; + + fmt.exponenta_bits = 6; + fmt.mantissa_bits = 12; + fmt.sign = false; + + if (!convert_to_custom_float_format(arr_points[0].x, &fmt, + &arr_points[0].custom_float_x)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(arr_points[0].offset, &fmt, + &arr_points[0].custom_float_offset)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(arr_points[0].slope, &fmt, + &arr_points[0].custom_float_slope)) { + BREAK_TO_DEBUGGER(); + return false; + } + + fmt.mantissa_bits = 10; + fmt.sign = false; + + if (!convert_to_custom_float_format(arr_points[1].x, &fmt, + &arr_points[1].custom_float_x)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (fixpoint == true) + arr_points[1].custom_float_y = dal_fixed31_32_clamp_u0d14(arr_points[1].y); + else if (!convert_to_custom_float_format(arr_points[1].y, &fmt, + &arr_points[1].custom_float_y)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(arr_points[1].slope, &fmt, + &arr_points[1].custom_float_slope)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (hw_points_num == 0 || rgb_resulted == NULL || fixpoint == true) + return true; + + fmt.mantissa_bits = 12; + fmt.sign = true; + + while (i != hw_points_num) { + if (!convert_to_custom_float_format(rgb->red, &fmt, + &rgb->red_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->green, &fmt, + &rgb->green_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->blue, &fmt, + &rgb->blue_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->delta_red, &fmt, + &rgb->delta_red_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->delta_green, &fmt, + &rgb->delta_green_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + if (!convert_to_custom_float_format(rgb->delta_blue, &fmt, + &rgb->delta_blue_reg)) { + BREAK_TO_DEBUGGER(); + return false; + } + + ++rgb; + ++i; + } + + return true; +} + + +#define MAX_REGIONS_NUMBER 34 +#define MAX_LOW_POINT 25 +#define NUMBER_SEGMENTS 32 + +bool cm_helper_translate_curve_to_hw_format( + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params, bool fixpoint) +{ + struct curve_points *arr_points; + struct pwl_result_data *rgb_resulted; + struct pwl_result_data *rgb; + struct pwl_result_data *rgb_plus_1; + struct fixed31_32 y_r; + struct fixed31_32 y_g; + struct fixed31_32 y_b; + struct fixed31_32 y1_min; + struct fixed31_32 y3_max; + + int32_t segment_start, segment_end; + int32_t i; + uint32_t j, k, seg_distr[MAX_REGIONS_NUMBER], increment, start_index, hw_points; + + if (output_tf == NULL || lut_params == NULL || output_tf->type == TF_TYPE_BYPASS) + return false; + + PERF_TRACE(); + + arr_points = lut_params->arr_points; + rgb_resulted = lut_params->rgb_resulted; + hw_points = 0; + + memset(lut_params, 0, sizeof(struct pwl_params)); + memset(seg_distr, 0, sizeof(seg_distr)); + + if (output_tf->tf == TRANSFER_FUNCTION_PQ) { + /* 32 segments + * segments are from 2^-25 to 2^7 + */ + for (i = 0; i < 32 ; i++) + seg_distr[i] = 3; + + segment_start = -25; + segment_end = 7; + } else { + /* 10 segments + * segment is from 2^-10 to 2^0 + * There are less than 256 points, for optimization + */ + seg_distr[0] = 3; + seg_distr[1] = 4; + seg_distr[2] = 4; + seg_distr[3] = 4; + seg_distr[4] = 4; + seg_distr[5] = 4; + seg_distr[6] = 4; + seg_distr[7] = 4; + seg_distr[8] = 5; + seg_distr[9] = 5; + + segment_start = -10; + segment_end = 0; + } + + for (i = segment_end - segment_start; i < MAX_REGIONS_NUMBER ; i++) + seg_distr[i] = -1; + + for (k = 0; k < MAX_REGIONS_NUMBER; k++) { + if (seg_distr[k] != -1) + hw_points += (1 << seg_distr[k]); + } + + j = 0; + for (k = 0; k < (segment_end - segment_start); k++) { + increment = NUMBER_SEGMENTS / (1 << seg_distr[k]); + start_index = (segment_start + k + MAX_LOW_POINT) * NUMBER_SEGMENTS; + for (i = start_index; i < start_index + NUMBER_SEGMENTS; i += increment) { + if (j == hw_points - 1) + break; + rgb_resulted[j].red = output_tf->tf_pts.red[i]; + rgb_resulted[j].green = output_tf->tf_pts.green[i]; + rgb_resulted[j].blue = output_tf->tf_pts.blue[i]; + j++; + } + } + + /* last point */ + start_index = (segment_end + MAX_LOW_POINT) * NUMBER_SEGMENTS; + rgb_resulted[hw_points - 1].red = output_tf->tf_pts.red[start_index]; + rgb_resulted[hw_points - 1].green = output_tf->tf_pts.green[start_index]; + rgb_resulted[hw_points - 1].blue = output_tf->tf_pts.blue[start_index]; + + arr_points[0].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(segment_start)); + arr_points[1].x = dal_fixed31_32_pow(dal_fixed31_32_from_int(2), + dal_fixed31_32_from_int(segment_end)); + + y_r = rgb_resulted[0].red; + y_g = rgb_resulted[0].green; + y_b = rgb_resulted[0].blue; + + y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b)); + + arr_points[0].y = y1_min; + arr_points[0].slope = dal_fixed31_32_div(arr_points[0].y, arr_points[0].x); + y_r = rgb_resulted[hw_points - 1].red; + y_g = rgb_resulted[hw_points - 1].green; + y_b = rgb_resulted[hw_points - 1].blue; + + /* see comment above, m_arrPoints[1].y should be the Y value for the + * region end (m_numOfHwPoints), not last HW point(m_numOfHwPoints - 1) + */ + y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b)); + + arr_points[1].y = y3_max; + + arr_points[1].slope = dal_fixed31_32_zero; + + if (output_tf->tf == TRANSFER_FUNCTION_PQ) { + /* for PQ, we want to have a straight line from last HW X point, + * and the slope to be such that we hit 1.0 at 10000 nits. + */ + const struct fixed31_32 end_value = + dal_fixed31_32_from_int(125); + + arr_points[1].slope = dal_fixed31_32_div( + dal_fixed31_32_sub(dal_fixed31_32_one, arr_points[1].y), + dal_fixed31_32_sub(end_value, arr_points[1].x)); + } + + lut_params->hw_points_num = hw_points; + + i = 1; + for (k = 0; k < MAX_REGIONS_NUMBER && i < MAX_REGIONS_NUMBER; k++) { + if (seg_distr[k] != -1) { + lut_params->arr_curve_points[k].segments_num = + seg_distr[k]; + lut_params->arr_curve_points[i].offset = + lut_params->arr_curve_points[k].offset + (1 << seg_distr[k]); + } + i++; + } + + if (seg_distr[k] != -1) + lut_params->arr_curve_points[k].segments_num = seg_distr[k]; + + rgb = rgb_resulted; + rgb_plus_1 = rgb_resulted + 1; + + i = 1; + while (i != hw_points + 1) { + if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red)) + rgb_plus_1->red = rgb->red; + if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green)) + rgb_plus_1->green = rgb->green; + if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue)) + rgb_plus_1->blue = rgb->blue; + + rgb->delta_red = dal_fixed31_32_sub(rgb_plus_1->red, rgb->red); + rgb->delta_green = dal_fixed31_32_sub(rgb_plus_1->green, rgb->green); + rgb->delta_blue = dal_fixed31_32_sub(rgb_plus_1->blue, rgb->blue); + + if (fixpoint == true) { + rgb->delta_red_reg = dal_fixed31_32_clamp_u0d10(rgb->delta_red); + rgb->delta_green_reg = dal_fixed31_32_clamp_u0d10(rgb->delta_green); + rgb->delta_blue_reg = dal_fixed31_32_clamp_u0d10(rgb->delta_blue); + rgb->red_reg = dal_fixed31_32_clamp_u0d14(rgb->red); + rgb->green_reg = dal_fixed31_32_clamp_u0d14(rgb->green); + rgb->blue_reg = dal_fixed31_32_clamp_u0d14(rgb->blue); + } + + ++rgb_plus_1; + ++rgb; + ++i; + } + cm_helper_convert_to_custom_float(rgb_resulted, + lut_params->arr_points, + hw_points, fixpoint); + + return true; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h new file mode 100644 index 000000000000..64e476b83bcb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h @@ -0,0 +1,109 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DAL_DCN10_CM_COMMON_H__ +#define __DAL_DCN10_CM_COMMON_H__ + +#define TF_HELPER_REG_FIELD_LIST(type) \ + type exp_region0_lut_offset; \ + type exp_region0_num_segments; \ + type exp_region1_lut_offset; \ + type exp_region1_num_segments;\ + type field_region_end;\ + type field_region_end_slope;\ + type field_region_end_base;\ + type exp_region_start;\ + type exp_resion_start_segment;\ + type field_region_linear_slope + +#define TF_CM_REG_FIELD_LIST(type) \ + type csc_c11; \ + type csc_c12 + +struct xfer_func_shift { + TF_HELPER_REG_FIELD_LIST(uint8_t); +}; + +struct xfer_func_mask { + TF_HELPER_REG_FIELD_LIST(uint32_t); +}; + +struct xfer_func_reg { + struct xfer_func_shift shifts; + struct xfer_func_mask masks; + + uint32_t start_cntl_b; + uint32_t start_cntl_g; + uint32_t start_cntl_r; + uint32_t start_slope_cntl_b; + uint32_t start_slope_cntl_g; + uint32_t start_slope_cntl_r; + uint32_t start_end_cntl1_b; + uint32_t start_end_cntl2_b; + uint32_t start_end_cntl1_g; + uint32_t start_end_cntl2_g; + uint32_t start_end_cntl1_r; + uint32_t start_end_cntl2_r; + uint32_t region_start; + uint32_t region_end; +}; + +struct cm_color_matrix_shift { + TF_CM_REG_FIELD_LIST(uint8_t); +}; + +struct cm_color_matrix_mask { + TF_CM_REG_FIELD_LIST(uint32_t); +}; + +struct color_matrices_reg{ + struct cm_color_matrix_shift shifts; + struct cm_color_matrix_mask masks; + + uint32_t csc_c11_c12; + uint32_t csc_c33_c34; +}; + +void cm_helper_program_color_matrices( + struct dc_context *ctx, + const uint16_t *regval, + const struct color_matrices_reg *reg); + +void cm_helper_program_xfer_func( + struct dc_context *ctx, + const struct pwl_params *params, + const struct xfer_func_reg *reg); + +bool cm_helper_convert_to_custom_float( + struct pwl_result_data *rgb_resulted, + struct curve_points *arr_points, + uint32_t hw_points_num, + bool fixpoint); + +bool cm_helper_translate_curve_to_hw_format( + const struct dc_transfer_func *output_tf, + struct pwl_params *lut_params, bool fixpoint); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c new file mode 100644 index 000000000000..f2a08b156cf0 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c @@ -0,0 +1,484 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" + +#include "core_types.h" + +#include "reg_helper.h" +#include "dcn10_dpp.h" +#include "basics/conversion.h" + +#define NUM_PHASES 64 +#define HORZ_MAX_TAPS 8 +#define VERT_MAX_TAPS 8 + +#define BLACK_OFFSET_RGB_Y 0x0 +#define BLACK_OFFSET_CBCR 0x8000 + +#define REG(reg)\ + dpp->tf_regs->reg + +#define CTX \ + dpp->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + dpp->tf_shift->field_name, dpp->tf_mask->field_name + +enum pixel_format_description { + PIXEL_FORMAT_FIXED = 0, + PIXEL_FORMAT_FIXED16, + PIXEL_FORMAT_FLOAT + +}; + +enum dcn10_coef_filter_type_sel { + SCL_COEF_LUMA_VERT_FILTER = 0, + SCL_COEF_LUMA_HORZ_FILTER = 1, + SCL_COEF_CHROMA_VERT_FILTER = 2, + SCL_COEF_CHROMA_HORZ_FILTER = 3, + SCL_COEF_ALPHA_VERT_FILTER = 4, + SCL_COEF_ALPHA_HORZ_FILTER = 5 +}; + +enum dscl_autocal_mode { + AUTOCAL_MODE_OFF = 0, + + /* Autocal calculate the scaling ratio and initial phase and the + * DSCL_MODE_SEL must be set to 1 + */ + AUTOCAL_MODE_AUTOSCALE = 1, + /* Autocal perform auto centering without replication and the + * DSCL_MODE_SEL must be set to 0 + */ + AUTOCAL_MODE_AUTOCENTER = 2, + /* Autocal perform auto centering and auto replication and the + * DSCL_MODE_SEL must be set to 0 + */ + AUTOCAL_MODE_AUTOREPLICATE = 3 +}; + +enum dscl_mode_sel { + DSCL_MODE_SCALING_444_BYPASS = 0, + DSCL_MODE_SCALING_444_RGB_ENABLE = 1, + DSCL_MODE_SCALING_444_YCBCR_ENABLE = 2, + DSCL_MODE_SCALING_420_YCBCR_ENABLE = 3, + DSCL_MODE_SCALING_420_LUMA_BYPASS = 4, + DSCL_MODE_SCALING_420_CHROMA_BYPASS = 5, + DSCL_MODE_DSCL_BYPASS = 6 +}; + +enum gamut_remap_select { + GAMUT_REMAP_BYPASS = 0, + GAMUT_REMAP_COEFF, + GAMUT_REMAP_COMA_COEFF, + GAMUT_REMAP_COMB_COEFF +}; + +/* Program gamut remap in bypass mode */ +void dpp_set_gamut_remap_bypass(struct dcn10_dpp *dpp) +{ + REG_SET(CM_GAMUT_REMAP_CONTROL, 0, + CM_GAMUT_REMAP_MODE, 0); + /* Gamut remap in bypass */ +} + +#define IDENTITY_RATIO(ratio) (dal_fixed31_32_u2d19(ratio) == (1 << 19)) + + +bool dpp_get_optimal_number_of_taps( + struct dpp *dpp, + struct scaler_data *scl_data, + const struct scaling_taps *in_taps) +{ + uint32_t pixel_width; + + if (scl_data->viewport.width > scl_data->recout.width) + pixel_width = scl_data->recout.width; + else + pixel_width = scl_data->viewport.width; + + /* TODO: add lb check */ + + /* No support for programming ratio of 4, drop to 3.99999.. */ + if (scl_data->ratios.horz.value == (4ll << 32)) + scl_data->ratios.horz.value--; + if (scl_data->ratios.vert.value == (4ll << 32)) + scl_data->ratios.vert.value--; + if (scl_data->ratios.horz_c.value == (4ll << 32)) + scl_data->ratios.horz_c.value--; + if (scl_data->ratios.vert_c.value == (4ll << 32)) + scl_data->ratios.vert_c.value--; + + /* Set default taps if none are provided */ + if (in_taps->h_taps == 0) + scl_data->taps.h_taps = 4; + else + scl_data->taps.h_taps = in_taps->h_taps; + if (in_taps->v_taps == 0) + scl_data->taps.v_taps = 4; + else + scl_data->taps.v_taps = in_taps->v_taps; + if (in_taps->v_taps_c == 0) + scl_data->taps.v_taps_c = 2; + else + scl_data->taps.v_taps_c = in_taps->v_taps_c; + if (in_taps->h_taps_c == 0) + scl_data->taps.h_taps_c = 2; + /* Only 1 and even h_taps_c are supported by hw */ + else if ((in_taps->h_taps_c % 2) != 0 && in_taps->h_taps_c != 1) + scl_data->taps.h_taps_c = in_taps->h_taps_c - 1; + else + scl_data->taps.h_taps_c = in_taps->h_taps_c; + + if (!dpp->ctx->dc->debug.always_scale) { + if (IDENTITY_RATIO(scl_data->ratios.horz)) + scl_data->taps.h_taps = 1; + if (IDENTITY_RATIO(scl_data->ratios.vert)) + scl_data->taps.v_taps = 1; + if (IDENTITY_RATIO(scl_data->ratios.horz_c)) + scl_data->taps.h_taps_c = 1; + if (IDENTITY_RATIO(scl_data->ratios.vert_c)) + scl_data->taps.v_taps_c = 1; + } + + return true; +} + +void dpp_reset(struct dpp *dpp_base) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + dpp->filter_h_c = NULL; + dpp->filter_v_c = NULL; + dpp->filter_h = NULL; + dpp->filter_v = NULL; + + memset(&dpp->scl_data, 0, sizeof(dpp->scl_data)); + memset(&dpp->pwl_data, 0, sizeof(dpp->pwl_data)); +} + + + +static void dpp1_cm_set_regamma_pwl( + struct dpp *dpp_base, const struct pwl_params *params, enum opp_regamma mode) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + uint32_t re_mode = 0; + + switch (mode) { + case OPP_REGAMMA_BYPASS: + re_mode = 0; + break; + case OPP_REGAMMA_SRGB: + re_mode = 1; + break; + case OPP_REGAMMA_3_6: + re_mode = 2; + break; + case OPP_REGAMMA_USER: + re_mode = dpp->is_write_to_ram_a_safe ? 4 : 3; + if (memcmp(&dpp->pwl_data, params, sizeof(*params)) == 0) + break; + + dpp1_cm_power_on_regamma_lut(dpp_base, true); + dpp1_cm_configure_regamma_lut(dpp_base, dpp->is_write_to_ram_a_safe); + + if (dpp->is_write_to_ram_a_safe) + dpp1_cm_program_regamma_luta_settings(dpp_base, params); + else + dpp1_cm_program_regamma_lutb_settings(dpp_base, params); + + dpp1_cm_program_regamma_lut(dpp_base, params->rgb_resulted, + params->hw_points_num); + dpp->pwl_data = *params; + + re_mode = dpp->is_write_to_ram_a_safe ? 3 : 4; + dpp->is_write_to_ram_a_safe = !dpp->is_write_to_ram_a_safe; + break; + default: + break; + } + REG_SET(CM_RGAM_CONTROL, 0, CM_RGAM_LUT_MODE, re_mode); +} + +static void dpp1_setup_format_flags(enum surface_pixel_format input_format,\ + enum pixel_format_description *fmt) +{ + + if (input_format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F || + input_format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) + *fmt = PIXEL_FORMAT_FLOAT; + else if (input_format == SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616) + *fmt = PIXEL_FORMAT_FIXED16; + else + *fmt = PIXEL_FORMAT_FIXED; +} + +static void dpp1_set_degamma_format_float( + struct dpp *dpp_base, + bool is_float) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + if (is_float) { + REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, 3); + REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, 1); + } else { + REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, 2); + REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, 0); + } +} + +void dpp1_cnv_setup ( + struct dpp *dpp_base, + enum surface_pixel_format format, + enum expansion_mode mode, + struct csc_transform input_csc_color_matrix, + enum dc_color_space input_color_space) +{ + uint32_t pixel_format; + uint32_t alpha_en; + enum pixel_format_description fmt ; + enum dc_color_space color_space; + enum dcn10_input_csc_select select; + bool is_float; + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + bool force_disable_cursor = false; + struct out_csc_color_matrix tbl_entry; + int i = 0; + + dpp1_setup_format_flags(format, &fmt); + alpha_en = 1; + pixel_format = 0; + color_space = COLOR_SPACE_SRGB; + select = INPUT_CSC_SELECT_BYPASS; + is_float = false; + + switch (fmt) { + case PIXEL_FORMAT_FIXED: + case PIXEL_FORMAT_FIXED16: + /*when output is float then FORMAT_CONTROL__OUTPUT_FP=1*/ + REG_SET_3(FORMAT_CONTROL, 0, + CNVC_BYPASS, 0, + FORMAT_EXPANSION_MODE, mode, + OUTPUT_FP, 0); + break; + case PIXEL_FORMAT_FLOAT: + REG_SET_3(FORMAT_CONTROL, 0, + CNVC_BYPASS, 0, + FORMAT_EXPANSION_MODE, mode, + OUTPUT_FP, 1); + is_float = true; + break; + default: + + break; + } + + dpp1_set_degamma_format_float(dpp_base, is_float); + + switch (format) { + case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: + pixel_format = 1; + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + pixel_format = 3; + alpha_en = 0; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + pixel_format = 8; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: + pixel_format = 10; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: + force_disable_cursor = false; + pixel_format = 65; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: + force_disable_cursor = true; + pixel_format = 64; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: + force_disable_cursor = true; + pixel_format = 67; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: + force_disable_cursor = true; + pixel_format = 66; + color_space = COLOR_SPACE_YCBCR709; + select = INPUT_CSC_SELECT_ICSC; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + pixel_format = 22; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: + pixel_format = 24; + break; + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: + pixel_format = 25; + break; + default: + break; + } + REG_SET(CNVC_SURFACE_PIXEL_FORMAT, 0, + CNVC_SURFACE_PIXEL_FORMAT, pixel_format); + REG_UPDATE(FORMAT_CONTROL, FORMAT_CONTROL__ALPHA_EN, alpha_en); + + // if input adjustments exist, program icsc with those values + + if (input_csc_color_matrix.enable_adjustment + == true) { + for (i = 0; i < 12; i++) + tbl_entry.regval[i] = input_csc_color_matrix.matrix[i]; + + tbl_entry.color_space = input_color_space; + + if (color_space >= COLOR_SPACE_YCBCR601) + select = INPUT_CSC_SELECT_ICSC; + else + select = INPUT_CSC_SELECT_BYPASS; + + dpp1_program_input_csc(dpp_base, color_space, select, &tbl_entry); + } else + dpp1_program_input_csc(dpp_base, color_space, select, NULL); + + if (force_disable_cursor) { + REG_UPDATE(CURSOR_CONTROL, + CURSOR_ENABLE, 0); + REG_UPDATE(CURSOR0_CONTROL, + CUR0_ENABLE, 0); + } +} + +void dpp1_set_cursor_attributes( + struct dpp *dpp_base, + enum dc_cursor_color_format color_format) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_UPDATE_2(CURSOR0_CONTROL, + CUR0_MODE, color_format, + CUR0_EXPANSION_MODE, 0); + + if (color_format == CURSOR_MODE_MONO) { + /* todo: clarify what to program these to */ + REG_UPDATE(CURSOR0_COLOR0, + CUR0_COLOR0, 0x00000000); + REG_UPDATE(CURSOR0_COLOR1, + CUR0_COLOR1, 0xFFFFFFFF); + } +} + + +void dpp1_set_cursor_position( + struct dpp *dpp_base, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param, + uint32_t width) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + int src_x_offset = pos->x - pos->x_hotspot - param->viewport_x_start; + uint32_t cur_en = pos->enable ? 1 : 0; + + if (src_x_offset >= (int)param->viewport_width) + cur_en = 0; /* not visible beyond right edge*/ + + if (src_x_offset + (int)width < 0) + cur_en = 0; /* not visible beyond left edge*/ + + REG_UPDATE(CURSOR0_CONTROL, + CUR0_ENABLE, cur_en); + +} + +static const struct dpp_funcs dcn10_dpp_funcs = { + .dpp_reset = dpp_reset, + .dpp_set_scaler = dpp1_dscl_set_scaler_manual_scale, + .dpp_get_optimal_number_of_taps = dpp_get_optimal_number_of_taps, + .dpp_set_gamut_remap = dpp1_cm_set_gamut_remap, + .dpp_set_csc_adjustment = dpp1_cm_set_output_csc_adjustment, + .dpp_set_csc_default = dpp1_cm_set_output_csc_default, + .dpp_power_on_regamma_lut = dpp1_cm_power_on_regamma_lut, + .dpp_program_regamma_lut = dpp1_cm_program_regamma_lut, + .dpp_configure_regamma_lut = dpp1_cm_configure_regamma_lut, + .dpp_program_regamma_lutb_settings = dpp1_cm_program_regamma_lutb_settings, + .dpp_program_regamma_luta_settings = dpp1_cm_program_regamma_luta_settings, + .dpp_program_regamma_pwl = dpp1_cm_set_regamma_pwl, + .dpp_program_bias_and_scale = dpp1_program_bias_and_scale, + .dpp_set_degamma = dpp1_set_degamma, + .dpp_program_input_lut = dpp1_program_input_lut, + .dpp_program_degamma_pwl = dpp1_set_degamma_pwl, + .dpp_setup = dpp1_cnv_setup, + .dpp_full_bypass = dpp1_full_bypass, + .set_cursor_attributes = dpp1_set_cursor_attributes, + .set_cursor_position = dpp1_set_cursor_position, +}; + +static struct dpp_caps dcn10_dpp_cap = { + .dscl_data_proc_format = DSCL_DATA_PRCESSING_FIXED_FORMAT, + .dscl_calc_lb_num_partitions = dpp1_dscl_calc_lb_num_partitions, +}; + +/*****************************************/ +/* Constructor, Destructor */ +/*****************************************/ + +void dpp1_construct( + struct dcn10_dpp *dpp, + struct dc_context *ctx, + uint32_t inst, + const struct dcn_dpp_registers *tf_regs, + const struct dcn_dpp_shift *tf_shift, + const struct dcn_dpp_mask *tf_mask) +{ + dpp->base.ctx = ctx; + + dpp->base.inst = inst; + dpp->base.funcs = &dcn10_dpp_funcs; + dpp->base.caps = &dcn10_dpp_cap; + + dpp->tf_regs = tf_regs; + dpp->tf_shift = tf_shift; + dpp->tf_mask = tf_mask; + + dpp->lb_pixel_depth_supported = + LB_PIXEL_DEPTH_18BPP | + LB_PIXEL_DEPTH_24BPP | + LB_PIXEL_DEPTH_30BPP; + + dpp->lb_bits_per_entry = LB_BITS_PER_ENTRY; + dpp->lb_memory_size = LB_TOTAL_NUMBER_OF_ENTRIES; /*0x1404*/ +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h new file mode 100644 index 000000000000..f56ee4d08d89 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h @@ -0,0 +1,1406 @@ +/* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DAL_DPP_DCN10_H__ +#define __DAL_DPP_DCN10_H__ + +#include "dpp.h" + +#define TO_DCN10_DPP(dpp)\ + container_of(dpp, struct dcn10_dpp, base) + +/* TODO: Use correct number of taps. Using polaris values for now */ +#define LB_TOTAL_NUMBER_OF_ENTRIES 5124 +#define LB_BITS_PER_ENTRY 144 + +#define TF_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +//Used to resolve corner case +#define TF2_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## _ ## field_name ## post_fix + +#define TF_REG_LIST_DCN(id) \ + SRI(CM_GAMUT_REMAP_CONTROL, CM, id),\ + SRI(CM_GAMUT_REMAP_C11_C12, CM, id),\ + SRI(CM_GAMUT_REMAP_C33_C34, CM, id),\ + SRI(DSCL_EXT_OVERSCAN_LEFT_RIGHT, DSCL, id), \ + SRI(DSCL_EXT_OVERSCAN_TOP_BOTTOM, DSCL, id), \ + SRI(OTG_H_BLANK, DSCL, id), \ + SRI(OTG_V_BLANK, DSCL, id), \ + SRI(SCL_MODE, DSCL, id), \ + SRI(LB_DATA_FORMAT, DSCL, id), \ + SRI(LB_MEMORY_CTRL, DSCL, id), \ + SRI(DSCL_AUTOCAL, DSCL, id), \ + SRI(SCL_BLACK_OFFSET, DSCL, id), \ + SRI(SCL_TAP_CONTROL, DSCL, id), \ + SRI(SCL_COEF_RAM_TAP_SELECT, DSCL, id), \ + SRI(SCL_COEF_RAM_TAP_DATA, DSCL, id), \ + SRI(DSCL_2TAP_CONTROL, DSCL, id), \ + SRI(MPC_SIZE, DSCL, id), \ + SRI(SCL_HORZ_FILTER_SCALE_RATIO, DSCL, id), \ + SRI(SCL_VERT_FILTER_SCALE_RATIO, DSCL, id), \ + SRI(SCL_HORZ_FILTER_SCALE_RATIO_C, DSCL, id), \ + SRI(SCL_VERT_FILTER_SCALE_RATIO_C, DSCL, id), \ + SRI(SCL_HORZ_FILTER_INIT, DSCL, id), \ + SRI(SCL_HORZ_FILTER_INIT_C, DSCL, id), \ + SRI(SCL_VERT_FILTER_INIT, DSCL, id), \ + SRI(SCL_VERT_FILTER_INIT_BOT, DSCL, id), \ + SRI(SCL_VERT_FILTER_INIT_C, DSCL, id), \ + SRI(SCL_VERT_FILTER_INIT_BOT_C, DSCL, id), \ + SRI(RECOUT_START, DSCL, id), \ + SRI(RECOUT_SIZE, DSCL, id), \ + SRI(CM_ICSC_CONTROL, CM, id), \ + SRI(CM_ICSC_C11_C12, CM, id), \ + SRI(CM_ICSC_C33_C34, CM, id), \ + SRI(CM_DGAM_RAMB_START_CNTL_B, CM, id), \ + SRI(CM_DGAM_RAMB_START_CNTL_G, CM, id), \ + SRI(CM_DGAM_RAMB_START_CNTL_R, CM, id), \ + SRI(CM_DGAM_RAMB_SLOPE_CNTL_B, CM, id), \ + SRI(CM_DGAM_RAMB_SLOPE_CNTL_G, CM, id), \ + SRI(CM_DGAM_RAMB_SLOPE_CNTL_R, CM, id), \ + SRI(CM_DGAM_RAMB_END_CNTL1_B, CM, id), \ + SRI(CM_DGAM_RAMB_END_CNTL2_B, CM, id), \ + SRI(CM_DGAM_RAMB_END_CNTL1_G, CM, id), \ + SRI(CM_DGAM_RAMB_END_CNTL2_G, CM, id), \ + SRI(CM_DGAM_RAMB_END_CNTL1_R, CM, id), \ + SRI(CM_DGAM_RAMB_END_CNTL2_R, CM, id), \ + SRI(CM_DGAM_RAMB_REGION_0_1, CM, id), \ + SRI(CM_DGAM_RAMB_REGION_14_15, CM, id), \ + SRI(CM_DGAM_RAMA_START_CNTL_B, CM, id), \ + SRI(CM_DGAM_RAMA_START_CNTL_G, CM, id), \ + SRI(CM_DGAM_RAMA_START_CNTL_R, CM, id), \ + SRI(CM_DGAM_RAMA_SLOPE_CNTL_B, CM, id), \ + SRI(CM_DGAM_RAMA_SLOPE_CNTL_G, CM, id), \ + SRI(CM_DGAM_RAMA_SLOPE_CNTL_R, CM, id), \ + SRI(CM_DGAM_RAMA_END_CNTL1_B, CM, id), \ + SRI(CM_DGAM_RAMA_END_CNTL2_B, CM, id), \ + SRI(CM_DGAM_RAMA_END_CNTL1_G, CM, id), \ + SRI(CM_DGAM_RAMA_END_CNTL2_G, CM, id), \ + SRI(CM_DGAM_RAMA_END_CNTL1_R, CM, id), \ + SRI(CM_DGAM_RAMA_END_CNTL2_R, CM, id), \ + SRI(CM_DGAM_RAMA_REGION_0_1, CM, id), \ + SRI(CM_DGAM_RAMA_REGION_14_15, CM, id), \ + SRI(CM_MEM_PWR_CTRL, CM, id), \ + SRI(CM_DGAM_LUT_WRITE_EN_MASK, CM, id), \ + SRI(CM_DGAM_LUT_INDEX, CM, id), \ + SRI(CM_DGAM_LUT_DATA, CM, id), \ + SRI(CM_CONTROL, CM, id), \ + SRI(CM_DGAM_CONTROL, CM, id), \ + SRI(FORMAT_CONTROL, CNVC_CFG, id), \ + SRI(CNVC_SURFACE_PIXEL_FORMAT, CNVC_CFG, id), \ + SRI(CURSOR0_CONTROL, CNVC_CUR, id), \ + SRI(CURSOR0_COLOR0, CNVC_CUR, id), \ + SRI(CURSOR0_COLOR1, CNVC_CUR, id) + + + +#define TF_REG_LIST_DCN10(id) \ + TF_REG_LIST_DCN(id), \ + SRI(CM_COMA_C11_C12, CM, id),\ + SRI(CM_COMA_C33_C34, CM, id),\ + SRI(CM_COMB_C11_C12, CM, id),\ + SRI(CM_COMB_C33_C34, CM, id),\ + SRI(CM_OCSC_CONTROL, CM, id), \ + SRI(CM_OCSC_C11_C12, CM, id), \ + SRI(CM_OCSC_C33_C34, CM, id), \ + SRI(CM_BNS_VALUES_R, CM, id), \ + SRI(CM_BNS_VALUES_G, CM, id), \ + SRI(CM_BNS_VALUES_B, CM, id), \ + SRI(CM_MEM_PWR_CTRL, CM, id), \ + SRI(CM_RGAM_LUT_DATA, CM, id), \ + SRI(CM_RGAM_LUT_WRITE_EN_MASK, CM, id),\ + SRI(CM_RGAM_LUT_INDEX, CM, id), \ + SRI(CM_RGAM_RAMB_START_CNTL_B, CM, id), \ + SRI(CM_RGAM_RAMB_START_CNTL_G, CM, id), \ + SRI(CM_RGAM_RAMB_START_CNTL_R, CM, id), \ + SRI(CM_RGAM_RAMB_SLOPE_CNTL_B, CM, id), \ + SRI(CM_RGAM_RAMB_SLOPE_CNTL_G, CM, id), \ + SRI(CM_RGAM_RAMB_SLOPE_CNTL_R, CM, id), \ + SRI(CM_RGAM_RAMB_END_CNTL1_B, CM, id), \ + SRI(CM_RGAM_RAMB_END_CNTL2_B, CM, id), \ + SRI(CM_RGAM_RAMB_END_CNTL1_G, CM, id), \ + SRI(CM_RGAM_RAMB_END_CNTL2_G, CM, id), \ + SRI(CM_RGAM_RAMB_END_CNTL1_R, CM, id), \ + SRI(CM_RGAM_RAMB_END_CNTL2_R, CM, id), \ + SRI(CM_RGAM_RAMB_REGION_0_1, CM, id), \ + SRI(CM_RGAM_RAMB_REGION_32_33, CM, id), \ + SRI(CM_RGAM_RAMA_START_CNTL_B, CM, id), \ + SRI(CM_RGAM_RAMA_START_CNTL_G, CM, id), \ + SRI(CM_RGAM_RAMA_START_CNTL_R, CM, id), \ + SRI(CM_RGAM_RAMA_SLOPE_CNTL_B, CM, id), \ + SRI(CM_RGAM_RAMA_SLOPE_CNTL_G, CM, id), \ + SRI(CM_RGAM_RAMA_SLOPE_CNTL_R, CM, id), \ + SRI(CM_RGAM_RAMA_END_CNTL1_B, CM, id), \ + SRI(CM_RGAM_RAMA_END_CNTL2_B, CM, id), \ + SRI(CM_RGAM_RAMA_END_CNTL1_G, CM, id), \ + SRI(CM_RGAM_RAMA_END_CNTL2_G, CM, id), \ + SRI(CM_RGAM_RAMA_END_CNTL1_R, CM, id), \ + SRI(CM_RGAM_RAMA_END_CNTL2_R, CM, id), \ + SRI(CM_RGAM_RAMA_REGION_0_1, CM, id), \ + SRI(CM_RGAM_RAMA_REGION_32_33, CM, id), \ + SRI(CM_RGAM_CONTROL, CM, id), \ + SRI(CM_IGAM_CONTROL, CM, id), \ + SRI(CM_IGAM_LUT_RW_CONTROL, CM, id), \ + SRI(CM_IGAM_LUT_RW_INDEX, CM, id), \ + SRI(CM_IGAM_LUT_SEQ_COLOR, CM, id), \ + SRI(CURSOR_CONTROL, CURSOR, id), \ + SRI(CM_CMOUT_CONTROL, CM, id) + + +#define TF_REG_LIST_SH_MASK_DCN(mask_sh)\ + TF_SF(CM0_CM_GAMUT_REMAP_CONTROL, CM_GAMUT_REMAP_MODE, mask_sh),\ + TF_SF(CM0_CM_GAMUT_REMAP_C11_C12, CM_GAMUT_REMAP_C11, mask_sh),\ + TF_SF(CM0_CM_GAMUT_REMAP_C11_C12, CM_GAMUT_REMAP_C12, mask_sh),\ + TF_SF(CM0_CM_GAMUT_REMAP_C33_C34, CM_GAMUT_REMAP_C33, mask_sh),\ + TF_SF(CM0_CM_GAMUT_REMAP_C33_C34, CM_GAMUT_REMAP_C34, mask_sh),\ + TF_SF(DSCL0_DSCL_EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT, mask_sh),\ + TF_SF(DSCL0_DSCL_EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT, mask_sh),\ + TF_SF(DSCL0_DSCL_EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM, mask_sh),\ + TF_SF(DSCL0_DSCL_EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP, mask_sh),\ + TF_SF(DSCL0_OTG_H_BLANK, OTG_H_BLANK_START, mask_sh),\ + TF_SF(DSCL0_OTG_H_BLANK, OTG_H_BLANK_END, mask_sh),\ + TF_SF(DSCL0_OTG_V_BLANK, OTG_V_BLANK_START, mask_sh),\ + TF_SF(DSCL0_OTG_V_BLANK, OTG_V_BLANK_END, mask_sh),\ + TF_SF(DSCL0_LB_DATA_FORMAT, INTERLEAVE_EN, mask_sh),\ + TF2_SF(DSCL0, LB_DATA_FORMAT__ALPHA_EN, mask_sh),\ + TF_SF(DSCL0_LB_MEMORY_CTRL, MEMORY_CONFIG, mask_sh),\ + TF_SF(DSCL0_LB_MEMORY_CTRL, LB_MAX_PARTITIONS, mask_sh),\ + TF_SF(DSCL0_DSCL_AUTOCAL, AUTOCAL_MODE, mask_sh),\ + TF_SF(DSCL0_DSCL_AUTOCAL, AUTOCAL_NUM_PIPE, mask_sh),\ + TF_SF(DSCL0_DSCL_AUTOCAL, AUTOCAL_PIPE_ID, mask_sh),\ + TF_SF(DSCL0_SCL_BLACK_OFFSET, SCL_BLACK_OFFSET_RGB_Y, mask_sh),\ + TF_SF(DSCL0_SCL_BLACK_OFFSET, SCL_BLACK_OFFSET_CBCR, mask_sh),\ + TF_SF(DSCL0_SCL_TAP_CONTROL, SCL_V_NUM_TAPS, mask_sh),\ + TF_SF(DSCL0_SCL_TAP_CONTROL, SCL_H_NUM_TAPS, mask_sh),\ + TF_SF(DSCL0_SCL_TAP_CONTROL, SCL_V_NUM_TAPS_C, mask_sh),\ + TF_SF(DSCL0_SCL_TAP_CONTROL, SCL_H_NUM_TAPS_C, mask_sh),\ + TF_SF(DSCL0_SCL_COEF_RAM_TAP_SELECT, SCL_COEF_RAM_TAP_PAIR_IDX, mask_sh),\ + TF_SF(DSCL0_SCL_COEF_RAM_TAP_SELECT, SCL_COEF_RAM_PHASE, mask_sh),\ + TF_SF(DSCL0_SCL_COEF_RAM_TAP_SELECT, SCL_COEF_RAM_FILTER_TYPE, mask_sh),\ + TF_SF(DSCL0_SCL_COEF_RAM_TAP_DATA, SCL_COEF_RAM_EVEN_TAP_COEF, mask_sh),\ + TF_SF(DSCL0_SCL_COEF_RAM_TAP_DATA, SCL_COEF_RAM_EVEN_TAP_COEF_EN, mask_sh),\ + TF_SF(DSCL0_SCL_COEF_RAM_TAP_DATA, SCL_COEF_RAM_ODD_TAP_COEF, mask_sh),\ + TF_SF(DSCL0_SCL_COEF_RAM_TAP_DATA, SCL_COEF_RAM_ODD_TAP_COEF_EN, mask_sh),\ + TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_H_2TAP_HARDCODE_COEF_EN, mask_sh),\ + TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_H_2TAP_SHARP_EN, mask_sh),\ + TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_H_2TAP_SHARP_FACTOR, mask_sh),\ + TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_V_2TAP_HARDCODE_COEF_EN, mask_sh),\ + TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_V_2TAP_SHARP_EN, mask_sh),\ + TF_SF(DSCL0_DSCL_2TAP_CONTROL, SCL_V_2TAP_SHARP_FACTOR, mask_sh),\ + TF_SF(DSCL0_SCL_MODE, SCL_COEF_RAM_SELECT, mask_sh),\ + TF_SF(DSCL0_SCL_MODE, DSCL_MODE, mask_sh),\ + TF_SF(DSCL0_RECOUT_START, RECOUT_START_X, mask_sh),\ + TF_SF(DSCL0_RECOUT_START, RECOUT_START_Y, mask_sh),\ + TF_SF(DSCL0_RECOUT_SIZE, RECOUT_WIDTH, mask_sh),\ + TF_SF(DSCL0_RECOUT_SIZE, RECOUT_HEIGHT, mask_sh),\ + TF_SF(DSCL0_MPC_SIZE, MPC_WIDTH, mask_sh),\ + TF_SF(DSCL0_MPC_SIZE, MPC_HEIGHT, mask_sh),\ + TF_SF(DSCL0_SCL_HORZ_FILTER_SCALE_RATIO, SCL_H_SCALE_RATIO, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_SCALE_RATIO, SCL_V_SCALE_RATIO, mask_sh),\ + TF_SF(DSCL0_SCL_HORZ_FILTER_SCALE_RATIO_C, SCL_H_SCALE_RATIO_C, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_SCALE_RATIO_C, SCL_V_SCALE_RATIO_C, mask_sh),\ + TF_SF(DSCL0_SCL_HORZ_FILTER_INIT, SCL_H_INIT_FRAC, mask_sh),\ + TF_SF(DSCL0_SCL_HORZ_FILTER_INIT, SCL_H_INIT_INT, mask_sh),\ + TF_SF(DSCL0_SCL_HORZ_FILTER_INIT_C, SCL_H_INIT_FRAC_C, mask_sh),\ + TF_SF(DSCL0_SCL_HORZ_FILTER_INIT_C, SCL_H_INIT_INT_C, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_INIT, SCL_V_INIT_FRAC, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_INIT, SCL_V_INIT_INT, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_INIT_BOT, SCL_V_INIT_FRAC_BOT, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_INIT_BOT, SCL_V_INIT_INT_BOT, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_INIT_C, SCL_V_INIT_FRAC_C, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_INIT_C, SCL_V_INIT_INT_C, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_INIT_BOT_C, SCL_V_INIT_FRAC_BOT_C, mask_sh),\ + TF_SF(DSCL0_SCL_VERT_FILTER_INIT_BOT_C, SCL_V_INIT_INT_BOT_C, mask_sh),\ + TF_SF(DSCL0_SCL_MODE, SCL_CHROMA_COEF_MODE, mask_sh),\ + TF_SF(DSCL0_SCL_MODE, SCL_COEF_RAM_SELECT_CURRENT, mask_sh), \ + TF_SF(CM0_CM_ICSC_CONTROL, CM_ICSC_MODE, mask_sh), \ + TF_SF(CM0_CM_ICSC_C11_C12, CM_ICSC_C11, mask_sh), \ + TF_SF(CM0_CM_ICSC_C11_C12, CM_ICSC_C12, mask_sh), \ + TF_SF(CM0_CM_ICSC_C33_C34, CM_ICSC_C33, mask_sh), \ + TF_SF(CM0_CM_ICSC_C33_C34, CM_ICSC_C34, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_START_CNTL_B, CM_DGAM_RAMB_EXP_REGION_START_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_START_CNTL_B, CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_START_CNTL_G, CM_DGAM_RAMB_EXP_REGION_START_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_START_CNTL_G, CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_START_CNTL_R, CM_DGAM_RAMB_EXP_REGION_START_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_START_CNTL_R, CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_SLOPE_CNTL_B, CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_SLOPE_CNTL_G, CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_SLOPE_CNTL_R, CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL1_B, CM_DGAM_RAMB_EXP_REGION_END_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL2_B, CM_DGAM_RAMB_EXP_REGION_END_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL2_B, CM_DGAM_RAMB_EXP_REGION_END_BASE_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL1_G, CM_DGAM_RAMB_EXP_REGION_END_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL2_G, CM_DGAM_RAMB_EXP_REGION_END_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL2_G, CM_DGAM_RAMB_EXP_REGION_END_BASE_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL1_R, CM_DGAM_RAMB_EXP_REGION_END_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL2_R, CM_DGAM_RAMB_EXP_REGION_END_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_END_CNTL2_R, CM_DGAM_RAMB_EXP_REGION_END_BASE_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_REGION_0_1, CM_DGAM_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_REGION_0_1, CM_DGAM_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_REGION_0_1, CM_DGAM_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_REGION_0_1, CM_DGAM_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_REGION_14_15, CM_DGAM_RAMB_EXP_REGION14_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_REGION_14_15, CM_DGAM_RAMB_EXP_REGION14_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_REGION_14_15, CM_DGAM_RAMB_EXP_REGION15_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMB_REGION_14_15, CM_DGAM_RAMB_EXP_REGION15_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_START_CNTL_B, CM_DGAM_RAMA_EXP_REGION_START_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_START_CNTL_B, CM_DGAM_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_START_CNTL_G, CM_DGAM_RAMA_EXP_REGION_START_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_START_CNTL_G, CM_DGAM_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_START_CNTL_R, CM_DGAM_RAMA_EXP_REGION_START_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_START_CNTL_R, CM_DGAM_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_SLOPE_CNTL_B, CM_DGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_SLOPE_CNTL_G, CM_DGAM_RAMA_EXP_REGION_LINEAR_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_SLOPE_CNTL_R, CM_DGAM_RAMA_EXP_REGION_LINEAR_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL1_B, CM_DGAM_RAMA_EXP_REGION_END_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL2_B, CM_DGAM_RAMA_EXP_REGION_END_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL2_B, CM_DGAM_RAMA_EXP_REGION_END_BASE_B, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL1_G, CM_DGAM_RAMA_EXP_REGION_END_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL2_G, CM_DGAM_RAMA_EXP_REGION_END_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL2_G, CM_DGAM_RAMA_EXP_REGION_END_BASE_G, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL1_R, CM_DGAM_RAMA_EXP_REGION_END_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL2_R, CM_DGAM_RAMA_EXP_REGION_END_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_END_CNTL2_R, CM_DGAM_RAMA_EXP_REGION_END_BASE_R, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_REGION_0_1, CM_DGAM_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_REGION_0_1, CM_DGAM_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_REGION_0_1, CM_DGAM_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_REGION_0_1, CM_DGAM_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_REGION_14_15, CM_DGAM_RAMA_EXP_REGION14_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_REGION_14_15, CM_DGAM_RAMA_EXP_REGION14_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_REGION_14_15, CM_DGAM_RAMA_EXP_REGION15_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_DGAM_RAMA_REGION_14_15, CM_DGAM_RAMA_EXP_REGION15_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_MEM_PWR_CTRL, SHARED_MEM_PWR_DIS, mask_sh), \ + TF_SF(CM0_CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_LUT_WRITE_EN_MASK, mask_sh), \ + TF_SF(CM0_CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_LUT_WRITE_SEL, mask_sh), \ + TF_SF(CM0_CM_DGAM_LUT_INDEX, CM_DGAM_LUT_INDEX, mask_sh), \ + TF_SF(CM0_CM_DGAM_LUT_DATA, CM_DGAM_LUT_DATA, mask_sh), \ + TF_SF(CM0_CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, mask_sh), \ + TF_SF(CNVC_CFG0_FORMAT_CONTROL, CNVC_BYPASS, mask_sh), \ + TF2_SF(CNVC_CFG0, FORMAT_CONTROL__ALPHA_EN, mask_sh), \ + TF_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_EXPANSION_MODE, mask_sh), \ + TF_SF(CNVC_CFG0_CNVC_SURFACE_PIXEL_FORMAT, CNVC_SURFACE_PIXEL_FORMAT, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_MODE, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_EXPANSION_MODE, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_COLOR0, CUR0_COLOR0, mask_sh), \ + TF_SF(CNVC_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh) + +#define TF_REG_LIST_SH_MASK_DCN10(mask_sh)\ + TF_REG_LIST_SH_MASK_DCN(mask_sh),\ + TF_SF(DSCL0_LB_DATA_FORMAT, PIXEL_DEPTH, mask_sh),\ + TF_SF(DSCL0_LB_DATA_FORMAT, PIXEL_EXPAN_MODE, mask_sh),\ + TF_SF(DSCL0_LB_DATA_FORMAT, PIXEL_REDUCE_MODE, mask_sh),\ + TF_SF(DSCL0_LB_DATA_FORMAT, DYNAMIC_PIXEL_DEPTH, mask_sh),\ + TF_SF(DSCL0_LB_DATA_FORMAT, DITHER_EN, mask_sh),\ + TF_SF(CM0_CM_COMA_C11_C12, CM_COMA_C11, mask_sh),\ + TF_SF(CM0_CM_COMA_C11_C12, CM_COMA_C12, mask_sh),\ + TF_SF(CM0_CM_COMA_C33_C34, CM_COMA_C33, mask_sh),\ + TF_SF(CM0_CM_COMA_C33_C34, CM_COMA_C34, mask_sh),\ + TF_SF(CM0_CM_COMB_C11_C12, CM_COMB_C11, mask_sh),\ + TF_SF(CM0_CM_COMB_C11_C12, CM_COMB_C12, mask_sh),\ + TF_SF(CM0_CM_COMB_C33_C34, CM_COMB_C33, mask_sh),\ + TF_SF(CM0_CM_COMB_C33_C34, CM_COMB_C34, mask_sh),\ + TF_SF(CM0_CM_OCSC_CONTROL, CM_OCSC_MODE, mask_sh), \ + TF_SF(CM0_CM_OCSC_C11_C12, CM_OCSC_C11, mask_sh), \ + TF_SF(CM0_CM_OCSC_C11_C12, CM_OCSC_C12, mask_sh), \ + TF_SF(CM0_CM_OCSC_C33_C34, CM_OCSC_C33, mask_sh), \ + TF_SF(CM0_CM_OCSC_C33_C34, CM_OCSC_C34, mask_sh), \ + TF_SF(CM0_CM_BNS_VALUES_R, CM_BNS_BIAS_R, mask_sh), \ + TF_SF(CM0_CM_BNS_VALUES_G, CM_BNS_BIAS_G, mask_sh), \ + TF_SF(CM0_CM_BNS_VALUES_B, CM_BNS_BIAS_B, mask_sh), \ + TF_SF(CM0_CM_BNS_VALUES_R, CM_BNS_SCALE_R, mask_sh), \ + TF_SF(CM0_CM_BNS_VALUES_G, CM_BNS_SCALE_G, mask_sh), \ + TF_SF(CM0_CM_BNS_VALUES_B, CM_BNS_SCALE_B, mask_sh), \ + TF_SF(CM0_CM_MEM_PWR_CTRL, RGAM_MEM_PWR_FORCE, mask_sh), \ + TF_SF(CM0_CM_RGAM_LUT_DATA, CM_RGAM_LUT_DATA, mask_sh), \ + TF_SF(CM0_CM_RGAM_LUT_WRITE_EN_MASK, CM_RGAM_LUT_WRITE_EN_MASK, mask_sh), \ + TF_SF(CM0_CM_RGAM_LUT_WRITE_EN_MASK, CM_RGAM_LUT_WRITE_SEL, mask_sh), \ + TF_SF(CM0_CM_RGAM_LUT_INDEX, CM_RGAM_LUT_INDEX, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_START_CNTL_B, CM_RGAM_RAMB_EXP_REGION_START_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_START_CNTL_B, CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_START_CNTL_G, CM_RGAM_RAMB_EXP_REGION_START_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_START_CNTL_G, CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_START_CNTL_R, CM_RGAM_RAMB_EXP_REGION_START_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_START_CNTL_R, CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_SLOPE_CNTL_B, CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_SLOPE_CNTL_G, CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_SLOPE_CNTL_R, CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL1_B, CM_RGAM_RAMB_EXP_REGION_END_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL2_B, CM_RGAM_RAMB_EXP_REGION_END_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL2_B, CM_RGAM_RAMB_EXP_REGION_END_BASE_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL1_G, CM_RGAM_RAMB_EXP_REGION_END_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL2_G, CM_RGAM_RAMB_EXP_REGION_END_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL2_G, CM_RGAM_RAMB_EXP_REGION_END_BASE_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL1_R, CM_RGAM_RAMB_EXP_REGION_END_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL2_R, CM_RGAM_RAMB_EXP_REGION_END_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_END_CNTL2_R, CM_RGAM_RAMB_EXP_REGION_END_BASE_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_REGION_0_1, CM_RGAM_RAMB_EXP_REGION0_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_REGION_0_1, CM_RGAM_RAMB_EXP_REGION0_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_REGION_0_1, CM_RGAM_RAMB_EXP_REGION1_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_REGION_0_1, CM_RGAM_RAMB_EXP_REGION1_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_REGION_32_33, CM_RGAM_RAMB_EXP_REGION32_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_REGION_32_33, CM_RGAM_RAMB_EXP_REGION32_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_REGION_32_33, CM_RGAM_RAMB_EXP_REGION33_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMB_REGION_32_33, CM_RGAM_RAMB_EXP_REGION33_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_START_CNTL_B, CM_RGAM_RAMA_EXP_REGION_START_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_START_CNTL_B, CM_RGAM_RAMA_EXP_REGION_START_SEGMENT_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_START_CNTL_G, CM_RGAM_RAMA_EXP_REGION_START_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_START_CNTL_G, CM_RGAM_RAMA_EXP_REGION_START_SEGMENT_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_START_CNTL_R, CM_RGAM_RAMA_EXP_REGION_START_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_START_CNTL_R, CM_RGAM_RAMA_EXP_REGION_START_SEGMENT_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_SLOPE_CNTL_B, CM_RGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_SLOPE_CNTL_G, CM_RGAM_RAMA_EXP_REGION_LINEAR_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_SLOPE_CNTL_R, CM_RGAM_RAMA_EXP_REGION_LINEAR_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL1_B, CM_RGAM_RAMA_EXP_REGION_END_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL2_B, CM_RGAM_RAMA_EXP_REGION_END_SLOPE_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL2_B, CM_RGAM_RAMA_EXP_REGION_END_BASE_B, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL1_G, CM_RGAM_RAMA_EXP_REGION_END_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL2_G, CM_RGAM_RAMA_EXP_REGION_END_SLOPE_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL2_G, CM_RGAM_RAMA_EXP_REGION_END_BASE_G, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL1_R, CM_RGAM_RAMA_EXP_REGION_END_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL2_R, CM_RGAM_RAMA_EXP_REGION_END_SLOPE_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_END_CNTL2_R, CM_RGAM_RAMA_EXP_REGION_END_BASE_R, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_REGION_0_1, CM_RGAM_RAMA_EXP_REGION0_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_REGION_0_1, CM_RGAM_RAMA_EXP_REGION0_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_REGION_0_1, CM_RGAM_RAMA_EXP_REGION1_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_REGION_0_1, CM_RGAM_RAMA_EXP_REGION1_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_REGION_32_33, CM_RGAM_RAMA_EXP_REGION32_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_REGION_32_33, CM_RGAM_RAMA_EXP_REGION32_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_REGION_32_33, CM_RGAM_RAMA_EXP_REGION33_LUT_OFFSET, mask_sh), \ + TF_SF(CM0_CM_RGAM_RAMA_REGION_32_33, CM_RGAM_RAMA_EXP_REGION33_NUM_SEGMENTS, mask_sh), \ + TF_SF(CM0_CM_RGAM_CONTROL, CM_RGAM_LUT_MODE, mask_sh), \ + TF_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, mask_sh), \ + TF_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_LUT_FORMAT_R, mask_sh), \ + TF_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_LUT_FORMAT_G, mask_sh), \ + TF_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_LUT_FORMAT_B, mask_sh), \ + TF_SF(CM0_CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, mask_sh), \ + TF_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_DGAM_CONFIG_STATUS, mask_sh), \ + TF_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_HOST_EN, mask_sh), \ + TF_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_RW_MODE, mask_sh), \ + TF_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_SEL, mask_sh), \ + TF_SF(CM0_CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_WRITE_EN_MASK, mask_sh), \ + TF_SF(CM0_CM_IGAM_LUT_RW_INDEX, CM_IGAM_LUT_RW_INDEX, mask_sh), \ + TF_SF(CM0_CM_CONTROL, CM_BYPASS_EN, mask_sh), \ + TF_SF(CM0_CM_IGAM_LUT_SEQ_COLOR, CM_IGAM_LUT_SEQ_COLOR, mask_sh), \ + TF_SF(CNVC_CFG0_FORMAT_CONTROL, OUTPUT_FP, mask_sh), \ + TF_SF(CM0_CM_CMOUT_CONTROL, CM_CMOUT_ROUND_TRUNC_MODE, mask_sh), \ + TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \ + TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \ + TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \ + TF_SF(CURSOR0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh) + +#define TF_REG_FIELD_LIST(type) \ + type EXT_OVERSCAN_LEFT; \ + type EXT_OVERSCAN_RIGHT; \ + type EXT_OVERSCAN_BOTTOM; \ + type EXT_OVERSCAN_TOP; \ + type OTG_H_BLANK_START; \ + type OTG_H_BLANK_END; \ + type OTG_V_BLANK_START; \ + type OTG_V_BLANK_END; \ + type PIXEL_DEPTH; \ + type PIXEL_EXPAN_MODE; \ + type PIXEL_REDUCE_MODE; \ + type DYNAMIC_PIXEL_DEPTH; \ + type DITHER_EN; \ + type INTERLEAVE_EN; \ + type LB_DATA_FORMAT__ALPHA_EN; \ + type MEMORY_CONFIG; \ + type LB_MAX_PARTITIONS; \ + type AUTOCAL_MODE; \ + type AUTOCAL_NUM_PIPE; \ + type AUTOCAL_PIPE_ID; \ + type SCL_BLACK_OFFSET_RGB_Y; \ + type SCL_BLACK_OFFSET_CBCR; \ + type SCL_V_NUM_TAPS; \ + type SCL_H_NUM_TAPS; \ + type SCL_V_NUM_TAPS_C; \ + type SCL_H_NUM_TAPS_C; \ + type SCL_COEF_RAM_TAP_PAIR_IDX; \ + type SCL_COEF_RAM_PHASE; \ + type SCL_COEF_RAM_FILTER_TYPE; \ + type SCL_COEF_RAM_EVEN_TAP_COEF; \ + type SCL_COEF_RAM_EVEN_TAP_COEF_EN; \ + type SCL_COEF_RAM_ODD_TAP_COEF; \ + type SCL_COEF_RAM_ODD_TAP_COEF_EN; \ + type SCL_H_2TAP_HARDCODE_COEF_EN; \ + type SCL_H_2TAP_SHARP_EN; \ + type SCL_H_2TAP_SHARP_FACTOR; \ + type SCL_V_2TAP_HARDCODE_COEF_EN; \ + type SCL_V_2TAP_SHARP_EN; \ + type SCL_V_2TAP_SHARP_FACTOR; \ + type SCL_COEF_RAM_SELECT; \ + type DSCL_MODE; \ + type RECOUT_START_X; \ + type RECOUT_START_Y; \ + type RECOUT_WIDTH; \ + type RECOUT_HEIGHT; \ + type MPC_WIDTH; \ + type MPC_HEIGHT; \ + type SCL_H_SCALE_RATIO; \ + type SCL_V_SCALE_RATIO; \ + type SCL_H_SCALE_RATIO_C; \ + type SCL_V_SCALE_RATIO_C; \ + type SCL_H_INIT_FRAC; \ + type SCL_H_INIT_INT; \ + type SCL_H_INIT_FRAC_C; \ + type SCL_H_INIT_INT_C; \ + type SCL_V_INIT_FRAC; \ + type SCL_V_INIT_INT; \ + type SCL_V_INIT_FRAC_BOT; \ + type SCL_V_INIT_INT_BOT; \ + type SCL_V_INIT_FRAC_C; \ + type SCL_V_INIT_INT_C; \ + type SCL_V_INIT_FRAC_BOT_C; \ + type SCL_V_INIT_INT_BOT_C; \ + type SCL_CHROMA_COEF_MODE; \ + type SCL_COEF_RAM_SELECT_CURRENT; \ + type CM_GAMUT_REMAP_MODE; \ + type CM_GAMUT_REMAP_C11; \ + type CM_GAMUT_REMAP_C12; \ + type CM_GAMUT_REMAP_C33; \ + type CM_GAMUT_REMAP_C34; \ + type CM_COMA_C11; \ + type CM_COMA_C12; \ + type CM_COMA_C33; \ + type CM_COMA_C34; \ + type CM_COMB_C11; \ + type CM_COMB_C12; \ + type CM_COMB_C33; \ + type CM_COMB_C34; \ + type CM_OCSC_MODE; \ + type CM_OCSC_C11; \ + type CM_OCSC_C12; \ + type CM_OCSC_C33; \ + type CM_OCSC_C34; \ + type RGAM_MEM_PWR_FORCE; \ + type CM_RGAM_LUT_DATA; \ + type CM_RGAM_LUT_WRITE_EN_MASK; \ + type CM_RGAM_LUT_WRITE_SEL; \ + type CM_RGAM_LUT_INDEX; \ + type CM_RGAM_RAMB_EXP_REGION_START_B; \ + type CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_B; \ + type CM_RGAM_RAMB_EXP_REGION_START_G; \ + type CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_G; \ + type CM_RGAM_RAMB_EXP_REGION_START_R; \ + type CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_R; \ + type CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; \ + type CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_G; \ + type CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_R; \ + type CM_RGAM_RAMB_EXP_REGION_END_B; \ + type CM_RGAM_RAMB_EXP_REGION_END_SLOPE_B; \ + type CM_RGAM_RAMB_EXP_REGION_END_BASE_B; \ + type CM_RGAM_RAMB_EXP_REGION_END_G; \ + type CM_RGAM_RAMB_EXP_REGION_END_SLOPE_G; \ + type CM_RGAM_RAMB_EXP_REGION_END_BASE_G; \ + type CM_RGAM_RAMB_EXP_REGION_END_R; \ + type CM_RGAM_RAMB_EXP_REGION_END_SLOPE_R; \ + type CM_RGAM_RAMB_EXP_REGION_END_BASE_R; \ + type CM_RGAM_RAMB_EXP_REGION0_LUT_OFFSET; \ + type CM_RGAM_RAMB_EXP_REGION0_NUM_SEGMENTS; \ + type CM_RGAM_RAMB_EXP_REGION1_LUT_OFFSET; \ + type CM_RGAM_RAMB_EXP_REGION1_NUM_SEGMENTS; \ + type CM_RGAM_RAMB_EXP_REGION32_LUT_OFFSET; \ + type CM_RGAM_RAMB_EXP_REGION32_NUM_SEGMENTS; \ + type CM_RGAM_RAMB_EXP_REGION33_LUT_OFFSET; \ + type CM_RGAM_RAMB_EXP_REGION33_NUM_SEGMENTS; \ + type CM_RGAM_RAMA_EXP_REGION_START_B; \ + type CM_RGAM_RAMA_EXP_REGION_START_SEGMENT_B; \ + type CM_RGAM_RAMA_EXP_REGION_START_G; \ + type CM_RGAM_RAMA_EXP_REGION_START_SEGMENT_G; \ + type CM_RGAM_RAMA_EXP_REGION_START_R; \ + type CM_RGAM_RAMA_EXP_REGION_START_SEGMENT_R; \ + type CM_RGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B; \ + type CM_RGAM_RAMA_EXP_REGION_LINEAR_SLOPE_G; \ + type CM_RGAM_RAMA_EXP_REGION_LINEAR_SLOPE_R; \ + type CM_RGAM_RAMA_EXP_REGION_END_B; \ + type CM_RGAM_RAMA_EXP_REGION_END_SLOPE_B; \ + type CM_RGAM_RAMA_EXP_REGION_END_BASE_B; \ + type CM_RGAM_RAMA_EXP_REGION_END_G; \ + type CM_RGAM_RAMA_EXP_REGION_END_SLOPE_G; \ + type CM_RGAM_RAMA_EXP_REGION_END_BASE_G; \ + type CM_RGAM_RAMA_EXP_REGION_END_R; \ + type CM_RGAM_RAMA_EXP_REGION_END_SLOPE_R; \ + type CM_RGAM_RAMA_EXP_REGION_END_BASE_R; \ + type CM_RGAM_RAMA_EXP_REGION0_LUT_OFFSET; \ + type CM_RGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; \ + type CM_RGAM_RAMA_EXP_REGION1_LUT_OFFSET; \ + type CM_RGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; \ + type CM_RGAM_RAMA_EXP_REGION32_LUT_OFFSET; \ + type CM_RGAM_RAMA_EXP_REGION32_NUM_SEGMENTS; \ + type CM_RGAM_RAMA_EXP_REGION33_LUT_OFFSET; \ + type CM_RGAM_RAMA_EXP_REGION33_NUM_SEGMENTS; \ + type CM_RGAM_LUT_MODE; \ + type CM_CMOUT_ROUND_TRUNC_MODE; \ + type CM_BLNDGAM_LUT_MODE; \ + type CM_BLNDGAM_RAMB_EXP_REGION_START_B; \ + type CM_BLNDGAM_RAMB_EXP_REGION_START_SEGMENT_B; \ + type CM_BLNDGAM_RAMB_EXP_REGION_START_G; \ + type CM_BLNDGAM_RAMB_EXP_REGION_START_SEGMENT_G; \ + type CM_BLNDGAM_RAMB_EXP_REGION_START_R; \ + type CM_BLNDGAM_RAMB_EXP_REGION_START_SEGMENT_R; \ + type CM_BLNDGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; \ + type CM_BLNDGAM_RAMB_EXP_REGION_LINEAR_SLOPE_G; \ + type CM_BLNDGAM_RAMB_EXP_REGION_LINEAR_SLOPE_R; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_B; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_SLOPE_B; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_BASE_B; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_G; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_SLOPE_G; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_BASE_G; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_R; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_SLOPE_R; \ + type CM_BLNDGAM_RAMB_EXP_REGION_END_BASE_R; \ + type CM_BLNDGAM_RAMB_EXP_REGION0_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION0_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION1_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION1_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION2_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION2_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION3_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION3_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION4_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION4_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION5_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION5_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION6_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION6_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION7_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION7_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION8_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION8_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION9_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION9_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION10_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION10_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION11_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION11_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION12_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION12_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION13_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION13_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION14_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION14_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION15_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION15_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION16_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION16_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION17_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION17_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION18_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION18_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION19_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION19_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION20_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION20_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION21_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION21_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION22_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION22_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION23_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION23_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION24_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION24_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION25_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION25_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION26_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION26_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION27_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION27_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION28_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION28_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION29_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION29_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION30_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION30_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION31_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION31_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION32_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION32_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMB_EXP_REGION33_LUT_OFFSET; \ + type CM_BLNDGAM_RAMB_EXP_REGION33_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION_START_B; \ + type CM_BLNDGAM_RAMA_EXP_REGION_START_SEGMENT_B; \ + type CM_BLNDGAM_RAMA_EXP_REGION_START_G; \ + type CM_BLNDGAM_RAMA_EXP_REGION_START_SEGMENT_G; \ + type CM_BLNDGAM_RAMA_EXP_REGION_START_R; \ + type CM_BLNDGAM_RAMA_EXP_REGION_START_SEGMENT_R; \ + type CM_BLNDGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B; \ + type CM_BLNDGAM_RAMA_EXP_REGION_LINEAR_SLOPE_G; \ + type CM_BLNDGAM_RAMA_EXP_REGION_LINEAR_SLOPE_R; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_B; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_SLOPE_B; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_BASE_B; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_G; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_SLOPE_G; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_BASE_G; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_R; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_SLOPE_R; \ + type CM_BLNDGAM_RAMA_EXP_REGION_END_BASE_R; \ + type CM_BLNDGAM_RAMA_EXP_REGION0_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION1_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION2_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION2_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION3_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION3_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION4_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION4_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION5_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION5_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION6_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION6_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION7_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION7_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION8_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION8_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION9_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION9_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION10_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION10_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION11_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION11_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION12_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION12_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION13_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION13_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION14_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION14_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION15_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION15_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION16_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION16_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION17_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION17_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION18_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION18_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION19_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION19_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION20_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION20_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION21_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION21_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION22_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION22_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION23_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION23_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION24_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION24_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION25_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION25_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION26_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION26_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION27_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION27_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION28_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION28_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION29_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION29_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION30_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION30_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION31_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION31_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION32_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION32_NUM_SEGMENTS; \ + type CM_BLNDGAM_RAMA_EXP_REGION33_LUT_OFFSET; \ + type CM_BLNDGAM_RAMA_EXP_REGION33_NUM_SEGMENTS; \ + type CM_BLNDGAM_LUT_WRITE_EN_MASK; \ + type CM_BLNDGAM_LUT_WRITE_SEL; \ + type CM_BLNDGAM_CONFIG_STATUS; \ + type CM_BLNDGAM_LUT_INDEX; \ + type BLNDGAM_MEM_PWR_FORCE; \ + type CM_3DLUT_MODE; \ + type CM_3DLUT_SIZE; \ + type CM_3DLUT_INDEX; \ + type CM_3DLUT_DATA0; \ + type CM_3DLUT_DATA1; \ + type CM_3DLUT_DATA_30BIT; \ + type CM_3DLUT_WRITE_EN_MASK; \ + type CM_3DLUT_RAM_SEL; \ + type CM_3DLUT_30BIT_EN; \ + type CM_3DLUT_CONFIG_STATUS; \ + type CM_3DLUT_READ_SEL; \ + type CM_SHAPER_LUT_MODE; \ + type CM_SHAPER_RAMB_EXP_REGION_START_B; \ + type CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_B; \ + type CM_SHAPER_RAMB_EXP_REGION_START_G; \ + type CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_G; \ + type CM_SHAPER_RAMB_EXP_REGION_START_R; \ + type CM_SHAPER_RAMB_EXP_REGION_START_SEGMENT_R; \ + type CM_SHAPER_RAMB_EXP_REGION_END_B; \ + type CM_SHAPER_RAMB_EXP_REGION_END_BASE_B; \ + type CM_SHAPER_RAMB_EXP_REGION_END_G; \ + type CM_SHAPER_RAMB_EXP_REGION_END_BASE_G; \ + type CM_SHAPER_RAMB_EXP_REGION_END_R; \ + type CM_SHAPER_RAMB_EXP_REGION_END_BASE_R; \ + type CM_SHAPER_RAMB_EXP_REGION0_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION0_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION1_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION1_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION2_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION2_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION3_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION3_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION4_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION4_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION5_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION5_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION6_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION6_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION7_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION7_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION8_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION8_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION9_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION9_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION10_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION10_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION11_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION11_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION12_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION12_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION13_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION13_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION14_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION14_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION15_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION15_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION16_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION16_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION17_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION17_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION18_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION18_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION19_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION19_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION20_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION20_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION21_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION21_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION22_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION22_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION23_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION23_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION24_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION24_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION25_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION25_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION26_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION26_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION27_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION27_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION28_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION28_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION29_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION29_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION30_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION30_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION31_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION31_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION32_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION32_NUM_SEGMENTS; \ + type CM_SHAPER_RAMB_EXP_REGION33_LUT_OFFSET; \ + type CM_SHAPER_RAMB_EXP_REGION33_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION_START_B; \ + type CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_B; \ + type CM_SHAPER_RAMA_EXP_REGION_START_G; \ + type CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_G; \ + type CM_SHAPER_RAMA_EXP_REGION_START_R; \ + type CM_SHAPER_RAMA_EXP_REGION_START_SEGMENT_R; \ + type CM_SHAPER_RAMA_EXP_REGION_END_B; \ + type CM_SHAPER_RAMA_EXP_REGION_END_BASE_B; \ + type CM_SHAPER_RAMA_EXP_REGION_END_G; \ + type CM_SHAPER_RAMA_EXP_REGION_END_BASE_G; \ + type CM_SHAPER_RAMA_EXP_REGION_END_R; \ + type CM_SHAPER_RAMA_EXP_REGION_END_BASE_R; \ + type CM_SHAPER_RAMA_EXP_REGION0_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION0_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION1_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION1_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION2_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION2_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION3_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION3_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION4_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION4_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION5_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION5_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION6_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION6_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION7_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION7_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION8_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION8_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION9_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION9_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION10_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION10_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION11_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION11_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION12_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION12_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION13_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION13_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION14_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION14_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION15_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION15_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION16_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION16_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION17_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION17_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION18_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION18_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION19_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION19_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION20_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION20_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION21_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION21_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION22_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION22_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION23_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION23_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION24_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION24_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION25_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION25_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION26_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION26_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION27_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION27_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION28_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION28_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION29_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION29_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION30_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION30_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION31_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION31_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION32_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION32_NUM_SEGMENTS; \ + type CM_SHAPER_RAMA_EXP_REGION33_LUT_OFFSET; \ + type CM_SHAPER_RAMA_EXP_REGION33_NUM_SEGMENTS; \ + type CM_SHAPER_LUT_WRITE_EN_MASK; \ + type CM_SHAPER_CONFIG_STATUS; \ + type CM_SHAPER_LUT_WRITE_SEL; \ + type CM_SHAPER_LUT_INDEX; \ + type CM_SHAPER_LUT_DATA; \ + type CM_DGAM_CONFIG_STATUS; \ + type CM_ICSC_MODE; \ + type CM_ICSC_C11; \ + type CM_ICSC_C12; \ + type CM_ICSC_C33; \ + type CM_ICSC_C34; \ + type CM_BNS_BIAS_R; \ + type CM_BNS_BIAS_G; \ + type CM_BNS_BIAS_B; \ + type CM_BNS_SCALE_R; \ + type CM_BNS_SCALE_G; \ + type CM_BNS_SCALE_B; \ + type CM_DGAM_RAMB_EXP_REGION_START_B; \ + type CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_B; \ + type CM_DGAM_RAMB_EXP_REGION_START_G; \ + type CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_G; \ + type CM_DGAM_RAMB_EXP_REGION_START_R; \ + type CM_DGAM_RAMB_EXP_REGION_START_SEGMENT_R; \ + type CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; \ + type CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_G; \ + type CM_DGAM_RAMB_EXP_REGION_LINEAR_SLOPE_R; \ + type CM_DGAM_RAMB_EXP_REGION_END_B; \ + type CM_DGAM_RAMB_EXP_REGION_END_SLOPE_B; \ + type CM_DGAM_RAMB_EXP_REGION_END_BASE_B; \ + type CM_DGAM_RAMB_EXP_REGION_END_G; \ + type CM_DGAM_RAMB_EXP_REGION_END_SLOPE_G; \ + type CM_DGAM_RAMB_EXP_REGION_END_BASE_G; \ + type CM_DGAM_RAMB_EXP_REGION_END_R; \ + type CM_DGAM_RAMB_EXP_REGION_END_SLOPE_R; \ + type CM_DGAM_RAMB_EXP_REGION_END_BASE_R; \ + type CM_DGAM_RAMB_EXP_REGION0_LUT_OFFSET; \ + type CM_DGAM_RAMB_EXP_REGION0_NUM_SEGMENTS; \ + type CM_DGAM_RAMB_EXP_REGION1_LUT_OFFSET; \ + type CM_DGAM_RAMB_EXP_REGION1_NUM_SEGMENTS; \ + type CM_DGAM_RAMB_EXP_REGION14_LUT_OFFSET; \ + type CM_DGAM_RAMB_EXP_REGION14_NUM_SEGMENTS; \ + type CM_DGAM_RAMB_EXP_REGION15_LUT_OFFSET; \ + type CM_DGAM_RAMB_EXP_REGION15_NUM_SEGMENTS; \ + type CM_DGAM_RAMA_EXP_REGION_START_B; \ + type CM_DGAM_RAMA_EXP_REGION_START_SEGMENT_B; \ + type CM_DGAM_RAMA_EXP_REGION_START_G; \ + type CM_DGAM_RAMA_EXP_REGION_START_SEGMENT_G; \ + type CM_DGAM_RAMA_EXP_REGION_START_R; \ + type CM_DGAM_RAMA_EXP_REGION_START_SEGMENT_R; \ + type CM_DGAM_RAMA_EXP_REGION_LINEAR_SLOPE_B; \ + type CM_DGAM_RAMA_EXP_REGION_LINEAR_SLOPE_G; \ + type CM_DGAM_RAMA_EXP_REGION_LINEAR_SLOPE_R; \ + type CM_DGAM_RAMA_EXP_REGION_END_B; \ + type CM_DGAM_RAMA_EXP_REGION_END_SLOPE_B; \ + type CM_DGAM_RAMA_EXP_REGION_END_BASE_B; \ + type CM_DGAM_RAMA_EXP_REGION_END_G; \ + type CM_DGAM_RAMA_EXP_REGION_END_SLOPE_G; \ + type CM_DGAM_RAMA_EXP_REGION_END_BASE_G; \ + type CM_DGAM_RAMA_EXP_REGION_END_R; \ + type CM_DGAM_RAMA_EXP_REGION_END_SLOPE_R; \ + type CM_DGAM_RAMA_EXP_REGION_END_BASE_R; \ + type CM_DGAM_RAMA_EXP_REGION0_LUT_OFFSET; \ + type CM_DGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; \ + type CM_DGAM_RAMA_EXP_REGION1_LUT_OFFSET; \ + type CM_DGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; \ + type CM_DGAM_RAMA_EXP_REGION14_LUT_OFFSET; \ + type CM_DGAM_RAMA_EXP_REGION14_NUM_SEGMENTS; \ + type CM_DGAM_RAMA_EXP_REGION15_LUT_OFFSET; \ + type CM_DGAM_RAMA_EXP_REGION15_NUM_SEGMENTS; \ + type SHARED_MEM_PWR_DIS; \ + type CM_IGAM_LUT_FORMAT_R; \ + type CM_IGAM_LUT_FORMAT_G; \ + type CM_IGAM_LUT_FORMAT_B; \ + type CM_IGAM_LUT_HOST_EN; \ + type CM_IGAM_LUT_RW_MODE; \ + type CM_IGAM_LUT_WRITE_EN_MASK; \ + type CM_IGAM_LUT_SEL; \ + type CM_IGAM_LUT_SEQ_COLOR; \ + type CM_IGAM_DGAM_CONFIG_STATUS; \ + type CM_DGAM_LUT_WRITE_EN_MASK; \ + type CM_DGAM_LUT_WRITE_SEL; \ + type CM_DGAM_LUT_INDEX; \ + type CM_DGAM_LUT_DATA; \ + type CM_DGAM_LUT_MODE; \ + type CM_IGAM_LUT_MODE; \ + type CM_IGAM_INPUT_FORMAT; \ + type CM_IGAM_LUT_RW_INDEX; \ + type CM_BYPASS_EN; \ + type FORMAT_EXPANSION_MODE; \ + type CNVC_BYPASS; \ + type OUTPUT_FP; \ + type CNVC_SURFACE_PIXEL_FORMAT; \ + type CURSOR_MODE; \ + type CURSOR_PITCH; \ + type CURSOR_LINES_PER_CHUNK; \ + type CURSOR_ENABLE; \ + type CUR0_MODE; \ + type CUR0_EXPANSION_MODE; \ + type CUR0_ENABLE; \ + type CM_BYPASS; \ + type FORMAT_CONTROL__ALPHA_EN; \ + type CUR0_COLOR0; \ + type CUR0_COLOR1; + +struct dcn_dpp_shift { + TF_REG_FIELD_LIST(uint8_t) +}; + +struct dcn_dpp_mask { + TF_REG_FIELD_LIST(uint32_t) +}; + +#define DPP_COMMON_REG_VARIABLE_LIST \ + uint32_t DSCL_EXT_OVERSCAN_LEFT_RIGHT; \ + uint32_t DSCL_EXT_OVERSCAN_TOP_BOTTOM; \ + uint32_t OTG_H_BLANK; \ + uint32_t OTG_V_BLANK; \ + uint32_t SCL_MODE; \ + uint32_t LB_DATA_FORMAT; \ + uint32_t LB_MEMORY_CTRL; \ + uint32_t DSCL_AUTOCAL; \ + uint32_t SCL_BLACK_OFFSET; \ + uint32_t SCL_TAP_CONTROL; \ + uint32_t SCL_COEF_RAM_TAP_SELECT; \ + uint32_t SCL_COEF_RAM_TAP_DATA; \ + uint32_t DSCL_2TAP_CONTROL; \ + uint32_t MPC_SIZE; \ + uint32_t SCL_HORZ_FILTER_SCALE_RATIO; \ + uint32_t SCL_VERT_FILTER_SCALE_RATIO; \ + uint32_t SCL_HORZ_FILTER_SCALE_RATIO_C; \ + uint32_t SCL_VERT_FILTER_SCALE_RATIO_C; \ + uint32_t SCL_HORZ_FILTER_INIT; \ + uint32_t SCL_HORZ_FILTER_INIT_C; \ + uint32_t SCL_VERT_FILTER_INIT; \ + uint32_t SCL_VERT_FILTER_INIT_BOT; \ + uint32_t SCL_VERT_FILTER_INIT_C; \ + uint32_t SCL_VERT_FILTER_INIT_BOT_C; \ + uint32_t RECOUT_START; \ + uint32_t RECOUT_SIZE; \ + uint32_t CM_GAMUT_REMAP_CONTROL; \ + uint32_t CM_GAMUT_REMAP_C11_C12; \ + uint32_t CM_GAMUT_REMAP_C33_C34; \ + uint32_t CM_COMA_C11_C12; \ + uint32_t CM_COMA_C33_C34; \ + uint32_t CM_COMB_C11_C12; \ + uint32_t CM_COMB_C33_C34; \ + uint32_t CM_OCSC_CONTROL; \ + uint32_t CM_OCSC_C11_C12; \ + uint32_t CM_OCSC_C33_C34; \ + uint32_t CM_MEM_PWR_CTRL; \ + uint32_t CM_RGAM_LUT_DATA; \ + uint32_t CM_RGAM_LUT_WRITE_EN_MASK; \ + uint32_t CM_RGAM_LUT_INDEX; \ + uint32_t CM_RGAM_RAMB_START_CNTL_B; \ + uint32_t CM_RGAM_RAMB_START_CNTL_G; \ + uint32_t CM_RGAM_RAMB_START_CNTL_R; \ + uint32_t CM_RGAM_RAMB_SLOPE_CNTL_B; \ + uint32_t CM_RGAM_RAMB_SLOPE_CNTL_G; \ + uint32_t CM_RGAM_RAMB_SLOPE_CNTL_R; \ + uint32_t CM_RGAM_RAMB_END_CNTL1_B; \ + uint32_t CM_RGAM_RAMB_END_CNTL2_B; \ + uint32_t CM_RGAM_RAMB_END_CNTL1_G; \ + uint32_t CM_RGAM_RAMB_END_CNTL2_G; \ + uint32_t CM_RGAM_RAMB_END_CNTL1_R; \ + uint32_t CM_RGAM_RAMB_END_CNTL2_R; \ + uint32_t CM_RGAM_RAMB_REGION_0_1; \ + uint32_t CM_RGAM_RAMB_REGION_32_33; \ + uint32_t CM_RGAM_RAMA_START_CNTL_B; \ + uint32_t CM_RGAM_RAMA_START_CNTL_G; \ + uint32_t CM_RGAM_RAMA_START_CNTL_R; \ + uint32_t CM_RGAM_RAMA_SLOPE_CNTL_B; \ + uint32_t CM_RGAM_RAMA_SLOPE_CNTL_G; \ + uint32_t CM_RGAM_RAMA_SLOPE_CNTL_R; \ + uint32_t CM_RGAM_RAMA_END_CNTL1_B; \ + uint32_t CM_RGAM_RAMA_END_CNTL2_B; \ + uint32_t CM_RGAM_RAMA_END_CNTL1_G; \ + uint32_t CM_RGAM_RAMA_END_CNTL2_G; \ + uint32_t CM_RGAM_RAMA_END_CNTL1_R; \ + uint32_t CM_RGAM_RAMA_END_CNTL2_R; \ + uint32_t CM_RGAM_RAMA_REGION_0_1; \ + uint32_t CM_RGAM_RAMA_REGION_32_33; \ + uint32_t CM_RGAM_CONTROL; \ + uint32_t CM_CMOUT_CONTROL; \ + uint32_t CM_BLNDGAM_LUT_WRITE_EN_MASK; \ + uint32_t CM_BLNDGAM_CONTROL; \ + uint32_t CM_BLNDGAM_RAMB_START_CNTL_B; \ + uint32_t CM_BLNDGAM_RAMB_START_CNTL_G; \ + uint32_t CM_BLNDGAM_RAMB_START_CNTL_R; \ + uint32_t CM_BLNDGAM_RAMB_SLOPE_CNTL_B; \ + uint32_t CM_BLNDGAM_RAMB_SLOPE_CNTL_G; \ + uint32_t CM_BLNDGAM_RAMB_SLOPE_CNTL_R; \ + uint32_t CM_BLNDGAM_RAMB_END_CNTL1_B; \ + uint32_t CM_BLNDGAM_RAMB_END_CNTL2_B; \ + uint32_t CM_BLNDGAM_RAMB_END_CNTL1_G; \ + uint32_t CM_BLNDGAM_RAMB_END_CNTL2_G; \ + uint32_t CM_BLNDGAM_RAMB_END_CNTL1_R; \ + uint32_t CM_BLNDGAM_RAMB_END_CNTL2_R; \ + uint32_t CM_BLNDGAM_RAMB_REGION_0_1; \ + uint32_t CM_BLNDGAM_RAMB_REGION_2_3; \ + uint32_t CM_BLNDGAM_RAMB_REGION_4_5; \ + uint32_t CM_BLNDGAM_RAMB_REGION_6_7; \ + uint32_t CM_BLNDGAM_RAMB_REGION_8_9; \ + uint32_t CM_BLNDGAM_RAMB_REGION_10_11; \ + uint32_t CM_BLNDGAM_RAMB_REGION_12_13; \ + uint32_t CM_BLNDGAM_RAMB_REGION_14_15; \ + uint32_t CM_BLNDGAM_RAMB_REGION_16_17; \ + uint32_t CM_BLNDGAM_RAMB_REGION_18_19; \ + uint32_t CM_BLNDGAM_RAMB_REGION_20_21; \ + uint32_t CM_BLNDGAM_RAMB_REGION_22_23; \ + uint32_t CM_BLNDGAM_RAMB_REGION_24_25; \ + uint32_t CM_BLNDGAM_RAMB_REGION_26_27; \ + uint32_t CM_BLNDGAM_RAMB_REGION_28_29; \ + uint32_t CM_BLNDGAM_RAMB_REGION_30_31; \ + uint32_t CM_BLNDGAM_RAMB_REGION_32_33; \ + uint32_t CM_BLNDGAM_RAMA_START_CNTL_B; \ + uint32_t CM_BLNDGAM_RAMA_START_CNTL_G; \ + uint32_t CM_BLNDGAM_RAMA_START_CNTL_R; \ + uint32_t CM_BLNDGAM_RAMA_SLOPE_CNTL_B; \ + uint32_t CM_BLNDGAM_RAMA_SLOPE_CNTL_G; \ + uint32_t CM_BLNDGAM_RAMA_SLOPE_CNTL_R; \ + uint32_t CM_BLNDGAM_RAMA_END_CNTL1_B; \ + uint32_t CM_BLNDGAM_RAMA_END_CNTL2_B; \ + uint32_t CM_BLNDGAM_RAMA_END_CNTL1_G; \ + uint32_t CM_BLNDGAM_RAMA_END_CNTL2_G; \ + uint32_t CM_BLNDGAM_RAMA_END_CNTL1_R; \ + uint32_t CM_BLNDGAM_RAMA_END_CNTL2_R; \ + uint32_t CM_BLNDGAM_RAMA_REGION_0_1; \ + uint32_t CM_BLNDGAM_RAMA_REGION_2_3; \ + uint32_t CM_BLNDGAM_RAMA_REGION_4_5; \ + uint32_t CM_BLNDGAM_RAMA_REGION_6_7; \ + uint32_t CM_BLNDGAM_RAMA_REGION_8_9; \ + uint32_t CM_BLNDGAM_RAMA_REGION_10_11; \ + uint32_t CM_BLNDGAM_RAMA_REGION_12_13; \ + uint32_t CM_BLNDGAM_RAMA_REGION_14_15; \ + uint32_t CM_BLNDGAM_RAMA_REGION_16_17; \ + uint32_t CM_BLNDGAM_RAMA_REGION_18_19; \ + uint32_t CM_BLNDGAM_RAMA_REGION_20_21; \ + uint32_t CM_BLNDGAM_RAMA_REGION_22_23; \ + uint32_t CM_BLNDGAM_RAMA_REGION_24_25; \ + uint32_t CM_BLNDGAM_RAMA_REGION_26_27; \ + uint32_t CM_BLNDGAM_RAMA_REGION_28_29; \ + uint32_t CM_BLNDGAM_RAMA_REGION_30_31; \ + uint32_t CM_BLNDGAM_RAMA_REGION_32_33; \ + uint32_t CM_BLNDGAM_LUT_INDEX; \ + uint32_t CM_3DLUT_MODE; \ + uint32_t CM_3DLUT_INDEX; \ + uint32_t CM_3DLUT_DATA; \ + uint32_t CM_3DLUT_DATA_30BIT; \ + uint32_t CM_3DLUT_READ_WRITE_CONTROL; \ + uint32_t CM_SHAPER_LUT_WRITE_EN_MASK; \ + uint32_t CM_SHAPER_CONTROL; \ + uint32_t CM_SHAPER_RAMB_START_CNTL_B; \ + uint32_t CM_SHAPER_RAMB_START_CNTL_G; \ + uint32_t CM_SHAPER_RAMB_START_CNTL_R; \ + uint32_t CM_SHAPER_RAMB_END_CNTL_B; \ + uint32_t CM_SHAPER_RAMB_END_CNTL_G; \ + uint32_t CM_SHAPER_RAMB_END_CNTL_R; \ + uint32_t CM_SHAPER_RAMB_REGION_0_1; \ + uint32_t CM_SHAPER_RAMB_REGION_2_3; \ + uint32_t CM_SHAPER_RAMB_REGION_4_5; \ + uint32_t CM_SHAPER_RAMB_REGION_6_7; \ + uint32_t CM_SHAPER_RAMB_REGION_8_9; \ + uint32_t CM_SHAPER_RAMB_REGION_10_11; \ + uint32_t CM_SHAPER_RAMB_REGION_12_13; \ + uint32_t CM_SHAPER_RAMB_REGION_14_15; \ + uint32_t CM_SHAPER_RAMB_REGION_16_17; \ + uint32_t CM_SHAPER_RAMB_REGION_18_19; \ + uint32_t CM_SHAPER_RAMB_REGION_20_21; \ + uint32_t CM_SHAPER_RAMB_REGION_22_23; \ + uint32_t CM_SHAPER_RAMB_REGION_24_25; \ + uint32_t CM_SHAPER_RAMB_REGION_26_27; \ + uint32_t CM_SHAPER_RAMB_REGION_28_29; \ + uint32_t CM_SHAPER_RAMB_REGION_30_31; \ + uint32_t CM_SHAPER_RAMB_REGION_32_33; \ + uint32_t CM_SHAPER_RAMA_START_CNTL_B; \ + uint32_t CM_SHAPER_RAMA_START_CNTL_G; \ + uint32_t CM_SHAPER_RAMA_START_CNTL_R; \ + uint32_t CM_SHAPER_RAMA_END_CNTL_B; \ + uint32_t CM_SHAPER_RAMA_END_CNTL_G; \ + uint32_t CM_SHAPER_RAMA_END_CNTL_R; \ + uint32_t CM_SHAPER_RAMA_REGION_0_1; \ + uint32_t CM_SHAPER_RAMA_REGION_2_3; \ + uint32_t CM_SHAPER_RAMA_REGION_4_5; \ + uint32_t CM_SHAPER_RAMA_REGION_6_7; \ + uint32_t CM_SHAPER_RAMA_REGION_8_9; \ + uint32_t CM_SHAPER_RAMA_REGION_10_11; \ + uint32_t CM_SHAPER_RAMA_REGION_12_13; \ + uint32_t CM_SHAPER_RAMA_REGION_14_15; \ + uint32_t CM_SHAPER_RAMA_REGION_16_17; \ + uint32_t CM_SHAPER_RAMA_REGION_18_19; \ + uint32_t CM_SHAPER_RAMA_REGION_20_21; \ + uint32_t CM_SHAPER_RAMA_REGION_22_23; \ + uint32_t CM_SHAPER_RAMA_REGION_24_25; \ + uint32_t CM_SHAPER_RAMA_REGION_26_27; \ + uint32_t CM_SHAPER_RAMA_REGION_28_29; \ + uint32_t CM_SHAPER_RAMA_REGION_30_31; \ + uint32_t CM_SHAPER_RAMA_REGION_32_33; \ + uint32_t CM_SHAPER_LUT_INDEX; \ + uint32_t CM_SHAPER_LUT_DATA; \ + uint32_t CM_ICSC_CONTROL; \ + uint32_t CM_ICSC_C11_C12; \ + uint32_t CM_ICSC_C33_C34; \ + uint32_t CM_BNS_VALUES_R; \ + uint32_t CM_BNS_VALUES_G; \ + uint32_t CM_BNS_VALUES_B; \ + uint32_t CM_DGAM_RAMB_START_CNTL_B; \ + uint32_t CM_DGAM_RAMB_START_CNTL_G; \ + uint32_t CM_DGAM_RAMB_START_CNTL_R; \ + uint32_t CM_DGAM_RAMB_SLOPE_CNTL_B; \ + uint32_t CM_DGAM_RAMB_SLOPE_CNTL_G; \ + uint32_t CM_DGAM_RAMB_SLOPE_CNTL_R; \ + uint32_t CM_DGAM_RAMB_END_CNTL1_B; \ + uint32_t CM_DGAM_RAMB_END_CNTL2_B; \ + uint32_t CM_DGAM_RAMB_END_CNTL1_G; \ + uint32_t CM_DGAM_RAMB_END_CNTL2_G; \ + uint32_t CM_DGAM_RAMB_END_CNTL1_R; \ + uint32_t CM_DGAM_RAMB_END_CNTL2_R; \ + uint32_t CM_DGAM_RAMB_REGION_0_1; \ + uint32_t CM_DGAM_RAMB_REGION_14_15; \ + uint32_t CM_DGAM_RAMA_START_CNTL_B; \ + uint32_t CM_DGAM_RAMA_START_CNTL_G; \ + uint32_t CM_DGAM_RAMA_START_CNTL_R; \ + uint32_t CM_DGAM_RAMA_SLOPE_CNTL_B; \ + uint32_t CM_DGAM_RAMA_SLOPE_CNTL_G; \ + uint32_t CM_DGAM_RAMA_SLOPE_CNTL_R; \ + uint32_t CM_DGAM_RAMA_END_CNTL1_B; \ + uint32_t CM_DGAM_RAMA_END_CNTL2_B; \ + uint32_t CM_DGAM_RAMA_END_CNTL1_G; \ + uint32_t CM_DGAM_RAMA_END_CNTL2_G; \ + uint32_t CM_DGAM_RAMA_END_CNTL1_R; \ + uint32_t CM_DGAM_RAMA_END_CNTL2_R; \ + uint32_t CM_DGAM_RAMA_REGION_0_1; \ + uint32_t CM_DGAM_RAMA_REGION_14_15; \ + uint32_t CM_DGAM_LUT_WRITE_EN_MASK; \ + uint32_t CM_DGAM_LUT_INDEX; \ + uint32_t CM_DGAM_LUT_DATA; \ + uint32_t CM_CONTROL; \ + uint32_t CM_DGAM_CONTROL; \ + uint32_t CM_IGAM_CONTROL; \ + uint32_t CM_IGAM_LUT_RW_CONTROL; \ + uint32_t CM_IGAM_LUT_RW_INDEX; \ + uint32_t CM_IGAM_LUT_SEQ_COLOR; \ + uint32_t FORMAT_CONTROL; \ + uint32_t CNVC_SURFACE_PIXEL_FORMAT; \ + uint32_t CURSOR_CONTROL; \ + uint32_t CURSOR0_CONTROL; \ + uint32_t CURSOR0_COLOR0; \ + uint32_t CURSOR0_COLOR1; + +struct dcn_dpp_registers { + DPP_COMMON_REG_VARIABLE_LIST +}; + +struct dcn10_dpp { + struct dpp base; + + const struct dcn_dpp_registers *tf_regs; + const struct dcn_dpp_shift *tf_shift; + const struct dcn_dpp_mask *tf_mask; + + const uint16_t *filter_v; + const uint16_t *filter_h; + const uint16_t *filter_v_c; + const uint16_t *filter_h_c; + int lb_pixel_depth_supported; + int lb_memory_size; + int lb_bits_per_entry; + bool is_write_to_ram_a_safe; + struct scaler_data scl_data; + struct pwl_params pwl_data; +}; + +enum dcn10_input_csc_select { + INPUT_CSC_SELECT_BYPASS = 0, + INPUT_CSC_SELECT_ICSC, + INPUT_CSC_SELECT_COMA +}; + +void dpp1_set_cursor_attributes( + struct dpp *dpp_base, + enum dc_cursor_color_format color_format); + +bool dpp1_dscl_is_lb_conf_valid( + int ceil_vratio, + int num_partitions, + int vtaps); + +void dpp1_dscl_calc_lb_num_partitions( + const struct scaler_data *scl_data, + enum lb_memory_config lb_config, + int *num_part_y, + int *num_part_c); + +void dpp1_degamma_ram_select( + struct dpp *dpp_base, + bool use_ram_a); + +void dpp1_program_degamma_luta_settings( + struct dpp *dpp_base, + const struct pwl_params *params); + +void dpp1_program_degamma_lutb_settings( + struct dpp *dpp_base, + const struct pwl_params *params); + +void dpp1_program_degamma_lut( + struct dpp *dpp_base, + const struct pwl_result_data *rgb, + uint32_t num, + bool is_ram_a); + +void dpp1_power_on_degamma_lut( + struct dpp *dpp_base, + bool power_on); + +void dpp1_program_input_csc( + struct dpp *dpp_base, + enum dc_color_space color_space, + enum dcn10_input_csc_select select, + const struct out_csc_color_matrix *tbl_entry); + +void dpp1_program_bias_and_scale( + struct dpp *dpp_base, + struct dc_bias_and_scale *params); + +void dpp1_program_input_lut( + struct dpp *dpp_base, + const struct dc_gamma *gamma); + +void dpp1_full_bypass(struct dpp *dpp_base); + +void dpp1_set_degamma( + struct dpp *dpp_base, + enum ipp_degamma_mode mode); + +void dpp1_set_degamma_pwl(struct dpp *dpp_base, + const struct pwl_params *params); + +bool dpp_get_optimal_number_of_taps( + struct dpp *dpp, + struct scaler_data *scl_data, + const struct scaling_taps *in_taps); + +void dpp_reset(struct dpp *dpp_base); + +void dpp1_cm_program_regamma_lut( + struct dpp *dpp_base, + const struct pwl_result_data *rgb, + uint32_t num); + +void dpp1_cm_power_on_regamma_lut( + struct dpp *dpp_base, + bool power_on); + +void dpp1_cm_configure_regamma_lut( + struct dpp *dpp_base, + bool is_ram_a); + +/*program re gamma RAM A*/ +void dpp1_cm_program_regamma_luta_settings( + struct dpp *dpp_base, + const struct pwl_params *params); + +/*program re gamma RAM B*/ +void dpp1_cm_program_regamma_lutb_settings( + struct dpp *dpp_base, + const struct pwl_params *params); +void dpp1_cm_set_output_csc_adjustment( + struct dpp *dpp_base, + const uint16_t *regval); + +void dpp1_cm_set_output_csc_default( + struct dpp *dpp_base, + enum dc_color_space colorspace); + +void dpp1_cm_set_gamut_remap( + struct dpp *dpp, + const struct dpp_grph_csc_adjustment *adjust); + +void dpp1_dscl_set_scaler_manual_scale( + struct dpp *dpp_base, + const struct scaler_data *scl_data); + +void dpp1_cnv_setup ( + struct dpp *dpp_base, + enum surface_pixel_format format, + enum expansion_mode mode, + struct csc_transform input_csc_color_matrix, + enum dc_color_space input_color_space); + +void dpp1_full_bypass(struct dpp *dpp_base); + +void dpp1_construct(struct dcn10_dpp *dpp1, + struct dc_context *ctx, + uint32_t inst, + const struct dcn_dpp_registers *tf_regs, + const struct dcn_dpp_shift *tf_shift, + const struct dcn_dpp_mask *tf_mask); +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c new file mode 100644 index 000000000000..a5b099023652 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c @@ -0,0 +1,791 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" + +#include "core_types.h" + +#include "reg_helper.h" +#include "dcn10_dpp.h" +#include "basics/conversion.h" +#include "dcn10_cm_common.h" + +#define NUM_PHASES 64 +#define HORZ_MAX_TAPS 8 +#define VERT_MAX_TAPS 8 + +#define BLACK_OFFSET_RGB_Y 0x0 +#define BLACK_OFFSET_CBCR 0x8000 + +#define REG(reg)\ + dpp->tf_regs->reg + +#define CTX \ + dpp->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + dpp->tf_shift->field_name, dpp->tf_mask->field_name + +#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) + +struct dcn10_input_csc_matrix { + enum dc_color_space color_space; + uint16_t regval[12]; +}; + +enum dcn10_coef_filter_type_sel { + SCL_COEF_LUMA_VERT_FILTER = 0, + SCL_COEF_LUMA_HORZ_FILTER = 1, + SCL_COEF_CHROMA_VERT_FILTER = 2, + SCL_COEF_CHROMA_HORZ_FILTER = 3, + SCL_COEF_ALPHA_VERT_FILTER = 4, + SCL_COEF_ALPHA_HORZ_FILTER = 5 +}; + +enum dscl_autocal_mode { + AUTOCAL_MODE_OFF = 0, + + /* Autocal calculate the scaling ratio and initial phase and the + * DSCL_MODE_SEL must be set to 1 + */ + AUTOCAL_MODE_AUTOSCALE = 1, + /* Autocal perform auto centering without replication and the + * DSCL_MODE_SEL must be set to 0 + */ + AUTOCAL_MODE_AUTOCENTER = 2, + /* Autocal perform auto centering and auto replication and the + * DSCL_MODE_SEL must be set to 0 + */ + AUTOCAL_MODE_AUTOREPLICATE = 3 +}; + +enum dscl_mode_sel { + DSCL_MODE_SCALING_444_BYPASS = 0, + DSCL_MODE_SCALING_444_RGB_ENABLE = 1, + DSCL_MODE_SCALING_444_YCBCR_ENABLE = 2, + DSCL_MODE_SCALING_420_YCBCR_ENABLE = 3, + DSCL_MODE_SCALING_420_LUMA_BYPASS = 4, + DSCL_MODE_SCALING_420_CHROMA_BYPASS = 5, + DSCL_MODE_DSCL_BYPASS = 6 +}; + +enum gamut_remap_select { + GAMUT_REMAP_BYPASS = 0, + GAMUT_REMAP_COEFF, + GAMUT_REMAP_COMA_COEFF, + GAMUT_REMAP_COMB_COEFF +}; + +static const struct dcn10_input_csc_matrix dcn10_input_csc_matrix[] = { + {COLOR_SPACE_SRGB, + {0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, + {COLOR_SPACE_SRGB_LIMITED, + {0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} }, + {COLOR_SPACE_YCBCR601, + {0x2cdd, 0x2000, 0, 0xe991, 0xe926, 0x2000, 0xf4fd, 0x10ef, + 0, 0x2000, 0x38b4, 0xe3a6} }, + {COLOR_SPACE_YCBCR601_LIMITED, + {0x3353, 0x2568, 0, 0xe400, 0xe5dc, 0x2568, 0xf367, 0x1108, + 0, 0x2568, 0x40de, 0xdd3a} }, + {COLOR_SPACE_YCBCR709, + {0x3265, 0x2000, 0, 0xe6ce, 0xf105, 0x2000, 0xfa01, 0xa7d, 0, + 0x2000, 0x3b61, 0xe24f} }, + + {COLOR_SPACE_YCBCR709_LIMITED, + {0x39a6, 0x2568, 0, 0xe0d6, 0xeedd, 0x2568, 0xf925, 0x9a8, 0, + 0x2568, 0x43ee, 0xdbb2} } +}; + +static void program_gamut_remap( + struct dcn10_dpp *dpp, + const uint16_t *regval, + enum gamut_remap_select select) +{ + uint16_t selection = 0; + struct color_matrices_reg gam_regs; + + if (regval == NULL || select == GAMUT_REMAP_BYPASS) { + REG_SET(CM_GAMUT_REMAP_CONTROL, 0, + CM_GAMUT_REMAP_MODE, 0); + return; + } + switch (select) { + case GAMUT_REMAP_COEFF: + selection = 1; + break; + case GAMUT_REMAP_COMA_COEFF: + selection = 2; + break; + case GAMUT_REMAP_COMB_COEFF: + selection = 3; + break; + default: + break; + } + + gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_GAMUT_REMAP_C11; + gam_regs.masks.csc_c11 = dpp->tf_mask->CM_GAMUT_REMAP_C11; + gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_GAMUT_REMAP_C12; + gam_regs.masks.csc_c12 = dpp->tf_mask->CM_GAMUT_REMAP_C12; + + + if (select == GAMUT_REMAP_COEFF) { + gam_regs.csc_c11_c12 = REG(CM_GAMUT_REMAP_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_GAMUT_REMAP_C33_C34); + + cm_helper_program_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + + } else if (select == GAMUT_REMAP_COMA_COEFF) { + + gam_regs.csc_c11_c12 = REG(CM_COMA_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_COMA_C33_C34); + + cm_helper_program_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + + } else { + + gam_regs.csc_c11_c12 = REG(CM_COMB_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_COMB_C33_C34); + + cm_helper_program_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + } + + REG_SET( + CM_GAMUT_REMAP_CONTROL, 0, + CM_GAMUT_REMAP_MODE, selection); + +} + +void dpp1_cm_set_gamut_remap( + struct dpp *dpp_base, + const struct dpp_grph_csc_adjustment *adjust) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW) + /* Bypass if type is bypass or hw */ + program_gamut_remap(dpp, NULL, GAMUT_REMAP_BYPASS); + else { + struct fixed31_32 arr_matrix[12]; + uint16_t arr_reg_val[12]; + + arr_matrix[0] = adjust->temperature_matrix[0]; + arr_matrix[1] = adjust->temperature_matrix[1]; + arr_matrix[2] = adjust->temperature_matrix[2]; + arr_matrix[3] = dal_fixed31_32_zero; + + arr_matrix[4] = adjust->temperature_matrix[3]; + arr_matrix[5] = adjust->temperature_matrix[4]; + arr_matrix[6] = adjust->temperature_matrix[5]; + arr_matrix[7] = dal_fixed31_32_zero; + + arr_matrix[8] = adjust->temperature_matrix[6]; + arr_matrix[9] = adjust->temperature_matrix[7]; + arr_matrix[10] = adjust->temperature_matrix[8]; + arr_matrix[11] = dal_fixed31_32_zero; + + convert_float_matrix( + arr_reg_val, arr_matrix, 12); + + program_gamut_remap(dpp, arr_reg_val, GAMUT_REMAP_COEFF); + } +} + +static void dpp1_cm_program_color_matrix( + struct dcn10_dpp *dpp, + const uint16_t *regval) +{ + uint32_t mode; + struct color_matrices_reg gam_regs; + + REG_GET(CM_OCSC_CONTROL, CM_OCSC_MODE, &mode); + + if (regval == NULL) { + BREAK_TO_DEBUGGER(); + return; + } + mode = 4; + gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_OCSC_C11; + gam_regs.masks.csc_c11 = dpp->tf_mask->CM_OCSC_C11; + gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_OCSC_C12; + gam_regs.masks.csc_c12 = dpp->tf_mask->CM_OCSC_C12; + + if (mode == 4) { + + gam_regs.csc_c11_c12 = REG(CM_OCSC_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_OCSC_C33_C34); + + cm_helper_program_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + + } else { + + gam_regs.csc_c11_c12 = REG(CM_COMB_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_COMB_C33_C34); + + cm_helper_program_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + } +} + +void dpp1_cm_set_output_csc_default( + struct dpp *dpp_base, + enum dc_color_space colorspace) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + const uint16_t *regval = NULL; + int arr_size; + uint32_t ocsc_mode = 4; + + regval = find_color_matrix(colorspace, &arr_size); + if (regval == NULL) { + BREAK_TO_DEBUGGER(); + return; + } + dpp1_cm_program_color_matrix(dpp, regval); + REG_SET(CM_OCSC_CONTROL, 0, CM_OCSC_MODE, ocsc_mode); +} + +static void dpp1_cm_get_reg_field( + struct dcn10_dpp *dpp, + struct xfer_func_reg *reg) +{ + reg->shifts.exp_region0_lut_offset = dpp->tf_shift->CM_RGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->masks.exp_region0_lut_offset = dpp->tf_mask->CM_RGAM_RAMA_EXP_REGION0_LUT_OFFSET; + reg->shifts.exp_region0_num_segments = dpp->tf_shift->CM_RGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->masks.exp_region0_num_segments = dpp->tf_mask->CM_RGAM_RAMA_EXP_REGION0_NUM_SEGMENTS; + reg->shifts.exp_region1_lut_offset = dpp->tf_shift->CM_RGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->masks.exp_region1_lut_offset = dpp->tf_mask->CM_RGAM_RAMA_EXP_REGION1_LUT_OFFSET; + reg->shifts.exp_region1_num_segments = dpp->tf_shift->CM_RGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + reg->masks.exp_region1_num_segments = dpp->tf_mask->CM_RGAM_RAMA_EXP_REGION1_NUM_SEGMENTS; + + reg->shifts.field_region_end = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_END_B; + reg->masks.field_region_end = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_END_B; + reg->shifts.field_region_end_slope = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_END_SLOPE_B; + reg->masks.field_region_end_slope = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_END_SLOPE_B; + reg->shifts.field_region_end_base = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_END_BASE_B; + reg->masks.field_region_end_base = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_END_BASE_B; + reg->shifts.field_region_linear_slope = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; + reg->masks.field_region_linear_slope = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_LINEAR_SLOPE_B; + reg->shifts.exp_region_start = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_START_B; + reg->masks.exp_region_start = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_START_B; + reg->shifts.exp_resion_start_segment = dpp->tf_shift->CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_B; + reg->masks.exp_resion_start_segment = dpp->tf_mask->CM_RGAM_RAMB_EXP_REGION_START_SEGMENT_B; +} + +void dpp1_cm_set_output_csc_adjustment( + struct dpp *dpp_base, + const uint16_t *regval) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + uint32_t ocsc_mode = 4; + dpp1_cm_program_color_matrix(dpp, regval); + REG_SET(CM_OCSC_CONTROL, 0, CM_OCSC_MODE, ocsc_mode); +} + +void dpp1_cm_power_on_regamma_lut(struct dpp *dpp_base, + bool power_on) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_SET(CM_MEM_PWR_CTRL, 0, + RGAM_MEM_PWR_FORCE, power_on == true ? 0:1); + +} + +void dpp1_cm_program_regamma_lut(struct dpp *dpp_base, + const struct pwl_result_data *rgb, + uint32_t num) +{ + uint32_t i; + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + for (i = 0 ; i < num; i++) { + REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].red_reg); + REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].green_reg); + REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].blue_reg); + + REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].delta_red_reg); + REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].delta_green_reg); + REG_SET(CM_RGAM_LUT_DATA, 0, CM_RGAM_LUT_DATA, rgb[i].delta_blue_reg); + + } + +} + +void dpp1_cm_configure_regamma_lut( + struct dpp *dpp_base, + bool is_ram_a) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_UPDATE(CM_RGAM_LUT_WRITE_EN_MASK, + CM_RGAM_LUT_WRITE_EN_MASK, 7); + REG_UPDATE(CM_RGAM_LUT_WRITE_EN_MASK, + CM_RGAM_LUT_WRITE_SEL, is_ram_a == true ? 0:1); + REG_SET(CM_RGAM_LUT_INDEX, 0, CM_RGAM_LUT_INDEX, 0); +} + +/*program re gamma RAM A*/ +void dpp1_cm_program_regamma_luta_settings( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + struct xfer_func_reg gam_regs; + + dpp1_cm_get_reg_field(dpp, &gam_regs); + + gam_regs.start_cntl_b = REG(CM_RGAM_RAMA_START_CNTL_B); + gam_regs.start_cntl_g = REG(CM_RGAM_RAMA_START_CNTL_G); + gam_regs.start_cntl_r = REG(CM_RGAM_RAMA_START_CNTL_R); + gam_regs.start_slope_cntl_b = REG(CM_RGAM_RAMA_SLOPE_CNTL_B); + gam_regs.start_slope_cntl_g = REG(CM_RGAM_RAMA_SLOPE_CNTL_G); + gam_regs.start_slope_cntl_r = REG(CM_RGAM_RAMA_SLOPE_CNTL_R); + gam_regs.start_end_cntl1_b = REG(CM_RGAM_RAMA_END_CNTL1_B); + gam_regs.start_end_cntl2_b = REG(CM_RGAM_RAMA_END_CNTL2_B); + gam_regs.start_end_cntl1_g = REG(CM_RGAM_RAMA_END_CNTL1_G); + gam_regs.start_end_cntl2_g = REG(CM_RGAM_RAMA_END_CNTL2_G); + gam_regs.start_end_cntl1_r = REG(CM_RGAM_RAMA_END_CNTL1_R); + gam_regs.start_end_cntl2_r = REG(CM_RGAM_RAMA_END_CNTL2_R); + gam_regs.region_start = REG(CM_RGAM_RAMA_REGION_0_1); + gam_regs.region_end = REG(CM_RGAM_RAMA_REGION_32_33); + + cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs); + +} + +/*program re gamma RAM B*/ +void dpp1_cm_program_regamma_lutb_settings( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + struct xfer_func_reg gam_regs; + + dpp1_cm_get_reg_field(dpp, &gam_regs); + + gam_regs.start_cntl_b = REG(CM_RGAM_RAMB_START_CNTL_B); + gam_regs.start_cntl_g = REG(CM_RGAM_RAMB_START_CNTL_G); + gam_regs.start_cntl_r = REG(CM_RGAM_RAMB_START_CNTL_R); + gam_regs.start_slope_cntl_b = REG(CM_RGAM_RAMB_SLOPE_CNTL_B); + gam_regs.start_slope_cntl_g = REG(CM_RGAM_RAMB_SLOPE_CNTL_G); + gam_regs.start_slope_cntl_r = REG(CM_RGAM_RAMB_SLOPE_CNTL_R); + gam_regs.start_end_cntl1_b = REG(CM_RGAM_RAMB_END_CNTL1_B); + gam_regs.start_end_cntl2_b = REG(CM_RGAM_RAMB_END_CNTL2_B); + gam_regs.start_end_cntl1_g = REG(CM_RGAM_RAMB_END_CNTL1_G); + gam_regs.start_end_cntl2_g = REG(CM_RGAM_RAMB_END_CNTL2_G); + gam_regs.start_end_cntl1_r = REG(CM_RGAM_RAMB_END_CNTL1_R); + gam_regs.start_end_cntl2_r = REG(CM_RGAM_RAMB_END_CNTL2_R); + gam_regs.region_start = REG(CM_RGAM_RAMB_REGION_0_1); + gam_regs.region_end = REG(CM_RGAM_RAMB_REGION_32_33); + + cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs); +} + +void dpp1_program_input_csc( + struct dpp *dpp_base, + enum dc_color_space color_space, + enum dcn10_input_csc_select select, + const struct out_csc_color_matrix *tbl_entry) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + int i; + int arr_size = sizeof(dcn10_input_csc_matrix)/sizeof(struct dcn10_input_csc_matrix); + const uint16_t *regval = NULL; + uint32_t selection = 1; + struct color_matrices_reg gam_regs; + + if (select == INPUT_CSC_SELECT_BYPASS) { + REG_SET(CM_ICSC_CONTROL, 0, CM_ICSC_MODE, 0); + return; + } + + if (tbl_entry == NULL) { + for (i = 0; i < arr_size; i++) + if (dcn10_input_csc_matrix[i].color_space == color_space) { + regval = dcn10_input_csc_matrix[i].regval; + break; + } + + if (regval == NULL) { + BREAK_TO_DEBUGGER(); + return; + } + } else { + regval = tbl_entry->regval; + } + + if (select == INPUT_CSC_SELECT_COMA) + selection = 2; + REG_SET(CM_ICSC_CONTROL, 0, + CM_ICSC_MODE, selection); + + gam_regs.shifts.csc_c11 = dpp->tf_shift->CM_ICSC_C11; + gam_regs.masks.csc_c11 = dpp->tf_mask->CM_ICSC_C11; + gam_regs.shifts.csc_c12 = dpp->tf_shift->CM_ICSC_C12; + gam_regs.masks.csc_c12 = dpp->tf_mask->CM_ICSC_C12; + + + if (select == INPUT_CSC_SELECT_ICSC) { + + gam_regs.csc_c11_c12 = REG(CM_ICSC_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_ICSC_C33_C34); + + cm_helper_program_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + } else { + + gam_regs.csc_c11_c12 = REG(CM_COMA_C11_C12); + gam_regs.csc_c33_c34 = REG(CM_COMA_C33_C34); + + cm_helper_program_color_matrices( + dpp->base.ctx, + regval, + &gam_regs); + } +} + +//keep here for now, decide multi dce support later +void dpp1_program_bias_and_scale( + struct dpp *dpp_base, + struct dc_bias_and_scale *params) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_SET_2(CM_BNS_VALUES_R, 0, + CM_BNS_SCALE_R, params->scale_red, + CM_BNS_BIAS_R, params->bias_red); + + REG_SET_2(CM_BNS_VALUES_G, 0, + CM_BNS_SCALE_G, params->scale_green, + CM_BNS_BIAS_G, params->bias_green); + + REG_SET_2(CM_BNS_VALUES_B, 0, + CM_BNS_SCALE_B, params->scale_blue, + CM_BNS_BIAS_B, params->bias_blue); + +} + +/*program de gamma RAM B*/ +void dpp1_program_degamma_lutb_settings( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + struct xfer_func_reg gam_regs; + + dpp1_cm_get_reg_field(dpp, &gam_regs); + + gam_regs.start_cntl_b = REG(CM_DGAM_RAMB_START_CNTL_B); + gam_regs.start_cntl_g = REG(CM_DGAM_RAMB_START_CNTL_G); + gam_regs.start_cntl_r = REG(CM_DGAM_RAMB_START_CNTL_R); + gam_regs.start_slope_cntl_b = REG(CM_DGAM_RAMB_SLOPE_CNTL_B); + gam_regs.start_slope_cntl_g = REG(CM_DGAM_RAMB_SLOPE_CNTL_G); + gam_regs.start_slope_cntl_r = REG(CM_DGAM_RAMB_SLOPE_CNTL_R); + gam_regs.start_end_cntl1_b = REG(CM_DGAM_RAMB_END_CNTL1_B); + gam_regs.start_end_cntl2_b = REG(CM_DGAM_RAMB_END_CNTL2_B); + gam_regs.start_end_cntl1_g = REG(CM_DGAM_RAMB_END_CNTL1_G); + gam_regs.start_end_cntl2_g = REG(CM_DGAM_RAMB_END_CNTL2_G); + gam_regs.start_end_cntl1_r = REG(CM_DGAM_RAMB_END_CNTL1_R); + gam_regs.start_end_cntl2_r = REG(CM_DGAM_RAMB_END_CNTL2_R); + gam_regs.region_start = REG(CM_DGAM_RAMB_REGION_0_1); + gam_regs.region_end = REG(CM_DGAM_RAMB_REGION_14_15); + + + cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs); +} + +/*program de gamma RAM A*/ +void dpp1_program_degamma_luta_settings( + struct dpp *dpp_base, + const struct pwl_params *params) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + struct xfer_func_reg gam_regs; + + dpp1_cm_get_reg_field(dpp, &gam_regs); + + gam_regs.start_cntl_b = REG(CM_DGAM_RAMA_START_CNTL_B); + gam_regs.start_cntl_g = REG(CM_DGAM_RAMA_START_CNTL_G); + gam_regs.start_cntl_r = REG(CM_DGAM_RAMA_START_CNTL_R); + gam_regs.start_slope_cntl_b = REG(CM_DGAM_RAMA_SLOPE_CNTL_B); + gam_regs.start_slope_cntl_g = REG(CM_DGAM_RAMA_SLOPE_CNTL_G); + gam_regs.start_slope_cntl_r = REG(CM_DGAM_RAMA_SLOPE_CNTL_R); + gam_regs.start_end_cntl1_b = REG(CM_DGAM_RAMA_END_CNTL1_B); + gam_regs.start_end_cntl2_b = REG(CM_DGAM_RAMA_END_CNTL2_B); + gam_regs.start_end_cntl1_g = REG(CM_DGAM_RAMA_END_CNTL1_G); + gam_regs.start_end_cntl2_g = REG(CM_DGAM_RAMA_END_CNTL2_G); + gam_regs.start_end_cntl1_r = REG(CM_DGAM_RAMA_END_CNTL1_R); + gam_regs.start_end_cntl2_r = REG(CM_DGAM_RAMA_END_CNTL2_R); + gam_regs.region_start = REG(CM_DGAM_RAMA_REGION_0_1); + gam_regs.region_end = REG(CM_DGAM_RAMA_REGION_14_15); + + cm_helper_program_xfer_func(dpp->base.ctx, params, &gam_regs); +} + +void dpp1_power_on_degamma_lut( + struct dpp *dpp_base, + bool power_on) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_SET(CM_MEM_PWR_CTRL, 0, + SHARED_MEM_PWR_DIS, power_on == true ? 0:1); + +} + +static void dpp1_enable_cm_block( + struct dpp *dpp_base) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_UPDATE(CM_CMOUT_CONTROL, CM_CMOUT_ROUND_TRUNC_MODE, 8); + REG_UPDATE(CM_CONTROL, CM_BYPASS_EN, 0); +} + +void dpp1_set_degamma( + struct dpp *dpp_base, + enum ipp_degamma_mode mode) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + dpp1_enable_cm_block(dpp_base); + + switch (mode) { + case IPP_DEGAMMA_MODE_BYPASS: + /* Setting de gamma bypass for now */ + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 0); + break; + case IPP_DEGAMMA_MODE_HW_sRGB: + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 1); + break; + case IPP_DEGAMMA_MODE_HW_xvYCC: + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 2); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +void dpp1_degamma_ram_select( + struct dpp *dpp_base, + bool use_ram_a) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + if (use_ram_a) + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 3); + else + REG_UPDATE(CM_DGAM_CONTROL, CM_DGAM_LUT_MODE, 4); + +} + +static bool dpp1_degamma_ram_inuse( + struct dpp *dpp_base, + bool *ram_a_inuse) +{ + bool ret = false; + uint32_t status_reg = 0; + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_GET(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_DGAM_CONFIG_STATUS, + &status_reg); + + if (status_reg == 9) { + *ram_a_inuse = true; + ret = true; + } else if (status_reg == 10) { + *ram_a_inuse = false; + ret = true; + } + return ret; +} + +void dpp1_program_degamma_lut( + struct dpp *dpp_base, + const struct pwl_result_data *rgb, + uint32_t num, + bool is_ram_a) +{ + uint32_t i; + + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_HOST_EN, 0); + REG_UPDATE(CM_DGAM_LUT_WRITE_EN_MASK, + CM_DGAM_LUT_WRITE_EN_MASK, 7); + REG_UPDATE(CM_DGAM_LUT_WRITE_EN_MASK, CM_DGAM_LUT_WRITE_SEL, + is_ram_a == true ? 0:1); + + REG_SET(CM_DGAM_LUT_INDEX, 0, CM_DGAM_LUT_INDEX, 0); + for (i = 0 ; i < num; i++) { + REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].red_reg); + REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].green_reg); + REG_SET(CM_DGAM_LUT_DATA, 0, CM_DGAM_LUT_DATA, rgb[i].blue_reg); + + REG_SET(CM_DGAM_LUT_DATA, 0, + CM_DGAM_LUT_DATA, rgb[i].delta_red_reg); + REG_SET(CM_DGAM_LUT_DATA, 0, + CM_DGAM_LUT_DATA, rgb[i].delta_green_reg); + REG_SET(CM_DGAM_LUT_DATA, 0, + CM_DGAM_LUT_DATA, rgb[i].delta_blue_reg); + } +} + +void dpp1_set_degamma_pwl(struct dpp *dpp_base, + const struct pwl_params *params) +{ + bool is_ram_a = true; + + dpp1_power_on_degamma_lut(dpp_base, true); + dpp1_enable_cm_block(dpp_base); + dpp1_degamma_ram_inuse(dpp_base, &is_ram_a); + if (is_ram_a == true) + dpp1_program_degamma_lutb_settings(dpp_base, params); + else + dpp1_program_degamma_luta_settings(dpp_base, params); + + dpp1_program_degamma_lut(dpp_base, params->rgb_resulted, + params->hw_points_num, !is_ram_a); + dpp1_degamma_ram_select(dpp_base, !is_ram_a); +} + +void dpp1_full_bypass(struct dpp *dpp_base) +{ + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + /* Input pixel format: ARGB8888 */ + REG_SET(CNVC_SURFACE_PIXEL_FORMAT, 0, + CNVC_SURFACE_PIXEL_FORMAT, 0x8); + + /* Zero expansion */ + REG_SET_3(FORMAT_CONTROL, 0, + CNVC_BYPASS, 0, + FORMAT_CONTROL__ALPHA_EN, 0, + FORMAT_EXPANSION_MODE, 0); + + /* COLOR_KEYER_CONTROL.COLOR_KEYER_EN = 0 this should be default */ + if (dpp->tf_mask->CM_BYPASS_EN) + REG_SET(CM_CONTROL, 0, CM_BYPASS_EN, 1); + + /* Setting degamma bypass for now */ + REG_SET(CM_DGAM_CONTROL, 0, CM_DGAM_LUT_MODE, 0); +} + +static bool dpp1_ingamma_ram_inuse(struct dpp *dpp_base, + bool *ram_a_inuse) +{ + bool in_use = false; + uint32_t status_reg = 0; + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + + REG_GET(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_DGAM_CONFIG_STATUS, + &status_reg); + + // 1 => IGAM_RAMA, 3 => IGAM_RAMA & DGAM_ROMA, 4 => IGAM_RAMA & DGAM_ROMB + if (status_reg == 1 || status_reg == 3 || status_reg == 4) { + *ram_a_inuse = true; + in_use = true; + // 2 => IGAM_RAMB, 5 => IGAM_RAMB & DGAM_ROMA, 6 => IGAM_RAMB & DGAM_ROMB + } else if (status_reg == 2 || status_reg == 5 || status_reg == 6) { + *ram_a_inuse = false; + in_use = true; + } + return in_use; +} + +/* + * Input gamma LUT currently supports 256 values only. This means input color + * can have a maximum of 8 bits per channel (= 256 possible values) in order to + * have a one-to-one mapping with the LUT. Truncation will occur with color + * values greater than 8 bits. + * + * In the future, this function should support additional input gamma methods, + * such as piecewise linear mapping, and input gamma bypass. + */ +void dpp1_program_input_lut( + struct dpp *dpp_base, + const struct dc_gamma *gamma) +{ + int i; + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + bool rama_occupied = false; + uint32_t ram_num; + // Power on LUT memory. + REG_SET(CM_MEM_PWR_CTRL, 0, SHARED_MEM_PWR_DIS, 1); + dpp1_enable_cm_block(dpp_base); + // Determine whether to use RAM A or RAM B + dpp1_ingamma_ram_inuse(dpp_base, &rama_occupied); + if (!rama_occupied) + REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_SEL, 0); + else + REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_SEL, 1); + // RW mode is 256-entry LUT + REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_RW_MODE, 0); + // IGAM Input format should be 8 bits per channel. + REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_INPUT_FORMAT, 0); + // Do not mask any R,G,B values + REG_UPDATE(CM_IGAM_LUT_RW_CONTROL, CM_IGAM_LUT_WRITE_EN_MASK, 7); + // LUT-256, unsigned, integer, new u0.12 format + REG_UPDATE_3( + CM_IGAM_CONTROL, + CM_IGAM_LUT_FORMAT_R, 3, + CM_IGAM_LUT_FORMAT_G, 3, + CM_IGAM_LUT_FORMAT_B, 3); + // Start at index 0 of IGAM LUT + REG_UPDATE(CM_IGAM_LUT_RW_INDEX, CM_IGAM_LUT_RW_INDEX, 0); + for (i = 0; i < gamma->num_entries; i++) { + REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR, + dal_fixed31_32_round( + gamma->entries.red[i])); + REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR, + dal_fixed31_32_round( + gamma->entries.green[i])); + REG_SET(CM_IGAM_LUT_SEQ_COLOR, 0, CM_IGAM_LUT_SEQ_COLOR, + dal_fixed31_32_round( + gamma->entries.blue[i])); + } + // Power off LUT memory + REG_SET(CM_MEM_PWR_CTRL, 0, SHARED_MEM_PWR_DIS, 0); + // Enable IGAM LUT on ram we just wrote to. 2 => RAMA, 3 => RAMB + REG_UPDATE(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, rama_occupied ? 3 : 2); + REG_GET(CM_IGAM_CONTROL, CM_IGAM_LUT_MODE, &ram_num); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c new file mode 100644 index 000000000000..3eb824debf43 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c @@ -0,0 +1,710 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" + +#include "core_types.h" + +#include "reg_helper.h" +#include "dcn10_dpp.h" +#include "basics/conversion.h" + + +#define NUM_PHASES 64 +#define HORZ_MAX_TAPS 8 +#define VERT_MAX_TAPS 8 + +#define BLACK_OFFSET_RGB_Y 0x0 +#define BLACK_OFFSET_CBCR 0x8000 + +#define REG(reg)\ + dpp->tf_regs->reg + +#define CTX \ + dpp->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + dpp->tf_shift->field_name, dpp->tf_mask->field_name + +enum dcn10_coef_filter_type_sel { + SCL_COEF_LUMA_VERT_FILTER = 0, + SCL_COEF_LUMA_HORZ_FILTER = 1, + SCL_COEF_CHROMA_VERT_FILTER = 2, + SCL_COEF_CHROMA_HORZ_FILTER = 3, + SCL_COEF_ALPHA_VERT_FILTER = 4, + SCL_COEF_ALPHA_HORZ_FILTER = 5 +}; + +enum dscl_autocal_mode { + AUTOCAL_MODE_OFF = 0, + + /* Autocal calculate the scaling ratio and initial phase and the + * DSCL_MODE_SEL must be set to 1 + */ + AUTOCAL_MODE_AUTOSCALE = 1, + /* Autocal perform auto centering without replication and the + * DSCL_MODE_SEL must be set to 0 + */ + AUTOCAL_MODE_AUTOCENTER = 2, + /* Autocal perform auto centering and auto replication and the + * DSCL_MODE_SEL must be set to 0 + */ + AUTOCAL_MODE_AUTOREPLICATE = 3 +}; + +enum dscl_mode_sel { + DSCL_MODE_SCALING_444_BYPASS = 0, + DSCL_MODE_SCALING_444_RGB_ENABLE = 1, + DSCL_MODE_SCALING_444_YCBCR_ENABLE = 2, + DSCL_MODE_SCALING_420_YCBCR_ENABLE = 3, + DSCL_MODE_SCALING_420_LUMA_BYPASS = 4, + DSCL_MODE_SCALING_420_CHROMA_BYPASS = 5, + DSCL_MODE_DSCL_BYPASS = 6 +}; + +static void dpp1_dscl_set_overscan( + struct dcn10_dpp *dpp, + const struct scaler_data *data) +{ + uint32_t left = data->recout.x; + uint32_t top = data->recout.y; + + int right = data->h_active - data->recout.x - data->recout.width; + int bottom = data->v_active - data->recout.y - data->recout.height; + + if (right < 0) { + BREAK_TO_DEBUGGER(); + right = 0; + } + if (bottom < 0) { + BREAK_TO_DEBUGGER(); + bottom = 0; + } + + REG_SET_2(DSCL_EXT_OVERSCAN_LEFT_RIGHT, 0, + EXT_OVERSCAN_LEFT, left, + EXT_OVERSCAN_RIGHT, right); + + REG_SET_2(DSCL_EXT_OVERSCAN_TOP_BOTTOM, 0, + EXT_OVERSCAN_BOTTOM, bottom, + EXT_OVERSCAN_TOP, top); +} + +static void dpp1_dscl_set_otg_blank( + struct dcn10_dpp *dpp, const struct scaler_data *data) +{ + uint32_t h_blank_start = data->h_active; + uint32_t h_blank_end = 0; + uint32_t v_blank_start = data->v_active; + uint32_t v_blank_end = 0; + + REG_SET_2(OTG_H_BLANK, 0, + OTG_H_BLANK_START, h_blank_start, + OTG_H_BLANK_END, h_blank_end); + + REG_SET_2(OTG_V_BLANK, 0, + OTG_V_BLANK_START, v_blank_start, + OTG_V_BLANK_END, v_blank_end); +} + +static int dpp1_dscl_get_pixel_depth_val(enum lb_pixel_depth depth) +{ + if (depth == LB_PIXEL_DEPTH_30BPP) + return 0; /* 10 bpc */ + else if (depth == LB_PIXEL_DEPTH_24BPP) + return 1; /* 8 bpc */ + else if (depth == LB_PIXEL_DEPTH_18BPP) + return 2; /* 6 bpc */ + else if (depth == LB_PIXEL_DEPTH_36BPP) + return 3; /* 12 bpc */ + else { + ASSERT(0); + return -1; /* Unsupported */ + } +} + +static bool dpp1_dscl_is_video_format(enum pixel_format format) +{ + if (format >= PIXEL_FORMAT_VIDEO_BEGIN + && format <= PIXEL_FORMAT_VIDEO_END) + return true; + else + return false; +} + +static bool dpp1_dscl_is_420_format(enum pixel_format format) +{ + if (format == PIXEL_FORMAT_420BPP8 || + format == PIXEL_FORMAT_420BPP10) + return true; + else + return false; +} + +static enum dscl_mode_sel dpp1_dscl_get_dscl_mode( + struct dpp *dpp_base, + const struct scaler_data *data, + bool dbg_always_scale) +{ + const long long one = dal_fixed31_32_one.value; + + if (dpp_base->caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT) { + /* DSCL is processing data in fixed format */ + if (data->format == PIXEL_FORMAT_FP16) + return DSCL_MODE_DSCL_BYPASS; + } + + if (data->ratios.horz.value == one + && data->ratios.vert.value == one + && data->ratios.horz_c.value == one + && data->ratios.vert_c.value == one + && !dbg_always_scale) + return DSCL_MODE_SCALING_444_BYPASS; + + if (!dpp1_dscl_is_420_format(data->format)) { + if (dpp1_dscl_is_video_format(data->format)) + return DSCL_MODE_SCALING_444_YCBCR_ENABLE; + else + return DSCL_MODE_SCALING_444_RGB_ENABLE; + } + if (data->ratios.horz.value == one && data->ratios.vert.value == one) + return DSCL_MODE_SCALING_420_LUMA_BYPASS; + if (data->ratios.horz_c.value == one && data->ratios.vert_c.value == one) + return DSCL_MODE_SCALING_420_CHROMA_BYPASS; + + return DSCL_MODE_SCALING_420_YCBCR_ENABLE; +} + +static void dpp1_dscl_set_lb( + struct dcn10_dpp *dpp, + const struct line_buffer_params *lb_params, + enum lb_memory_config mem_size_config) +{ + /* LB */ + if (dpp->base.caps->dscl_data_proc_format == DSCL_DATA_PRCESSING_FIXED_FORMAT) { + /* DSCL caps: pixel data processed in fixed format */ + uint32_t pixel_depth = dpp1_dscl_get_pixel_depth_val(lb_params->depth); + uint32_t dyn_pix_depth = lb_params->dynamic_pixel_depth; + + REG_SET_7(LB_DATA_FORMAT, 0, + PIXEL_DEPTH, pixel_depth, /* Pixel depth stored in LB */ + PIXEL_EXPAN_MODE, lb_params->pixel_expan_mode, /* Pixel expansion mode */ + PIXEL_REDUCE_MODE, 1, /* Pixel reduction mode: Rounding */ + DYNAMIC_PIXEL_DEPTH, dyn_pix_depth, /* Dynamic expansion pixel depth */ + DITHER_EN, 0, /* Dithering enable: Disabled */ + INTERLEAVE_EN, lb_params->interleave_en, /* Interleave source enable */ + LB_DATA_FORMAT__ALPHA_EN, lb_params->alpha_en); /* Alpha enable */ + } + + REG_SET_2(LB_MEMORY_CTRL, 0, + MEMORY_CONFIG, mem_size_config, + LB_MAX_PARTITIONS, 63); +} + +static const uint16_t *dpp1_dscl_get_filter_coeffs_64p(int taps, struct fixed31_32 ratio) +{ + if (taps == 8) + return get_filter_8tap_64p(ratio); + else if (taps == 7) + return get_filter_7tap_64p(ratio); + else if (taps == 6) + return get_filter_6tap_64p(ratio); + else if (taps == 5) + return get_filter_5tap_64p(ratio); + else if (taps == 4) + return get_filter_4tap_64p(ratio); + else if (taps == 3) + return get_filter_3tap_64p(ratio); + else if (taps == 2) + return get_filter_2tap_64p(); + else if (taps == 1) + return NULL; + else { + /* should never happen, bug */ + BREAK_TO_DEBUGGER(); + return NULL; + } +} + +static void dpp1_dscl_set_scaler_filter( + struct dcn10_dpp *dpp, + uint32_t taps, + enum dcn10_coef_filter_type_sel filter_type, + const uint16_t *filter) +{ + const int tap_pairs = (taps + 1) / 2; + int phase; + int pair; + uint16_t odd_coef, even_coef; + + REG_SET_3(SCL_COEF_RAM_TAP_SELECT, 0, + SCL_COEF_RAM_TAP_PAIR_IDX, 0, + SCL_COEF_RAM_PHASE, 0, + SCL_COEF_RAM_FILTER_TYPE, filter_type); + + for (phase = 0; phase < (NUM_PHASES / 2 + 1); phase++) { + for (pair = 0; pair < tap_pairs; pair++) { + even_coef = filter[phase * taps + 2 * pair]; + if ((pair * 2 + 1) < taps) + odd_coef = filter[phase * taps + 2 * pair + 1]; + else + odd_coef = 0; + + REG_SET_4(SCL_COEF_RAM_TAP_DATA, 0, + /* Even tap coefficient (bits 1:0 fixed to 0) */ + SCL_COEF_RAM_EVEN_TAP_COEF, even_coef, + /* Write/read control for even coefficient */ + SCL_COEF_RAM_EVEN_TAP_COEF_EN, 1, + /* Odd tap coefficient (bits 1:0 fixed to 0) */ + SCL_COEF_RAM_ODD_TAP_COEF, odd_coef, + /* Write/read control for odd coefficient */ + SCL_COEF_RAM_ODD_TAP_COEF_EN, 1); + } + } + +} + +static void dpp1_dscl_set_scl_filter( + struct dcn10_dpp *dpp, + const struct scaler_data *scl_data, + bool chroma_coef_mode) +{ + bool h_2tap_hardcode_coef_en = false; + bool v_2tap_hardcode_coef_en = false; + bool h_2tap_sharp_en = false; + bool v_2tap_sharp_en = false; + uint32_t h_2tap_sharp_factor = scl_data->sharpness.horz; + uint32_t v_2tap_sharp_factor = scl_data->sharpness.vert; + bool coef_ram_current; + const uint16_t *filter_h = NULL; + const uint16_t *filter_v = NULL; + const uint16_t *filter_h_c = NULL; + const uint16_t *filter_v_c = NULL; + + h_2tap_hardcode_coef_en = scl_data->taps.h_taps < 3 + && scl_data->taps.h_taps_c < 3 + && (scl_data->taps.h_taps > 1 && scl_data->taps.h_taps_c > 1); + v_2tap_hardcode_coef_en = scl_data->taps.v_taps < 3 + && scl_data->taps.v_taps_c < 3 + && (scl_data->taps.v_taps > 1 && scl_data->taps.v_taps_c > 1); + + h_2tap_sharp_en = h_2tap_hardcode_coef_en && h_2tap_sharp_factor != 0; + v_2tap_sharp_en = v_2tap_hardcode_coef_en && v_2tap_sharp_factor != 0; + + REG_UPDATE_6(DSCL_2TAP_CONTROL, + SCL_H_2TAP_HARDCODE_COEF_EN, h_2tap_hardcode_coef_en, + SCL_H_2TAP_SHARP_EN, h_2tap_sharp_en, + SCL_H_2TAP_SHARP_FACTOR, h_2tap_sharp_factor, + SCL_V_2TAP_HARDCODE_COEF_EN, v_2tap_hardcode_coef_en, + SCL_V_2TAP_SHARP_EN, v_2tap_sharp_en, + SCL_V_2TAP_SHARP_FACTOR, v_2tap_sharp_factor); + + if (!v_2tap_hardcode_coef_en || !h_2tap_hardcode_coef_en) { + bool filter_updated = false; + + filter_h = dpp1_dscl_get_filter_coeffs_64p( + scl_data->taps.h_taps, scl_data->ratios.horz); + filter_v = dpp1_dscl_get_filter_coeffs_64p( + scl_data->taps.v_taps, scl_data->ratios.vert); + + filter_updated = (filter_h && (filter_h != dpp->filter_h)) + || (filter_v && (filter_v != dpp->filter_v)); + + if (chroma_coef_mode) { + filter_h_c = dpp1_dscl_get_filter_coeffs_64p( + scl_data->taps.h_taps_c, scl_data->ratios.horz_c); + filter_v_c = dpp1_dscl_get_filter_coeffs_64p( + scl_data->taps.v_taps_c, scl_data->ratios.vert_c); + filter_updated = filter_updated || (filter_h_c && (filter_h_c != dpp->filter_h_c)) + || (filter_v_c && (filter_v_c != dpp->filter_v_c)); + } + + if (filter_updated) { + uint32_t scl_mode = REG_READ(SCL_MODE); + + if (!h_2tap_hardcode_coef_en && filter_h) { + dpp1_dscl_set_scaler_filter( + dpp, scl_data->taps.h_taps, + SCL_COEF_LUMA_HORZ_FILTER, filter_h); + } + dpp->filter_h = filter_h; + if (!v_2tap_hardcode_coef_en && filter_v) { + dpp1_dscl_set_scaler_filter( + dpp, scl_data->taps.v_taps, + SCL_COEF_LUMA_VERT_FILTER, filter_v); + } + dpp->filter_v = filter_v; + if (chroma_coef_mode) { + if (!h_2tap_hardcode_coef_en && filter_h_c) { + dpp1_dscl_set_scaler_filter( + dpp, scl_data->taps.h_taps_c, + SCL_COEF_CHROMA_HORZ_FILTER, filter_h_c); + } + if (!v_2tap_hardcode_coef_en && filter_v_c) { + dpp1_dscl_set_scaler_filter( + dpp, scl_data->taps.v_taps_c, + SCL_COEF_CHROMA_VERT_FILTER, filter_v_c); + } + } + dpp->filter_h_c = filter_h_c; + dpp->filter_v_c = filter_v_c; + + coef_ram_current = get_reg_field_value_ex( + scl_mode, dpp->tf_mask->SCL_COEF_RAM_SELECT_CURRENT, + dpp->tf_shift->SCL_COEF_RAM_SELECT_CURRENT); + + /* Swap coefficient RAM and set chroma coefficient mode */ + REG_SET_2(SCL_MODE, scl_mode, + SCL_COEF_RAM_SELECT, !coef_ram_current, + SCL_CHROMA_COEF_MODE, chroma_coef_mode); + } + } +} + +static int dpp1_dscl_get_lb_depth_bpc(enum lb_pixel_depth depth) +{ + if (depth == LB_PIXEL_DEPTH_30BPP) + return 10; + else if (depth == LB_PIXEL_DEPTH_24BPP) + return 8; + else if (depth == LB_PIXEL_DEPTH_18BPP) + return 6; + else if (depth == LB_PIXEL_DEPTH_36BPP) + return 12; + else { + BREAK_TO_DEBUGGER(); + return -1; /* Unsupported */ + } +} + +void dpp1_dscl_calc_lb_num_partitions( + const struct scaler_data *scl_data, + enum lb_memory_config lb_config, + int *num_part_y, + int *num_part_c) +{ + int line_size = scl_data->viewport.width < scl_data->recout.width ? + scl_data->viewport.width : scl_data->recout.width; + int line_size_c = scl_data->viewport_c.width < scl_data->recout.width ? + scl_data->viewport_c.width : scl_data->recout.width; + int lb_bpc = dpp1_dscl_get_lb_depth_bpc(scl_data->lb_params.depth); + int memory_line_size_y = (line_size * lb_bpc + 71) / 72; /* +71 to ceil */ + int memory_line_size_c = (line_size_c * lb_bpc + 71) / 72; /* +71 to ceil */ + int memory_line_size_a = (line_size + 5) / 6; /* +5 to ceil */ + int lb_memory_size, lb_memory_size_c, lb_memory_size_a, num_partitions_a; + + if (lb_config == LB_MEMORY_CONFIG_1) { + lb_memory_size = 816; + lb_memory_size_c = 816; + lb_memory_size_a = 984; + } else if (lb_config == LB_MEMORY_CONFIG_2) { + lb_memory_size = 1088; + lb_memory_size_c = 1088; + lb_memory_size_a = 1312; + } else if (lb_config == LB_MEMORY_CONFIG_3) { + /* 420 mode: using 3rd mem from Y, Cr and Cb */ + lb_memory_size = 816 + 1088 + 848 + 848 + 848; + lb_memory_size_c = 816 + 1088; + lb_memory_size_a = 984 + 1312 + 456; + } else { + lb_memory_size = 816 + 1088 + 848; + lb_memory_size_c = 816 + 1088 + 848; + lb_memory_size_a = 984 + 1312 + 456; + } + *num_part_y = lb_memory_size / memory_line_size_y; + *num_part_c = lb_memory_size_c / memory_line_size_c; + num_partitions_a = lb_memory_size_a / memory_line_size_a; + + if (scl_data->lb_params.alpha_en + && (num_partitions_a < *num_part_y)) + *num_part_y = num_partitions_a; + + if (*num_part_y > 64) + *num_part_y = 64; + if (*num_part_c > 64) + *num_part_c = 64; + +} + +bool dpp1_dscl_is_lb_conf_valid(int ceil_vratio, int num_partitions, int vtaps) +{ + if (ceil_vratio > 2) + return vtaps <= (num_partitions - ceil_vratio + 2); + else + return vtaps <= num_partitions; +} + +/*find first match configuration which meets the min required lb size*/ +static enum lb_memory_config dpp1_dscl_find_lb_memory_config(struct dcn10_dpp *dpp, + const struct scaler_data *scl_data) +{ + int num_part_y, num_part_c; + int vtaps = scl_data->taps.v_taps; + int vtaps_c = scl_data->taps.v_taps_c; + int ceil_vratio = dal_fixed31_32_ceil(scl_data->ratios.vert); + int ceil_vratio_c = dal_fixed31_32_ceil(scl_data->ratios.vert_c); + enum lb_memory_config mem_cfg = LB_MEMORY_CONFIG_0; + + if (dpp->base.ctx->dc->debug.use_max_lb) + return mem_cfg; + + dpp->base.caps->dscl_calc_lb_num_partitions( + scl_data, LB_MEMORY_CONFIG_1, &num_part_y, &num_part_c); + + if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps) + && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c)) + return LB_MEMORY_CONFIG_1; + + dpp->base.caps->dscl_calc_lb_num_partitions( + scl_data, LB_MEMORY_CONFIG_2, &num_part_y, &num_part_c); + + if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps) + && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c)) + return LB_MEMORY_CONFIG_2; + + if (scl_data->format == PIXEL_FORMAT_420BPP8 + || scl_data->format == PIXEL_FORMAT_420BPP10) { + dpp->base.caps->dscl_calc_lb_num_partitions( + scl_data, LB_MEMORY_CONFIG_3, &num_part_y, &num_part_c); + + if (dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps) + && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c)) + return LB_MEMORY_CONFIG_3; + } + + dpp->base.caps->dscl_calc_lb_num_partitions( + scl_data, LB_MEMORY_CONFIG_0, &num_part_y, &num_part_c); + + /*Ensure we can support the requested number of vtaps*/ + ASSERT(dpp1_dscl_is_lb_conf_valid(ceil_vratio, num_part_y, vtaps) + && dpp1_dscl_is_lb_conf_valid(ceil_vratio_c, num_part_c, vtaps_c)); + + return LB_MEMORY_CONFIG_0; +} + +void dpp1_dscl_set_scaler_auto_scale( + struct dpp *dpp_base, + const struct scaler_data *scl_data) +{ + enum lb_memory_config lb_config; + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + enum dscl_mode_sel dscl_mode = dpp1_dscl_get_dscl_mode( + dpp_base, scl_data, dpp_base->ctx->dc->debug.always_scale); + bool ycbcr = scl_data->format >= PIXEL_FORMAT_VIDEO_BEGIN + && scl_data->format <= PIXEL_FORMAT_VIDEO_END; + + dpp1_dscl_set_overscan(dpp, scl_data); + + dpp1_dscl_set_otg_blank(dpp, scl_data); + + REG_UPDATE(SCL_MODE, DSCL_MODE, dscl_mode); + + if (dscl_mode == DSCL_MODE_DSCL_BYPASS) + return; + + lb_config = dpp1_dscl_find_lb_memory_config(dpp, scl_data); + dpp1_dscl_set_lb(dpp, &scl_data->lb_params, lb_config); + + if (dscl_mode == DSCL_MODE_SCALING_444_BYPASS) + return; + + /* TODO: v_min */ + REG_SET_3(DSCL_AUTOCAL, 0, + AUTOCAL_MODE, AUTOCAL_MODE_AUTOSCALE, + AUTOCAL_NUM_PIPE, 0, + AUTOCAL_PIPE_ID, 0); + + /* Black offsets */ + if (ycbcr) + REG_SET_2(SCL_BLACK_OFFSET, 0, + SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, + SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR); + else + + REG_SET_2(SCL_BLACK_OFFSET, 0, + SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, + SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y); + + REG_SET_4(SCL_TAP_CONTROL, 0, + SCL_V_NUM_TAPS, scl_data->taps.v_taps - 1, + SCL_H_NUM_TAPS, scl_data->taps.h_taps - 1, + SCL_V_NUM_TAPS_C, scl_data->taps.v_taps_c - 1, + SCL_H_NUM_TAPS_C, scl_data->taps.h_taps_c - 1); + + dpp1_dscl_set_scl_filter(dpp, scl_data, ycbcr); +} + + +static void dpp1_dscl_set_manual_ratio_init( + struct dcn10_dpp *dpp, const struct scaler_data *data) +{ + uint32_t init_frac = 0; + uint32_t init_int = 0; + + REG_SET(SCL_HORZ_FILTER_SCALE_RATIO, 0, + SCL_H_SCALE_RATIO, dal_fixed31_32_u2d19(data->ratios.horz) << 5); + + REG_SET(SCL_VERT_FILTER_SCALE_RATIO, 0, + SCL_V_SCALE_RATIO, dal_fixed31_32_u2d19(data->ratios.vert) << 5); + + REG_SET(SCL_HORZ_FILTER_SCALE_RATIO_C, 0, + SCL_H_SCALE_RATIO_C, dal_fixed31_32_u2d19(data->ratios.horz_c) << 5); + + REG_SET(SCL_VERT_FILTER_SCALE_RATIO_C, 0, + SCL_V_SCALE_RATIO_C, dal_fixed31_32_u2d19(data->ratios.vert_c) << 5); + + /* + * 0.24 format for fraction, first five bits zeroed + */ + init_frac = dal_fixed31_32_u0d19(data->inits.h) << 5; + init_int = dal_fixed31_32_floor(data->inits.h); + REG_SET_2(SCL_HORZ_FILTER_INIT, 0, + SCL_H_INIT_FRAC, init_frac, + SCL_H_INIT_INT, init_int); + + init_frac = dal_fixed31_32_u0d19(data->inits.h_c) << 5; + init_int = dal_fixed31_32_floor(data->inits.h_c); + REG_SET_2(SCL_HORZ_FILTER_INIT_C, 0, + SCL_H_INIT_FRAC_C, init_frac, + SCL_H_INIT_INT_C, init_int); + + init_frac = dal_fixed31_32_u0d19(data->inits.v) << 5; + init_int = dal_fixed31_32_floor(data->inits.v); + REG_SET_2(SCL_VERT_FILTER_INIT, 0, + SCL_V_INIT_FRAC, init_frac, + SCL_V_INIT_INT, init_int); + + init_frac = dal_fixed31_32_u0d19(data->inits.v_bot) << 5; + init_int = dal_fixed31_32_floor(data->inits.v_bot); + REG_SET_2(SCL_VERT_FILTER_INIT_BOT, 0, + SCL_V_INIT_FRAC_BOT, init_frac, + SCL_V_INIT_INT_BOT, init_int); + + init_frac = dal_fixed31_32_u0d19(data->inits.v_c) << 5; + init_int = dal_fixed31_32_floor(data->inits.v_c); + REG_SET_2(SCL_VERT_FILTER_INIT_C, 0, + SCL_V_INIT_FRAC_C, init_frac, + SCL_V_INIT_INT_C, init_int); + + init_frac = dal_fixed31_32_u0d19(data->inits.v_c_bot) << 5; + init_int = dal_fixed31_32_floor(data->inits.v_c_bot); + REG_SET_2(SCL_VERT_FILTER_INIT_BOT_C, 0, + SCL_V_INIT_FRAC_BOT_C, init_frac, + SCL_V_INIT_INT_BOT_C, init_int); +} + + + +static void dpp1_dscl_set_recout( + struct dcn10_dpp *dpp, const struct rect *recout) +{ + REG_SET_2(RECOUT_START, 0, + /* First pixel of RECOUT */ + RECOUT_START_X, recout->x, + /* First line of RECOUT */ + RECOUT_START_Y, recout->y); + + REG_SET_2(RECOUT_SIZE, 0, + /* Number of RECOUT horizontal pixels */ + RECOUT_WIDTH, recout->width, + /* Number of RECOUT vertical lines */ + RECOUT_HEIGHT, recout->height + - dpp->base.ctx->dc->debug.surface_visual_confirm * 4 * + (dpp->base.inst + 1)); +} + +/* Main function to program scaler and line buffer in manual scaling mode */ +void dpp1_dscl_set_scaler_manual_scale( + struct dpp *dpp_base, + const struct scaler_data *scl_data) +{ + enum lb_memory_config lb_config; + struct dcn10_dpp *dpp = TO_DCN10_DPP(dpp_base); + enum dscl_mode_sel dscl_mode = dpp1_dscl_get_dscl_mode( + dpp_base, scl_data, dpp_base->ctx->dc->debug.always_scale); + bool ycbcr = scl_data->format >= PIXEL_FORMAT_VIDEO_BEGIN + && scl_data->format <= PIXEL_FORMAT_VIDEO_END; + + if (memcmp(&dpp->scl_data, scl_data, sizeof(*scl_data)) == 0) + return; + + PERF_TRACE(); + + dpp->scl_data = *scl_data; + + /* Recout */ + dpp1_dscl_set_recout(dpp, &scl_data->recout); + + /* MPC Size */ + REG_SET_2(MPC_SIZE, 0, + /* Number of horizontal pixels of MPC */ + MPC_WIDTH, scl_data->h_active, + /* Number of vertical lines of MPC */ + MPC_HEIGHT, scl_data->v_active); + + /* SCL mode */ + REG_UPDATE(SCL_MODE, DSCL_MODE, dscl_mode); + + if (dscl_mode == DSCL_MODE_DSCL_BYPASS) + return; + + /* LB */ + lb_config = dpp1_dscl_find_lb_memory_config(dpp, scl_data); + dpp1_dscl_set_lb(dpp, &scl_data->lb_params, lb_config); + + if (dscl_mode == DSCL_MODE_SCALING_444_BYPASS) + return; + + /* Autocal off */ + REG_SET_3(DSCL_AUTOCAL, 0, + AUTOCAL_MODE, AUTOCAL_MODE_OFF, + AUTOCAL_NUM_PIPE, 0, + AUTOCAL_PIPE_ID, 0); + + /* Black offsets */ + if (ycbcr) + REG_SET_2(SCL_BLACK_OFFSET, 0, + SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, + SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_CBCR); + else + + REG_SET_2(SCL_BLACK_OFFSET, 0, + SCL_BLACK_OFFSET_RGB_Y, BLACK_OFFSET_RGB_Y, + SCL_BLACK_OFFSET_CBCR, BLACK_OFFSET_RGB_Y); + + /* Manually calculate scale ratio and init values */ + dpp1_dscl_set_manual_ratio_init(dpp, scl_data); + + /* HTaps/VTaps */ + REG_SET_4(SCL_TAP_CONTROL, 0, + SCL_V_NUM_TAPS, scl_data->taps.v_taps - 1, + SCL_H_NUM_TAPS, scl_data->taps.h_taps - 1, + SCL_V_NUM_TAPS_C, scl_data->taps.v_taps_c - 1, + SCL_H_NUM_TAPS_C, scl_data->taps.h_taps_c - 1); + + dpp1_dscl_set_scl_filter(dpp, scl_data, ycbcr); + PERF_TRACE(); +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c new file mode 100644 index 000000000000..eb8317187f30 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -0,0 +1,516 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dcn10_hubp.h" +#include "dcn10_hubbub.h" +#include "reg_helper.h" + +#define CTX \ + hubbub->ctx +#define REG(reg)\ + hubbub->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hubbub->shifts->field_name, hubbub->masks->field_name + +void hubbub1_wm_read_state(struct hubbub *hubbub, + struct dcn_hubbub_wm *wm) +{ + struct dcn_hubbub_wm_set *s; + + memset(wm, 0, sizeof(struct dcn_hubbub_wm)); + + s = &wm->sets[0]; + s->wm_set = 0; + s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A); + s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A); + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { + s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A); + s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A); + } + s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A); + + s = &wm->sets[1]; + s->wm_set = 1; + s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B); + s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B); + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { + s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B); + s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B); + } + s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B); + + s = &wm->sets[2]; + s->wm_set = 2; + s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C); + s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C); + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { + s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C); + s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C); + } + s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C); + + s = &wm->sets[3]; + s->wm_set = 3; + s->data_urgent = REG_READ(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D); + s->pte_meta_urgent = REG_READ(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D); + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { + s->sr_enter = REG_READ(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D); + s->sr_exit = REG_READ(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D); + } + s->dram_clk_chanage = REG_READ(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D); +} + +bool hubbub1_verify_allow_pstate_change_high( + struct hubbub *hubbub) +{ + /* pstate latency is ~20us so if we wait over 40us and pstate allow + * still not asserted, we are probably stuck and going to hang + * + * TODO: Figure out why it takes ~100us on linux + * pstate takes around ~100us on linux. Unknown currently as to + * why it takes that long on linux + */ + static unsigned int pstate_wait_timeout_us = 200; + static unsigned int pstate_wait_expected_timeout_us = 40; + static unsigned int max_sampled_pstate_wait_us; /* data collection */ + static bool forced_pstate_allow; /* help with revert wa */ + + unsigned int debug_index = 0x7; + unsigned int debug_data; + unsigned int i; + + if (forced_pstate_allow) { + /* we hacked to force pstate allow to prevent hang last time + * we verify_allow_pstate_change_high. so disable force + * here so we can check status + */ + REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, + DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0, + DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0); + forced_pstate_allow = false; + } + + /* description "3-0: Pipe0 cursor0 QOS + * 7-4: Pipe1 cursor0 QOS + * 11-8: Pipe2 cursor0 QOS + * 15-12: Pipe3 cursor0 QOS + * 16: Pipe0 Plane0 Allow Pstate Change + * 17: Pipe1 Plane0 Allow Pstate Change + * 18: Pipe2 Plane0 Allow Pstate Change + * 19: Pipe3 Plane0 Allow Pstate Change + * 20: Pipe0 Plane1 Allow Pstate Change + * 21: Pipe1 Plane1 Allow Pstate Change + * 22: Pipe2 Plane1 Allow Pstate Change + * 23: Pipe3 Plane1 Allow Pstate Change + * 24: Pipe0 cursor0 Allow Pstate Change + * 25: Pipe1 cursor0 Allow Pstate Change + * 26: Pipe2 cursor0 Allow Pstate Change + * 27: Pipe3 cursor0 Allow Pstate Change + * 28: WB0 Allow Pstate Change + * 29: WB1 Allow Pstate Change + * 30: Arbiter's allow_pstate_change + * 31: SOC pstate change request + */ + + REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, debug_index); + + for (i = 0; i < pstate_wait_timeout_us; i++) { + debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA); + + if (debug_data & (1 << 30)) { + + if (i > pstate_wait_expected_timeout_us) + dm_logger_write(hubbub->ctx->logger, LOG_WARNING, + "pstate took longer than expected ~%dus\n", + i); + + return true; + } + if (max_sampled_pstate_wait_us < i) + max_sampled_pstate_wait_us = i; + + udelay(1); + } + + /* force pstate allow to prevent system hang + * and break to debugger to investigate + */ + REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, + DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1, + DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1); + forced_pstate_allow = true; + + dm_logger_write(hubbub->ctx->logger, LOG_WARNING, + "pstate TEST_DEBUG_DATA: 0x%X\n", + debug_data); + + return false; +} + +static uint32_t convert_and_clamp( + uint32_t wm_ns, + uint32_t refclk_mhz, + uint32_t clamp_value) +{ + uint32_t ret_val = 0; + ret_val = wm_ns * refclk_mhz; + ret_val /= 1000; + + if (ret_val > clamp_value) + ret_val = clamp_value; + + return ret_val; +} + + +void hubbub1_program_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz) +{ + uint32_t force_en = hubbub->ctx->dc->debug.disable_stutter ? 1 : 0; + /* + * Need to clamp to max of the register values (i.e. no wrap) + * for dcn1, all wm registers are 21-bit wide + */ + uint32_t prog_wm_value; + + REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, + DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 0); + + /* Repeat for water mark set A, B, C and D. */ + /* clock state A */ + prog_wm_value = convert_and_clamp(watermarks->a.urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A, prog_wm_value); + + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.urgent_ns, prog_wm_value); + + prog_wm_value = convert_and_clamp(watermarks->a.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "PTE_META_URGENCY_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.pte_meta_urgent_ns, prog_wm_value); + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A)) { + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "SR_ENTER_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + + + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "SR_EXIT_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->a.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + prog_wm_value = convert_and_clamp( + watermarks->a.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "DRAM_CLK_CHANGE_WATERMARK_A calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->a.cstate_pstate.pstate_change_ns, prog_wm_value); + + + /* clock state B */ + prog_wm_value = convert_and_clamp( + watermarks->b.urgent_ns, refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.urgent_ns, prog_wm_value); + + + prog_wm_value = convert_and_clamp( + watermarks->b.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "PTE_META_URGENCY_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.pte_meta_urgent_ns, prog_wm_value); + + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B)) { + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "SR_ENTER_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + + + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "SR_EXIT_WATERMARK_B calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + prog_wm_value = convert_and_clamp( + watermarks->b.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "DRAM_CLK_CHANGE_WATERMARK_B calculated =%d\n\n" + "HW register value = 0x%x\n", + watermarks->b.cstate_pstate.pstate_change_ns, prog_wm_value); + + /* clock state C */ + prog_wm_value = convert_and_clamp( + watermarks->c.urgent_ns, refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.urgent_ns, prog_wm_value); + + + prog_wm_value = convert_and_clamp( + watermarks->c.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "PTE_META_URGENCY_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.pte_meta_urgent_ns, prog_wm_value); + + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C)) { + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "SR_ENTER_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + + + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "SR_EXIT_WATERMARK_C calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + prog_wm_value = convert_and_clamp( + watermarks->c.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "DRAM_CLK_CHANGE_WATERMARK_C calculated =%d\n\n" + "HW register value = 0x%x\n", + watermarks->c.cstate_pstate.pstate_change_ns, prog_wm_value); + + /* clock state D */ + prog_wm_value = convert_and_clamp( + watermarks->d.urgent_ns, refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.urgent_ns, prog_wm_value); + + prog_wm_value = convert_and_clamp( + watermarks->d.pte_meta_urgent_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "PTE_META_URGENCY_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.pte_meta_urgent_ns, prog_wm_value); + + + if (REG(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D)) { + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "SR_ENTER_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_enter_plus_exit_ns, prog_wm_value); + + + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.cstate_exit_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "SR_EXIT_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n", + watermarks->d.cstate_pstate.cstate_exit_ns, prog_wm_value); + } + + + prog_wm_value = convert_and_clamp( + watermarks->d.cstate_pstate.pstate_change_ns, + refclk_mhz, 0x1fffff); + REG_WRITE(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D, prog_wm_value); + dm_logger_write(hubbub->ctx->logger, LOG_BANDWIDTH_CALCS, + "DRAM_CLK_CHANGE_WATERMARK_D calculated =%d\n" + "HW register value = 0x%x\n\n", + watermarks->d.cstate_pstate.pstate_change_ns, prog_wm_value); + + REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, + DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); + + REG_UPDATE(DCHUBBUB_ARB_SAT_LEVEL, + DCHUBBUB_ARB_SAT_LEVEL, 60 * refclk_mhz); + REG_UPDATE(DCHUBBUB_ARB_DF_REQ_OUTSTAND, + DCHUBBUB_ARB_MIN_REQ_OUTSTAND, 68); + + REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL, + DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, 0, + DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, force_en); + +#if 0 + REG_UPDATE_2(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, + DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, 1, + DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, 1); +#endif +} + +void hubbub1_update_dchub( + struct hubbub *hubbub, + struct dchub_init_data *dh_data) +{ + /* TODO: port code from dal2 */ + switch (dh_data->fb_mode) { + case FRAME_BUFFER_MODE_ZFB_ONLY: + /*For ZFB case need to put DCHUB FB BASE and TOP upside down to indicate ZFB mode*/ + REG_UPDATE(DCHUBBUB_SDPIF_FB_TOP, + SDPIF_FB_TOP, 0); + + REG_UPDATE(DCHUBBUB_SDPIF_FB_BASE, + SDPIF_FB_BASE, 0x0FFFF); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, + SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, + SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, + SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + + dh_data->zfb_size_in_byte - 1) >> 22); + break; + case FRAME_BUFFER_MODE_MIXED_ZFB_AND_LOCAL: + /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, + SDPIF_AGP_BASE, dh_data->zfb_phys_addr_base >> 22); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, + SDPIF_AGP_BOT, dh_data->zfb_mc_base_addr >> 22); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, + SDPIF_AGP_TOP, (dh_data->zfb_mc_base_addr + + dh_data->zfb_size_in_byte - 1) >> 22); + break; + case FRAME_BUFFER_MODE_LOCAL_ONLY: + /*Should not touch FB LOCATION (done by VBIOS on AsicInit table)*/ + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BASE, + SDPIF_AGP_BASE, 0); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_BOT, + SDPIF_AGP_BOT, 0X03FFFF); + + REG_UPDATE(DCHUBBUB_SDPIF_AGP_TOP, + SDPIF_AGP_TOP, 0); + break; + default: + break; + } + + dh_data->dchub_initialzied = true; + dh_data->dchub_info_valid = false; +} + +void hubbub1_toggle_watermark_change_req(struct hubbub *hubbub) +{ + uint32_t watermark_change_req; + + REG_GET(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, + DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, &watermark_change_req); + + if (watermark_change_req) + watermark_change_req = 0; + else + watermark_change_req = 1; + + REG_UPDATE(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, + DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, watermark_change_req); +} + +static const struct hubbub_funcs hubbub1_funcs = { + .update_dchub = hubbub1_update_dchub +}; + +void hubbub1_construct(struct hubbub *hubbub, + struct dc_context *ctx, + const struct dcn_hubbub_registers *hubbub_regs, + const struct dcn_hubbub_shift *hubbub_shift, + const struct dcn_hubbub_mask *hubbub_mask) +{ + hubbub->ctx = ctx; + + hubbub->funcs = &hubbub1_funcs; + + hubbub->regs = hubbub_regs; + hubbub->shifts = hubbub_shift; + hubbub->masks = hubbub_mask; + +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h new file mode 100644 index 000000000000..d5c97844312f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.h @@ -0,0 +1,214 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HUBBUB_DCN10_H__ +#define __DC_HUBBUB_DCN10_H__ + +#include "core_types.h" + +#define HUBHUB_REG_LIST_DCN()\ + SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A),\ + SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A),\ + SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A),\ + SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B),\ + SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B),\ + SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B),\ + SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C),\ + SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C),\ + SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C),\ + SR(DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D),\ + SR(DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D),\ + SR(DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D),\ + SR(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL),\ + SR(DCHUBBUB_ARB_DRAM_STATE_CNTL),\ + SR(DCHUBBUB_ARB_SAT_LEVEL),\ + SR(DCHUBBUB_ARB_DF_REQ_OUTSTAND),\ + SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \ + SR(DCHUBBUB_TEST_DEBUG_INDEX), \ + SR(DCHUBBUB_TEST_DEBUG_DATA) + +#define HUBBUB_SR_WATERMARK_REG_LIST()\ + SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A),\ + SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A),\ + SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B),\ + SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B),\ + SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C),\ + SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C),\ + SR(DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D),\ + SR(DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D) + +#define HUBBUB_REG_LIST_DCN10(id)\ + HUBHUB_REG_LIST_DCN(), \ + HUBBUB_SR_WATERMARK_REG_LIST(), \ + SR(DCHUBBUB_SDPIF_FB_TOP),\ + SR(DCHUBBUB_SDPIF_FB_BASE),\ + SR(DCHUBBUB_SDPIF_FB_OFFSET),\ + SR(DCHUBBUB_SDPIF_AGP_BASE),\ + SR(DCHUBBUB_SDPIF_AGP_BOT),\ + SR(DCHUBBUB_SDPIF_AGP_TOP) + +struct dcn_hubbub_registers { + uint32_t DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_A; + uint32_t DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_A; + uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_A; + uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_A; + uint32_t DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_A; + uint32_t DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_B; + uint32_t DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_B; + uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_B; + uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_B; + uint32_t DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_B; + uint32_t DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_C; + uint32_t DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_C; + uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_C; + uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_C; + uint32_t DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_C; + uint32_t DCHUBBUB_ARB_DATA_URGENCY_WATERMARK_D; + uint32_t DCHUBBUB_ARB_PTE_META_URGENCY_WATERMARK_D; + uint32_t DCHUBBUB_ARB_ALLOW_SR_ENTER_WATERMARK_D; + uint32_t DCHUBBUB_ARB_ALLOW_SR_EXIT_WATERMARK_D; + uint32_t DCHUBBUB_ARB_ALLOW_DRAM_CLK_CHANGE_WATERMARK_D; + uint32_t DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL; + uint32_t DCHUBBUB_ARB_SAT_LEVEL; + uint32_t DCHUBBUB_ARB_DF_REQ_OUTSTAND; + uint32_t DCHUBBUB_GLOBAL_TIMER_CNTL; + uint32_t DCHUBBUB_ARB_DRAM_STATE_CNTL; + uint32_t DCHUBBUB_TEST_DEBUG_INDEX; + uint32_t DCHUBBUB_TEST_DEBUG_DATA; + uint32_t DCHUBBUB_SDPIF_FB_TOP; + uint32_t DCHUBBUB_SDPIF_FB_BASE; + uint32_t DCHUBBUB_SDPIF_FB_OFFSET; + uint32_t DCHUBBUB_SDPIF_AGP_BASE; + uint32_t DCHUBBUB_SDPIF_AGP_BOT; + uint32_t DCHUBBUB_SDPIF_AGP_TOP; + uint32_t DCHUBBUB_CRC_CTRL; +}; + +/* set field name */ +#define HUBBUB_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + + +#define HUBBUB_MASK_SH_LIST_DCN(mask_sh)\ + HUBBUB_SF(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_WATERMARK_CHANGE_CNTL, DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DRAM_STATE_CNTL, DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_SAT_LEVEL, DCHUBBUB_ARB_SAT_LEVEL, mask_sh), \ + HUBBUB_SF(DCHUBBUB_ARB_DF_REQ_OUTSTAND, DCHUBBUB_ARB_MIN_REQ_OUTSTAND, mask_sh) + +#define HUBBUB_MASK_SH_LIST_DCN10(mask_sh)\ + HUBBUB_MASK_SH_LIST_DCN(mask_sh), \ + HUBBUB_SF(DCHUBBUB_SDPIF_FB_TOP, SDPIF_FB_TOP, mask_sh), \ + HUBBUB_SF(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, mask_sh), \ + HUBBUB_SF(DCHUBBUB_SDPIF_AGP_BASE, SDPIF_AGP_BASE, mask_sh), \ + HUBBUB_SF(DCHUBBUB_SDPIF_AGP_BOT, SDPIF_AGP_BOT, mask_sh), \ + HUBBUB_SF(DCHUBBUB_SDPIF_AGP_TOP, SDPIF_AGP_TOP, mask_sh) + +#define DCN_HUBBUB_REG_FIELD_LIST(type) \ + type DCHUBBUB_GLOBAL_TIMER_ENABLE; \ + type DCHUBBUB_ARB_WATERMARK_CHANGE_REQUEST;\ + type DCHUBBUB_ARB_WATERMARK_CHANGE_DONE_INTERRUPT_DISABLE;\ + type DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_VALUE;\ + type DCHUBBUB_ARB_ALLOW_SELF_REFRESH_FORCE_ENABLE;\ + type DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE;\ + type DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE;\ + type DCHUBBUB_ARB_SAT_LEVEL;\ + type DCHUBBUB_ARB_MIN_REQ_OUTSTAND;\ + type DCHUBBUB_GLOBAL_TIMER_REFDIV;\ + type SDPIF_FB_TOP;\ + type SDPIF_FB_BASE;\ + type SDPIF_FB_OFFSET;\ + type SDPIF_AGP_BASE;\ + type SDPIF_AGP_BOT;\ + type SDPIF_AGP_TOP + + +struct dcn_hubbub_shift { + DCN_HUBBUB_REG_FIELD_LIST(uint8_t); +}; + +struct dcn_hubbub_mask { + DCN_HUBBUB_REG_FIELD_LIST(uint32_t); +}; + +struct dc; + +struct dcn_hubbub_wm_set { + uint32_t wm_set; + uint32_t data_urgent; + uint32_t pte_meta_urgent; + uint32_t sr_enter; + uint32_t sr_exit; + uint32_t dram_clk_chanage; +}; + +struct dcn_hubbub_wm { + struct dcn_hubbub_wm_set sets[4]; +}; + +struct hubbub_funcs { + void (*update_dchub)( + struct hubbub *hubbub, + struct dchub_init_data *dh_data); +}; + +struct hubbub { + const struct hubbub_funcs *funcs; + struct dc_context *ctx; + const struct dcn_hubbub_registers *regs; + const struct dcn_hubbub_shift *shifts; + const struct dcn_hubbub_mask *masks; +}; + +void hubbub1_update_dchub( + struct hubbub *hubbub, + struct dchub_init_data *dh_data); + +bool hubbub1_verify_allow_pstate_change_high( + struct hubbub *hubbub); + +void hubbub1_program_watermarks( + struct hubbub *hubbub, + struct dcn_watermark_set *watermarks, + unsigned int refclk_mhz); + +void hubbub1_toggle_watermark_change_req( + struct hubbub *hubbub); + +void hubbub1_wm_read_state(struct hubbub *hubbub, + struct dcn_hubbub_wm *wm); + +void hubbub1_construct(struct hubbub *hubbub, + struct dc_context *ctx, + const struct dcn_hubbub_registers *hubbub_regs, + const struct dcn_hubbub_shift *hubbub_shift, + const struct dcn_hubbub_mask *hubbub_mask); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c new file mode 100644 index 000000000000..585b33384002 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c @@ -0,0 +1,952 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ +#include "dm_services.h" +#include "dce_calcs.h" +#include "reg_helper.h" +#include "basics/conversion.h" +#include "dcn10_hubp.h" + +#define REG(reg)\ + hubp1->hubp_regs->reg + +#define CTX \ + hubp1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + hubp1->hubp_shift->field_name, hubp1->hubp_mask->field_name + +void hubp1_set_blank(struct hubp *hubp, bool blank) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + uint32_t blank_en = blank ? 1 : 0; + + REG_UPDATE_2(DCHUBP_CNTL, + HUBP_BLANK_EN, blank_en, + HUBP_TTU_DISABLE, blank_en); + + if (blank) { + uint32_t reg_val = REG_READ(DCHUBP_CNTL); + + if (reg_val) { + /* init sequence workaround: in case HUBP is + * power gated, this wait would timeout. + * + * we just wrote reg_val to non-0, if it stay 0 + * it means HUBP is gated + */ + REG_WAIT(DCHUBP_CNTL, + HUBP_NO_OUTSTANDING_REQ, 1, + 1, 200); + } + + hubp->mpcc_id = 0xf; + hubp->opp_id = 0xf; + } +} + +static void hubp1_disconnect(struct hubp *hubp) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_UPDATE(DCHUBP_CNTL, + HUBP_TTU_DISABLE, 1); +} + +static void hubp1_set_hubp_blank_en(struct hubp *hubp, bool blank) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + uint32_t blank_en = blank ? 1 : 0; + + REG_UPDATE(DCHUBP_CNTL, HUBP_BLANK_EN, blank_en); +} + +static void hubp1_vready_workaround(struct hubp *hubp, + struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest) +{ + uint32_t value = 0; + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + /* set HBUBREQ_DEBUG_DB[12] = 1 */ + value = REG_READ(HUBPREQ_DEBUG_DB); + + /* hack mode disable */ + value |= 0x100; + value &= ~0x1000; + + if ((pipe_dest->vstartup_start - 2*(pipe_dest->vready_offset+pipe_dest->vupdate_width + + pipe_dest->vupdate_offset) / pipe_dest->htotal) <= pipe_dest->vblank_end) { + /* if (eco_fix_needed(otg_global_sync_timing) + * set HBUBREQ_DEBUG_DB[12] = 1 */ + value |= 0x1000; + } + + REG_WRITE(HUBPREQ_DEBUG_DB, value); +} + +void hubp1_program_tiling( + struct hubp *hubp, + const union dc_tiling_info *info, + const enum surface_pixel_format pixel_format) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_UPDATE_6(DCSURF_ADDR_CONFIG, + NUM_PIPES, log_2(info->gfx9.num_pipes), + NUM_BANKS, log_2(info->gfx9.num_banks), + PIPE_INTERLEAVE, info->gfx9.pipe_interleave, + NUM_SE, log_2(info->gfx9.num_shader_engines), + NUM_RB_PER_SE, log_2(info->gfx9.num_rb_per_se), + MAX_COMPRESSED_FRAGS, log_2(info->gfx9.max_compressed_frags)); + + REG_UPDATE_4(DCSURF_TILING_CONFIG, + SW_MODE, info->gfx9.swizzle, + META_LINEAR, info->gfx9.meta_linear, + RB_ALIGNED, info->gfx9.rb_aligned, + PIPE_ALIGNED, info->gfx9.pipe_aligned); +} + +void hubp1_program_size_and_rotation( + struct hubp *hubp, + enum dc_rotation_angle rotation, + enum surface_pixel_format format, + const union plane_size *plane_size, + struct dc_plane_dcc_param *dcc, + bool horizontal_mirror) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + uint32_t pitch, meta_pitch, pitch_c, meta_pitch_c, mirror; + + /* Program data and meta surface pitch (calculation from addrlib) + * 444 or 420 luma + */ + if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) { + pitch = plane_size->video.luma_pitch - 1; + meta_pitch = dcc->video.meta_pitch_l - 1; + pitch_c = plane_size->video.chroma_pitch - 1; + meta_pitch_c = dcc->video.meta_pitch_c - 1; + } else { + pitch = plane_size->grph.surface_pitch - 1; + meta_pitch = dcc->grph.meta_pitch - 1; + pitch_c = 0; + meta_pitch_c = 0; + } + + if (!dcc->enable) { + meta_pitch = 0; + meta_pitch_c = 0; + } + + REG_UPDATE_2(DCSURF_SURFACE_PITCH, + PITCH, pitch, META_PITCH, meta_pitch); + + if (format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) + REG_UPDATE_2(DCSURF_SURFACE_PITCH_C, + PITCH_C, pitch_c, META_PITCH_C, meta_pitch_c); + + if (horizontal_mirror) + mirror = 1; + else + mirror = 0; + + + /* Program rotation angle and horz mirror - no mirror */ + if (rotation == ROTATION_ANGLE_0) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 0, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_90) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 1, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_180) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 2, + H_MIRROR_EN, mirror); + else if (rotation == ROTATION_ANGLE_270) + REG_UPDATE_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, 3, + H_MIRROR_EN, mirror); +} + +void hubp1_program_pixel_format( + struct hubp *hubp, + enum surface_pixel_format format) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + uint32_t red_bar = 3; + uint32_t blue_bar = 2; + + /* swap for ABGR format */ + if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR8888 + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS + || format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) { + red_bar = 2; + blue_bar = 3; + } + + REG_UPDATE_2(HUBPRET_CONTROL, + CROSSBAR_SRC_CB_B, blue_bar, + CROSSBAR_SRC_CR_R, red_bar); + + /* Mapping is same as ipp programming (cnvc) */ + + switch (format) { + case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 1); + break; + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 3); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 8); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 10); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 22); + break; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:/*we use crossbar already*/ + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 24); + break; + + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 65); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 64); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 67); + break; + case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb: + REG_UPDATE(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, 66); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + /* don't see the need of program the xbar in DCN 1.0 */ +} + +bool hubp1_program_surface_flip_and_addr( + struct hubp *hubp, + const struct dc_plane_address *address, + bool flip_immediate) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + /* program flip type */ + REG_SET(DCSURF_FLIP_CONTROL, 0, + SURFACE_FLIP_TYPE, flip_immediate); + + /* HW automatically latch rest of address register on write to + * DCSURF_PRIMARY_SURFACE_ADDRESS if SURFACE_UPDATE_LOCK is not used + * + * program high first and then the low addr, order matters! + */ + switch (address->type) { + case PLN_ADDR_TYPE_GRAPHICS: + /* DCN1.0 does not support const color + * TODO: program DCHUBBUB_RET_PATH_DCC_CFGx_0/1 + * base on address->grph.dcc_const_color + * x = 0, 2, 4, 6 for pipe 0, 1, 2, 3 for rgb and luma + * x = 1, 3, 5, 7 for pipe 0, 1, 2, 3 for chroma + */ + + if (address->grph.addr.quad_part == 0) + break; + + REG_UPDATE(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface); + + if (address->grph.meta_addr.quad_part != 0) { + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_META_SURFACE_ADDRESS_HIGH, + address->grph.meta_addr.high_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS, 0, + PRIMARY_META_SURFACE_ADDRESS, + address->grph.meta_addr.low_part); + } + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_SURFACE_ADDRESS_HIGH, + address->grph.addr.high_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0, + PRIMARY_SURFACE_ADDRESS, + address->grph.addr.low_part); + break; + case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE: + if (address->video_progressive.luma_addr.quad_part == 0 + || address->video_progressive.chroma_addr.quad_part == 0) + break; + + REG_UPDATE(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface); + + if (address->video_progressive.luma_meta_addr.quad_part != 0) { + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, 0, + PRIMARY_META_SURFACE_ADDRESS_HIGH_C, + address->video_progressive.chroma_meta_addr.high_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_C, 0, + PRIMARY_META_SURFACE_ADDRESS_C, + address->video_progressive.chroma_meta_addr.low_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_META_SURFACE_ADDRESS_HIGH, + address->video_progressive.luma_meta_addr.high_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS, 0, + PRIMARY_META_SURFACE_ADDRESS, + address->video_progressive.luma_meta_addr.low_part); + } + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, 0, + PRIMARY_SURFACE_ADDRESS_HIGH_C, + address->video_progressive.chroma_addr.high_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_C, 0, + PRIMARY_SURFACE_ADDRESS_C, + address->video_progressive.chroma_addr.low_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_SURFACE_ADDRESS_HIGH, + address->video_progressive.luma_addr.high_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0, + PRIMARY_SURFACE_ADDRESS, + address->video_progressive.luma_addr.low_part); + break; + case PLN_ADDR_TYPE_GRPH_STEREO: + if (address->grph_stereo.left_addr.quad_part == 0) + break; + if (address->grph_stereo.right_addr.quad_part == 0) + break; + + REG_UPDATE(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_TMZ, address->tmz_surface); + + if (address->grph_stereo.right_meta_addr.quad_part != 0) { + + REG_SET(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH, 0, + SECONDARY_META_SURFACE_ADDRESS_HIGH, + address->grph_stereo.right_meta_addr.high_part); + + REG_SET(DCSURF_SECONDARY_META_SURFACE_ADDRESS, 0, + SECONDARY_META_SURFACE_ADDRESS, + address->grph_stereo.right_meta_addr.low_part); + } + if (address->grph_stereo.left_meta_addr.quad_part != 0) { + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_META_SURFACE_ADDRESS_HIGH, + address->grph_stereo.left_meta_addr.high_part); + + REG_SET(DCSURF_PRIMARY_META_SURFACE_ADDRESS, 0, + PRIMARY_META_SURFACE_ADDRESS, + address->grph_stereo.left_meta_addr.low_part); + } + + REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, 0, + SECONDARY_SURFACE_ADDRESS_HIGH, + address->grph_stereo.right_addr.high_part); + + REG_SET(DCSURF_SECONDARY_SURFACE_ADDRESS, 0, + SECONDARY_SURFACE_ADDRESS, + address->grph_stereo.right_addr.low_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, 0, + PRIMARY_SURFACE_ADDRESS_HIGH, + address->grph_stereo.left_addr.high_part); + + REG_SET(DCSURF_PRIMARY_SURFACE_ADDRESS, 0, + PRIMARY_SURFACE_ADDRESS, + address->grph_stereo.left_addr.low_part); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } + + hubp->request_address = *address; + + if (flip_immediate) + hubp->current_address = *address; + + return true; +} + +void hubp1_dcc_control(struct hubp *hubp, bool enable, + bool independent_64b_blks) +{ + uint32_t dcc_en = enable ? 1 : 0; + uint32_t dcc_ind_64b_blk = independent_64b_blks ? 1 : 0; + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_UPDATE_2(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_DCC_EN, dcc_en, + PRIMARY_SURFACE_DCC_IND_64B_BLK, dcc_ind_64b_blk); +} + +void hubp1_program_surface_config( + struct hubp *hubp, + enum surface_pixel_format format, + union dc_tiling_info *tiling_info, + union plane_size *plane_size, + enum dc_rotation_angle rotation, + struct dc_plane_dcc_param *dcc, + bool horizontal_mirror) +{ + hubp1_dcc_control(hubp, dcc->enable, dcc->grph.independent_64b_blks); + hubp1_program_tiling(hubp, tiling_info, format); + hubp1_program_size_and_rotation( + hubp, rotation, format, plane_size, dcc, horizontal_mirror); + hubp1_program_pixel_format(hubp, format); +} + +void hubp1_program_requestor( + struct hubp *hubp, + struct _vcs_dpi_display_rq_regs_st *rq_regs) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_UPDATE(HUBPRET_CONTROL, + DET_BUF_PLANE1_BASE_ADDRESS, rq_regs->plane1_base_address); + REG_SET_4(DCN_EXPANSION_MODE, 0, + DRQ_EXPANSION_MODE, rq_regs->drq_expansion_mode, + PRQ_EXPANSION_MODE, rq_regs->prq_expansion_mode, + MRQ_EXPANSION_MODE, rq_regs->mrq_expansion_mode, + CRQ_EXPANSION_MODE, rq_regs->crq_expansion_mode); + REG_SET_8(DCHUBP_REQ_SIZE_CONFIG, 0, + CHUNK_SIZE, rq_regs->rq_regs_l.chunk_size, + MIN_CHUNK_SIZE, rq_regs->rq_regs_l.min_chunk_size, + META_CHUNK_SIZE, rq_regs->rq_regs_l.meta_chunk_size, + MIN_META_CHUNK_SIZE, rq_regs->rq_regs_l.min_meta_chunk_size, + DPTE_GROUP_SIZE, rq_regs->rq_regs_l.dpte_group_size, + MPTE_GROUP_SIZE, rq_regs->rq_regs_l.mpte_group_size, + SWATH_HEIGHT, rq_regs->rq_regs_l.swath_height, + PTE_ROW_HEIGHT_LINEAR, rq_regs->rq_regs_l.pte_row_height_linear); + REG_SET_8(DCHUBP_REQ_SIZE_CONFIG_C, 0, + CHUNK_SIZE_C, rq_regs->rq_regs_c.chunk_size, + MIN_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_chunk_size, + META_CHUNK_SIZE_C, rq_regs->rq_regs_c.meta_chunk_size, + MIN_META_CHUNK_SIZE_C, rq_regs->rq_regs_c.min_meta_chunk_size, + DPTE_GROUP_SIZE_C, rq_regs->rq_regs_c.dpte_group_size, + MPTE_GROUP_SIZE_C, rq_regs->rq_regs_c.mpte_group_size, + SWATH_HEIGHT_C, rq_regs->rq_regs_c.swath_height, + PTE_ROW_HEIGHT_LINEAR_C, rq_regs->rq_regs_c.pte_row_height_linear); +} + + +void hubp1_program_deadline( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + /* DLG - Per hubp */ + REG_SET_2(BLANK_OFFSET_0, 0, + REFCYC_H_BLANK_END, dlg_attr->refcyc_h_blank_end, + DLG_V_BLANK_END, dlg_attr->dlg_vblank_end); + + REG_SET(BLANK_OFFSET_1, 0, + MIN_DST_Y_NEXT_START, dlg_attr->min_dst_y_next_start); + + REG_SET(DST_DIMENSIONS, 0, + REFCYC_PER_HTOTAL, dlg_attr->refcyc_per_htotal); + + REG_SET_2(DST_AFTER_SCALER, 0, + REFCYC_X_AFTER_SCALER, dlg_attr->refcyc_x_after_scaler, + DST_Y_AFTER_SCALER, dlg_attr->dst_y_after_scaler); + + if (REG(PREFETCH_SETTINS)) + REG_SET_2(PREFETCH_SETTINS, 0, + DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, dlg_attr->vratio_prefetch); + else + REG_SET_2(PREFETCH_SETTINGS, 0, + DST_Y_PREFETCH, dlg_attr->dst_y_prefetch, + VRATIO_PREFETCH, dlg_attr->vratio_prefetch); + + REG_SET_2(VBLANK_PARAMETERS_0, 0, + DST_Y_PER_VM_VBLANK, dlg_attr->dst_y_per_vm_vblank, + DST_Y_PER_ROW_VBLANK, dlg_attr->dst_y_per_row_vblank); + + REG_SET(REF_FREQ_TO_PIX_FREQ, 0, + REF_FREQ_TO_PIX_FREQ, dlg_attr->ref_freq_to_pix_freq); + + /* DLG - Per luma/chroma */ + REG_SET(VBLANK_PARAMETERS_1, 0, + REFCYC_PER_PTE_GROUP_VBLANK_L, dlg_attr->refcyc_per_pte_group_vblank_l); + + REG_SET(VBLANK_PARAMETERS_3, 0, + REFCYC_PER_META_CHUNK_VBLANK_L, dlg_attr->refcyc_per_meta_chunk_vblank_l); + + REG_SET(NOM_PARAMETERS_0, 0, + DST_Y_PER_PTE_ROW_NOM_L, dlg_attr->dst_y_per_pte_row_nom_l); + + REG_SET(NOM_PARAMETERS_1, 0, + REFCYC_PER_PTE_GROUP_NOM_L, dlg_attr->refcyc_per_pte_group_nom_l); + + REG_SET(NOM_PARAMETERS_4, 0, + DST_Y_PER_META_ROW_NOM_L, dlg_attr->dst_y_per_meta_row_nom_l); + + REG_SET(NOM_PARAMETERS_5, 0, + REFCYC_PER_META_CHUNK_NOM_L, dlg_attr->refcyc_per_meta_chunk_nom_l); + + REG_SET_2(PER_LINE_DELIVERY_PRE, 0, + REFCYC_PER_LINE_DELIVERY_PRE_L, dlg_attr->refcyc_per_line_delivery_pre_l, + REFCYC_PER_LINE_DELIVERY_PRE_C, dlg_attr->refcyc_per_line_delivery_pre_c); + + REG_SET_2(PER_LINE_DELIVERY, 0, + REFCYC_PER_LINE_DELIVERY_L, dlg_attr->refcyc_per_line_delivery_l, + REFCYC_PER_LINE_DELIVERY_C, dlg_attr->refcyc_per_line_delivery_c); + + if (REG(PREFETCH_SETTINS_C)) + REG_SET(PREFETCH_SETTINS_C, 0, + VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); + else + REG_SET(PREFETCH_SETTINGS_C, 0, + VRATIO_PREFETCH_C, dlg_attr->vratio_prefetch_c); + + REG_SET(VBLANK_PARAMETERS_2, 0, + REFCYC_PER_PTE_GROUP_VBLANK_C, dlg_attr->refcyc_per_pte_group_vblank_c); + + REG_SET(VBLANK_PARAMETERS_4, 0, + REFCYC_PER_META_CHUNK_VBLANK_C, dlg_attr->refcyc_per_meta_chunk_vblank_c); + + REG_SET(NOM_PARAMETERS_2, 0, + DST_Y_PER_PTE_ROW_NOM_C, dlg_attr->dst_y_per_pte_row_nom_c); + + REG_SET(NOM_PARAMETERS_3, 0, + REFCYC_PER_PTE_GROUP_NOM_C, dlg_attr->refcyc_per_pte_group_nom_c); + + REG_SET(NOM_PARAMETERS_6, 0, + DST_Y_PER_META_ROW_NOM_C, dlg_attr->dst_y_per_meta_row_nom_c); + + REG_SET(NOM_PARAMETERS_7, 0, + REFCYC_PER_META_CHUNK_NOM_C, dlg_attr->refcyc_per_meta_chunk_nom_c); + + /* TTU - per hubp */ + REG_SET_2(DCN_TTU_QOS_WM, 0, + QoS_LEVEL_LOW_WM, ttu_attr->qos_level_low_wm, + QoS_LEVEL_HIGH_WM, ttu_attr->qos_level_high_wm); + + REG_SET_2(DCN_GLOBAL_TTU_CNTL, 0, + MIN_TTU_VBLANK, ttu_attr->min_ttu_vblank, + QoS_LEVEL_FLIP, ttu_attr->qos_level_flip); + + /* TTU - per luma/chroma */ + /* Assumed surf0 is luma and 1 is chroma */ + + REG_SET_3(DCN_SURF0_TTU_CNTL0, 0, + REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_l, + QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_l, + QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_l); + + REG_SET(DCN_SURF0_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, + ttu_attr->refcyc_per_req_delivery_pre_l); + + REG_SET_3(DCN_SURF1_TTU_CNTL0, 0, + REFCYC_PER_REQ_DELIVERY, ttu_attr->refcyc_per_req_delivery_c, + QoS_LEVEL_FIXED, ttu_attr->qos_level_fixed_c, + QoS_RAMP_DISABLE, ttu_attr->qos_ramp_disable_c); + + REG_SET(DCN_SURF1_TTU_CNTL1, 0, + REFCYC_PER_REQ_DELIVERY_PRE, + ttu_attr->refcyc_per_req_delivery_pre_c); +} + +static void hubp1_setup( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr, + struct _vcs_dpi_display_rq_regs_st *rq_regs, + struct _vcs_dpi_display_pipe_dest_params_st *pipe_dest) +{ + /* otg is locked when this func is called. Register are double buffered. + * disable the requestors is not needed + */ + hubp1_program_requestor(hubp, rq_regs); + hubp1_program_deadline(hubp, dlg_attr, ttu_attr); + hubp1_vready_workaround(hubp, pipe_dest); +} + +bool hubp1_is_flip_pending(struct hubp *hubp) +{ + uint32_t flip_pending = 0; + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + struct dc_plane_address earliest_inuse_address; + + REG_GET(DCSURF_FLIP_CONTROL, + SURFACE_FLIP_PENDING, &flip_pending); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE, + SURFACE_EARLIEST_INUSE_ADDRESS, &earliest_inuse_address.grph.addr.low_part); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, + SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, &earliest_inuse_address.grph.addr.high_part); + + if (flip_pending) + return true; + + if (earliest_inuse_address.grph.addr.quad_part != hubp->request_address.grph.addr.quad_part) + return true; + + hubp->current_address = hubp->request_address; + return false; +} + +uint32_t aperture_default_system = 1; +uint32_t context0_default_system; /* = 0;*/ + +static void hubp1_set_vm_system_aperture_settings(struct hubp *hubp, + struct vm_system_aperture_param *apt) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + PHYSICAL_ADDRESS_LOC mc_vm_apt_default; + PHYSICAL_ADDRESS_LOC mc_vm_apt_low; + PHYSICAL_ADDRESS_LOC mc_vm_apt_high; + + mc_vm_apt_default.quad_part = apt->sys_default.quad_part >> 12; + mc_vm_apt_low.quad_part = apt->sys_low.quad_part >> 12; + mc_vm_apt_high.quad_part = apt->sys_high.quad_part >> 12; + + REG_SET_2(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, 0, + MC_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM, aperture_default_system, /* 1 = system physical memory */ + MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, mc_vm_apt_default.high_part); + REG_SET(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, 0, + MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, mc_vm_apt_default.low_part); + + REG_SET(DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, 0, + MC_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, mc_vm_apt_low.high_part); + REG_SET(DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, 0, + MC_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, mc_vm_apt_low.low_part); + + REG_SET(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, 0, + MC_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, mc_vm_apt_high.high_part); + REG_SET(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, 0, + MC_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, mc_vm_apt_high.low_part); +} + +static void hubp1_set_vm_context0_settings(struct hubp *hubp, + const struct vm_context0_param *vm0) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + /* pte base */ + REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB, 0, + VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB, vm0->pte_base.high_part); + REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB, 0, + VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB, vm0->pte_base.low_part); + + /* pte start */ + REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB, 0, + VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB, vm0->pte_start.high_part); + REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB, 0, + VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB, vm0->pte_start.low_part); + + /* pte end */ + REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB, 0, + VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB, vm0->pte_end.high_part); + REG_SET(DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB, 0, + VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB, vm0->pte_end.low_part); + + /* fault handling */ + REG_SET_2(DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB, 0, + VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB, vm0->fault_default.high_part, + VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_SYSTEM, context0_default_system); + REG_SET(DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB, 0, + VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB, vm0->fault_default.low_part); + + /* control: enable VM PTE*/ + REG_SET_2(DCN_VM_MX_L1_TLB_CNTL, 0, + ENABLE_L1_TLB, 1, + SYSTEM_ACCESS_MODE, 3); +} + +void min_set_viewport( + struct hubp *hubp, + const struct rect *viewport, + const struct rect *viewport_c) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + + REG_SET_2(DCSURF_PRI_VIEWPORT_DIMENSION, 0, + PRI_VIEWPORT_WIDTH, viewport->width, + PRI_VIEWPORT_HEIGHT, viewport->height); + + REG_SET_2(DCSURF_PRI_VIEWPORT_START, 0, + PRI_VIEWPORT_X_START, viewport->x, + PRI_VIEWPORT_Y_START, viewport->y); + + /*for stereo*/ + REG_SET_2(DCSURF_SEC_VIEWPORT_DIMENSION, 0, + SEC_VIEWPORT_WIDTH, viewport->width, + SEC_VIEWPORT_HEIGHT, viewport->height); + + REG_SET_2(DCSURF_SEC_VIEWPORT_START, 0, + SEC_VIEWPORT_X_START, viewport->x, + SEC_VIEWPORT_Y_START, viewport->y); + + /* DC supports NV12 only at the moment */ + REG_SET_2(DCSURF_PRI_VIEWPORT_DIMENSION_C, 0, + PRI_VIEWPORT_WIDTH_C, viewport_c->width, + PRI_VIEWPORT_HEIGHT_C, viewport_c->height); + + REG_SET_2(DCSURF_PRI_VIEWPORT_START_C, 0, + PRI_VIEWPORT_X_START_C, viewport_c->x, + PRI_VIEWPORT_Y_START_C, viewport_c->y); +} + +void hubp1_read_state(struct dcn10_hubp *hubp1, + struct dcn_hubp_state *s) +{ + REG_GET(DCSURF_SURFACE_CONFIG, + SURFACE_PIXEL_FORMAT, &s->pixel_format); + + REG_GET(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, + SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, &s->inuse_addr_hi); + + REG_GET_2(DCSURF_PRI_VIEWPORT_DIMENSION, + PRI_VIEWPORT_WIDTH, &s->viewport_width, + PRI_VIEWPORT_HEIGHT, &s->viewport_height); + + REG_GET_2(DCSURF_SURFACE_CONFIG, + ROTATION_ANGLE, &s->rotation_angle, + H_MIRROR_EN, &s->h_mirror_en); + + REG_GET(DCSURF_TILING_CONFIG, + SW_MODE, &s->sw_mode); + + REG_GET(DCSURF_SURFACE_CONTROL, + PRIMARY_SURFACE_DCC_EN, &s->dcc_en); + + REG_GET_3(DCHUBP_CNTL, + HUBP_BLANK_EN, &s->blank_en, + HUBP_TTU_DISABLE, &s->ttu_disable, + HUBP_UNDERFLOW_STATUS, &s->underflow_status); + + REG_GET(DCN_GLOBAL_TTU_CNTL, + MIN_TTU_VBLANK, &s->min_ttu_vblank); + + REG_GET_2(DCN_TTU_QOS_WM, + QoS_LEVEL_LOW_WM, &s->qos_level_low_wm, + QoS_LEVEL_HIGH_WM, &s->qos_level_high_wm); +} + +enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch) +{ + enum cursor_pitch hw_pitch; + + switch (pitch) { + case 64: + hw_pitch = CURSOR_PITCH_64_PIXELS; + break; + case 128: + hw_pitch = CURSOR_PITCH_128_PIXELS; + break; + case 256: + hw_pitch = CURSOR_PITCH_256_PIXELS; + break; + default: + DC_ERR("Invalid cursor pitch of %d. " + "Only 64/128/256 is supported on DCN.\n", pitch); + hw_pitch = CURSOR_PITCH_64_PIXELS; + break; + } + return hw_pitch; +} + +static enum cursor_lines_per_chunk hubp1_get_lines_per_chunk( + unsigned int cur_width, + enum dc_cursor_color_format format) +{ + enum cursor_lines_per_chunk line_per_chunk; + + if (format == CURSOR_MODE_MONO) + /* impl B. expansion in CUR Buffer reader */ + line_per_chunk = CURSOR_LINE_PER_CHUNK_16; + else if (cur_width <= 32) + line_per_chunk = CURSOR_LINE_PER_CHUNK_16; + else if (cur_width <= 64) + line_per_chunk = CURSOR_LINE_PER_CHUNK_8; + else if (cur_width <= 128) + line_per_chunk = CURSOR_LINE_PER_CHUNK_4; + else + line_per_chunk = CURSOR_LINE_PER_CHUNK_2; + + return line_per_chunk; +} + +void hubp1_cursor_set_attributes( + struct hubp *hubp, + const struct dc_cursor_attributes *attr) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + enum cursor_pitch hw_pitch = hubp1_get_cursor_pitch(attr->pitch); + enum cursor_lines_per_chunk lpc = hubp1_get_lines_per_chunk( + attr->width, attr->color_format); + + hubp->curs_attr = *attr; + + REG_UPDATE(CURSOR_SURFACE_ADDRESS_HIGH, + CURSOR_SURFACE_ADDRESS_HIGH, attr->address.high_part); + REG_UPDATE(CURSOR_SURFACE_ADDRESS, + CURSOR_SURFACE_ADDRESS, attr->address.low_part); + + REG_UPDATE_2(CURSOR_SIZE, + CURSOR_WIDTH, attr->width, + CURSOR_HEIGHT, attr->height); + + REG_UPDATE_3(CURSOR_CONTROL, + CURSOR_MODE, attr->color_format, + CURSOR_PITCH, hw_pitch, + CURSOR_LINES_PER_CHUNK, lpc); + + REG_SET_2(CURSOR_SETTINS, 0, + /* no shift of the cursor HDL schedule */ + CURSOR0_DST_Y_OFFSET, 0, + /* used to shift the cursor chunk request deadline */ + CURSOR0_CHUNK_HDL_ADJUST, 3); +} + +void hubp1_cursor_set_position( + struct hubp *hubp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + int src_x_offset = pos->x - pos->x_hotspot - param->viewport_x_start; + uint32_t cur_en = pos->enable ? 1 : 0; + uint32_t dst_x_offset = (src_x_offset >= 0) ? src_x_offset : 0; + + /* + * Guard aganst cursor_set_position() from being called with invalid + * attributes + * + * TODO: Look at combining cursor_set_position() and + * cursor_set_attributes() into cursor_update() + */ + if (hubp->curs_attr.address.quad_part == 0) + return; + + dst_x_offset *= param->ref_clk_khz; + dst_x_offset /= param->pixel_clk_khz; + + ASSERT(param->h_scale_ratio.value); + + if (param->h_scale_ratio.value) + dst_x_offset = dal_fixed31_32_floor(dal_fixed31_32_div( + dal_fixed31_32_from_int(dst_x_offset), + param->h_scale_ratio)); + + if (src_x_offset >= (int)param->viewport_width) + cur_en = 0; /* not visible beyond right edge*/ + + if (src_x_offset + (int)hubp->curs_attr.width < 0) + cur_en = 0; /* not visible beyond left edge*/ + + if (cur_en && REG_READ(CURSOR_SURFACE_ADDRESS) == 0) + hubp->funcs->set_cursor_attributes(hubp, &hubp->curs_attr); + + REG_UPDATE(CURSOR_CONTROL, + CURSOR_ENABLE, cur_en); + + REG_SET_2(CURSOR_POSITION, 0, + CURSOR_X_POSITION, pos->x, + CURSOR_Y_POSITION, pos->y); + + REG_SET_2(CURSOR_HOT_SPOT, 0, + CURSOR_HOT_SPOT_X, pos->x_hotspot, + CURSOR_HOT_SPOT_Y, pos->y_hotspot); + + REG_SET(CURSOR_DST_OFFSET, 0, + CURSOR_DST_X_OFFSET, dst_x_offset); + /* TODO Handle surface pixel formats other than 4:4:4 */ +} + +static struct hubp_funcs dcn10_hubp_funcs = { + .hubp_program_surface_flip_and_addr = + hubp1_program_surface_flip_and_addr, + .hubp_program_surface_config = + hubp1_program_surface_config, + .hubp_is_flip_pending = hubp1_is_flip_pending, + .hubp_setup = hubp1_setup, + .hubp_set_vm_system_aperture_settings = hubp1_set_vm_system_aperture_settings, + .hubp_set_vm_context0_settings = hubp1_set_vm_context0_settings, + .set_blank = hubp1_set_blank, + .dcc_control = hubp1_dcc_control, + .mem_program_viewport = min_set_viewport, + .set_hubp_blank_en = hubp1_set_hubp_blank_en, + .set_cursor_attributes = hubp1_cursor_set_attributes, + .set_cursor_position = hubp1_cursor_set_position, + .hubp_disconnect = hubp1_disconnect, +}; + +/*****************************************/ +/* Constructor, Destructor */ +/*****************************************/ + +void dcn10_hubp_construct( + struct dcn10_hubp *hubp1, + struct dc_context *ctx, + uint32_t inst, + const struct dcn_mi_registers *hubp_regs, + const struct dcn_mi_shift *hubp_shift, + const struct dcn_mi_mask *hubp_mask) +{ + hubp1->base.funcs = &dcn10_hubp_funcs; + hubp1->base.ctx = ctx; + hubp1->hubp_regs = hubp_regs; + hubp1->hubp_shift = hubp_shift; + hubp1->hubp_mask = hubp_mask; + hubp1->base.inst = inst; + hubp1->base.opp_id = 0xf; + hubp1->base.mpcc_id = 0xf; +} + + diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h new file mode 100644 index 000000000000..33e91d9c010f --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h @@ -0,0 +1,686 @@ +/* Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_MEM_INPUT_DCN10_H__ +#define __DC_MEM_INPUT_DCN10_H__ + +#include "hubp.h" + +#define TO_DCN10_HUBP(hubp)\ + container_of(hubp, struct dcn10_hubp, base) + +#define HUBP_REG_LIST_DCN(id)\ + SRI(DCHUBP_CNTL, HUBP, id),\ + SRI(HUBPREQ_DEBUG_DB, HUBP, id),\ + SRI(DCSURF_ADDR_CONFIG, HUBP, id),\ + SRI(DCSURF_TILING_CONFIG, HUBP, id),\ + SRI(DCSURF_SURFACE_PITCH, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_PITCH_C, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_CONFIG, HUBP, id),\ + SRI(DCSURF_FLIP_CONTROL, HUBPREQ, id),\ + SRI(DCSURF_PRI_VIEWPORT_DIMENSION, HUBP, id), \ + SRI(DCSURF_PRI_VIEWPORT_START, HUBP, id), \ + SRI(DCSURF_SEC_VIEWPORT_DIMENSION, HUBP, id), \ + SRI(DCSURF_SEC_VIEWPORT_START, HUBP, id), \ + SRI(DCSURF_PRI_VIEWPORT_DIMENSION_C, HUBP, id), \ + SRI(DCSURF_PRI_VIEWPORT_START_C, HUBP, id), \ + SRI(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, HUBPREQ, id),\ + SRI(DCSURF_PRIMARY_SURFACE_ADDRESS, HUBPREQ, id),\ + SRI(DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, HUBPREQ, id),\ + SRI(DCSURF_SECONDARY_SURFACE_ADDRESS, HUBPREQ, id),\ + SRI(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, HUBPREQ, id),\ + SRI(DCSURF_PRIMARY_META_SURFACE_ADDRESS, HUBPREQ, id),\ + SRI(DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH, HUBPREQ, id),\ + SRI(DCSURF_SECONDARY_META_SURFACE_ADDRESS, HUBPREQ, id),\ + SRI(DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id),\ + SRI(DCSURF_PRIMARY_SURFACE_ADDRESS_C, HUBPREQ, id),\ + SRI(DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, HUBPREQ, id),\ + SRI(DCSURF_PRIMARY_META_SURFACE_ADDRESS_C, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_INUSE, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_INUSE_HIGH, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_INUSE_C, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_INUSE_HIGH_C, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_EARLIEST_INUSE, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_EARLIEST_INUSE_HIGH, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_EARLIEST_INUSE_C, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, HUBPREQ, id),\ + SRI(DCSURF_SURFACE_CONTROL, HUBPREQ, id),\ + SRI(HUBPRET_CONTROL, HUBPRET, id),\ + SRI(DCN_EXPANSION_MODE, HUBPREQ, id),\ + SRI(DCHUBP_REQ_SIZE_CONFIG, HUBP, id),\ + SRI(DCHUBP_REQ_SIZE_CONFIG_C, HUBP, id),\ + SRI(BLANK_OFFSET_0, HUBPREQ, id),\ + SRI(BLANK_OFFSET_1, HUBPREQ, id),\ + SRI(DST_DIMENSIONS, HUBPREQ, id),\ + SRI(DST_AFTER_SCALER, HUBPREQ, id),\ + SRI(VBLANK_PARAMETERS_0, HUBPREQ, id),\ + SRI(REF_FREQ_TO_PIX_FREQ, HUBPREQ, id),\ + SRI(VBLANK_PARAMETERS_1, HUBPREQ, id),\ + SRI(VBLANK_PARAMETERS_3, HUBPREQ, id),\ + SRI(NOM_PARAMETERS_0, HUBPREQ, id),\ + SRI(NOM_PARAMETERS_1, HUBPREQ, id),\ + SRI(NOM_PARAMETERS_4, HUBPREQ, id),\ + SRI(NOM_PARAMETERS_5, HUBPREQ, id),\ + SRI(PER_LINE_DELIVERY_PRE, HUBPREQ, id),\ + SRI(PER_LINE_DELIVERY, HUBPREQ, id),\ + SRI(VBLANK_PARAMETERS_2, HUBPREQ, id),\ + SRI(VBLANK_PARAMETERS_4, HUBPREQ, id),\ + SRI(NOM_PARAMETERS_2, HUBPREQ, id),\ + SRI(NOM_PARAMETERS_3, HUBPREQ, id),\ + SRI(NOM_PARAMETERS_6, HUBPREQ, id),\ + SRI(NOM_PARAMETERS_7, HUBPREQ, id),\ + SRI(DCN_TTU_QOS_WM, HUBPREQ, id),\ + SRI(DCN_GLOBAL_TTU_CNTL, HUBPREQ, id),\ + SRI(DCN_SURF0_TTU_CNTL0, HUBPREQ, id),\ + SRI(DCN_SURF0_TTU_CNTL1, HUBPREQ, id),\ + SRI(DCN_SURF1_TTU_CNTL0, HUBPREQ, id),\ + SRI(DCN_SURF1_TTU_CNTL1, HUBPREQ, id),\ + SRI(DCN_VM_MX_L1_TLB_CNTL, HUBPREQ, id) + +#define HUBP_REG_LIST_DCN10(id)\ + HUBP_REG_LIST_DCN(id),\ + SRI(PREFETCH_SETTINS, HUBPREQ, id),\ + SRI(PREFETCH_SETTINS_C, HUBPREQ, id),\ + SRI(DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB, HUBPREQ, id),\ + SRI(DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB, HUBPREQ, id),\ + SRI(DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB, HUBPREQ, id),\ + SRI(DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB, HUBPREQ, id),\ + SRI(DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB, HUBPREQ, id),\ + SRI(DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB, HUBPREQ, id),\ + SRI(DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB, HUBPREQ, id),\ + SRI(DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB, HUBPREQ, id),\ + SRI(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, HUBPREQ, id),\ + SRI(DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, HUBPREQ, id),\ + SRI(DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, HUBPREQ, id),\ + SRI(DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, HUBPREQ, id),\ + SRI(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, HUBPREQ, id),\ + SRI(DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, HUBPREQ, id),\ + SR(DCHUBBUB_SDPIF_FB_BASE),\ + SR(DCHUBBUB_SDPIF_FB_OFFSET),\ + SRI(CURSOR_SETTINS, HUBPREQ, id), \ + SRI(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR, id), \ + SRI(CURSOR_SURFACE_ADDRESS, CURSOR, id), \ + SRI(CURSOR_SIZE, CURSOR, id), \ + SRI(CURSOR_CONTROL, CURSOR, id), \ + SRI(CURSOR_POSITION, CURSOR, id), \ + SRI(CURSOR_HOT_SPOT, CURSOR, id), \ + SRI(CURSOR_DST_OFFSET, CURSOR, id) + +#define HUBP_COMMON_REG_VARIABLE_LIST \ + uint32_t DCHUBP_CNTL; \ + uint32_t HUBPREQ_DEBUG_DB; \ + uint32_t DCSURF_ADDR_CONFIG; \ + uint32_t DCSURF_TILING_CONFIG; \ + uint32_t DCSURF_SURFACE_PITCH; \ + uint32_t DCSURF_SURFACE_PITCH_C; \ + uint32_t DCSURF_SURFACE_CONFIG; \ + uint32_t DCSURF_FLIP_CONTROL; \ + uint32_t DCSURF_PRI_VIEWPORT_DIMENSION; \ + uint32_t DCSURF_PRI_VIEWPORT_START; \ + uint32_t DCSURF_SEC_VIEWPORT_DIMENSION; \ + uint32_t DCSURF_SEC_VIEWPORT_START; \ + uint32_t DCSURF_PRI_VIEWPORT_DIMENSION_C; \ + uint32_t DCSURF_PRI_VIEWPORT_START_C; \ + uint32_t DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH; \ + uint32_t DCSURF_PRIMARY_SURFACE_ADDRESS; \ + uint32_t DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH; \ + uint32_t DCSURF_SECONDARY_SURFACE_ADDRESS; \ + uint32_t DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH; \ + uint32_t DCSURF_PRIMARY_META_SURFACE_ADDRESS; \ + uint32_t DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH; \ + uint32_t DCSURF_SECONDARY_META_SURFACE_ADDRESS; \ + uint32_t DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C; \ + uint32_t DCSURF_PRIMARY_SURFACE_ADDRESS_C; \ + uint32_t DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C; \ + uint32_t DCSURF_PRIMARY_META_SURFACE_ADDRESS_C; \ + uint32_t DCSURF_SURFACE_INUSE; \ + uint32_t DCSURF_SURFACE_INUSE_HIGH; \ + uint32_t DCSURF_SURFACE_INUSE_C; \ + uint32_t DCSURF_SURFACE_INUSE_HIGH_C; \ + uint32_t DCSURF_SURFACE_EARLIEST_INUSE; \ + uint32_t DCSURF_SURFACE_EARLIEST_INUSE_HIGH; \ + uint32_t DCSURF_SURFACE_EARLIEST_INUSE_C; \ + uint32_t DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C; \ + uint32_t DCSURF_SURFACE_CONTROL; \ + uint32_t HUBPRET_CONTROL; \ + uint32_t DCN_EXPANSION_MODE; \ + uint32_t DCHUBP_REQ_SIZE_CONFIG; \ + uint32_t DCHUBP_REQ_SIZE_CONFIG_C; \ + uint32_t BLANK_OFFSET_0; \ + uint32_t BLANK_OFFSET_1; \ + uint32_t DST_DIMENSIONS; \ + uint32_t DST_AFTER_SCALER; \ + uint32_t PREFETCH_SETTINS; \ + uint32_t PREFETCH_SETTINGS; \ + uint32_t VBLANK_PARAMETERS_0; \ + uint32_t REF_FREQ_TO_PIX_FREQ; \ + uint32_t VBLANK_PARAMETERS_1; \ + uint32_t VBLANK_PARAMETERS_3; \ + uint32_t NOM_PARAMETERS_0; \ + uint32_t NOM_PARAMETERS_1; \ + uint32_t NOM_PARAMETERS_4; \ + uint32_t NOM_PARAMETERS_5; \ + uint32_t PER_LINE_DELIVERY_PRE; \ + uint32_t PER_LINE_DELIVERY; \ + uint32_t PREFETCH_SETTINS_C; \ + uint32_t PREFETCH_SETTINGS_C; \ + uint32_t VBLANK_PARAMETERS_2; \ + uint32_t VBLANK_PARAMETERS_4; \ + uint32_t NOM_PARAMETERS_2; \ + uint32_t NOM_PARAMETERS_3; \ + uint32_t NOM_PARAMETERS_6; \ + uint32_t NOM_PARAMETERS_7; \ + uint32_t DCN_TTU_QOS_WM; \ + uint32_t DCN_GLOBAL_TTU_CNTL; \ + uint32_t DCN_SURF0_TTU_CNTL0; \ + uint32_t DCN_SURF0_TTU_CNTL1; \ + uint32_t DCN_SURF1_TTU_CNTL0; \ + uint32_t DCN_SURF1_TTU_CNTL1; \ + uint32_t DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB; \ + uint32_t DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB; \ + uint32_t DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB; \ + uint32_t DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB; \ + uint32_t DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB; \ + uint32_t DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB; \ + uint32_t DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB; \ + uint32_t DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB; \ + uint32_t DCN_VM_MX_L1_TLB_CNTL; \ + uint32_t DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB; \ + uint32_t DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB; \ + uint32_t DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB; \ + uint32_t DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB; \ + uint32_t DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB; \ + uint32_t DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB; \ + uint32_t DCN_VM_SYSTEM_APERTURE_LOW_ADDR; \ + uint32_t DCN_VM_SYSTEM_APERTURE_HIGH_ADDR; \ + uint32_t DCHUBBUB_SDPIF_FB_BASE; \ + uint32_t DCHUBBUB_SDPIF_FB_OFFSET; \ + uint32_t DCN_VM_FB_LOCATION_TOP; \ + uint32_t DCN_VM_FB_LOCATION_BASE; \ + uint32_t DCN_VM_FB_OFFSET; \ + uint32_t DCN_VM_AGP_BASE; \ + uint32_t DCN_VM_AGP_BOT; \ + uint32_t DCN_VM_AGP_TOP; \ + uint32_t CURSOR_SETTINS; \ + uint32_t CURSOR_SETTINGS; \ + uint32_t CURSOR_SURFACE_ADDRESS_HIGH; \ + uint32_t CURSOR_SURFACE_ADDRESS; \ + uint32_t CURSOR_SIZE; \ + uint32_t CURSOR_CONTROL; \ + uint32_t CURSOR_POSITION; \ + uint32_t CURSOR_HOT_SPOT; \ + uint32_t CURSOR_DST_OFFSET + +#define HUBP_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define HUBP_MASK_SH_LIST_DCN(mask_sh)\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_BLANK_EN, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_TTU_DISABLE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_UNDERFLOW_STATUS, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_CNTL, HUBP_NO_OUTSTANDING_REQ, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_PIPES, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_BANKS, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, PIPE_INTERLEAVE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_SE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, NUM_RB_PER_SE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_ADDR_CONFIG, MAX_COMPRESSED_FRAGS, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, SW_MODE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, META_LINEAR, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, RB_ALIGNED, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_TILING_CONFIG, PIPE_ALIGNED, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH, PITCH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH, META_PITCH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH_C, PITCH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_PITCH_C, META_PITCH_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, ROTATION_ANGLE, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, H_MIRROR_EN, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SURFACE_CONFIG, SURFACE_PIXEL_FORMAT, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_TYPE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_FLIP_PENDING, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_FLIP_CONTROL, SURFACE_UPDATE_LOCK, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_WIDTH, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION, PRI_VIEWPORT_HEIGHT, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START, PRI_VIEWPORT_X_START, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START, PRI_VIEWPORT_Y_START, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION, SEC_VIEWPORT_WIDTH, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_DIMENSION, SEC_VIEWPORT_HEIGHT, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START, SEC_VIEWPORT_X_START, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_SEC_VIEWPORT_START, SEC_VIEWPORT_Y_START, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_C, PRI_VIEWPORT_WIDTH_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_DIMENSION_C, PRI_VIEWPORT_HEIGHT_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START_C, PRI_VIEWPORT_X_START_C, mask_sh),\ + HUBP_SF(HUBP0_DCSURF_PRI_VIEWPORT_START_C, PRI_VIEWPORT_Y_START_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH, PRIMARY_SURFACE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS, PRIMARY_SURFACE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS_HIGH, SECONDARY_SURFACE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_SURFACE_ADDRESS, SECONDARY_SURFACE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH, PRIMARY_META_SURFACE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_META_SURFACE_ADDRESS, PRIMARY_META_SURFACE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_META_SURFACE_ADDRESS_HIGH, SECONDARY_META_SURFACE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SECONDARY_META_SURFACE_ADDRESS, SECONDARY_META_SURFACE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_HIGH_C, PRIMARY_SURFACE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_SURFACE_ADDRESS_C, PRIMARY_SURFACE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_META_SURFACE_ADDRESS_HIGH_C, PRIMARY_META_SURFACE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_PRIMARY_META_SURFACE_ADDRESS_C, PRIMARY_META_SURFACE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE, SURFACE_INUSE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_HIGH, SURFACE_INUSE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_C, SURFACE_INUSE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_INUSE_HIGH_C, SURFACE_INUSE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE, SURFACE_EARLIEST_INUSE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_HIGH, SURFACE_EARLIEST_INUSE_ADDRESS_HIGH, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_C, SURFACE_EARLIEST_INUSE_ADDRESS_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_EARLIEST_INUSE_HIGH_C, SURFACE_EARLIEST_INUSE_ADDRESS_HIGH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_TMZ, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_EN, mask_sh),\ + HUBP_SF(HUBPREQ0_DCSURF_SURFACE_CONTROL, PRIMARY_SURFACE_DCC_IND_64B_BLK, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, DET_BUF_PLANE1_BASE_ADDRESS, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CB_B, mask_sh),\ + HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CR_R, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, DRQ_EXPANSION_MODE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, PRQ_EXPANSION_MODE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, MRQ_EXPANSION_MODE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, CRQ_EXPANSION_MODE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, CHUNK_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MIN_CHUNK_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, META_CHUNK_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MIN_META_CHUNK_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, DPTE_GROUP_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, MPTE_GROUP_SIZE, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, SWATH_HEIGHT, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG, PTE_ROW_HEIGHT_LINEAR, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, CHUNK_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MIN_CHUNK_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, META_CHUNK_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MIN_META_CHUNK_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, DPTE_GROUP_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, MPTE_GROUP_SIZE_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, SWATH_HEIGHT_C, mask_sh),\ + HUBP_SF(HUBP0_DCHUBP_REQ_SIZE_CONFIG_C, PTE_ROW_HEIGHT_LINEAR_C, mask_sh),\ + HUBP_SF(HUBPREQ0_BLANK_OFFSET_0, REFCYC_H_BLANK_END, mask_sh),\ + HUBP_SF(HUBPREQ0_BLANK_OFFSET_0, DLG_V_BLANK_END, mask_sh),\ + HUBP_SF(HUBPREQ0_BLANK_OFFSET_1, MIN_DST_Y_NEXT_START, mask_sh),\ + HUBP_SF(HUBPREQ0_DST_DIMENSIONS, REFCYC_PER_HTOTAL, mask_sh),\ + HUBP_SF(HUBPREQ0_DST_AFTER_SCALER, REFCYC_X_AFTER_SCALER, mask_sh),\ + HUBP_SF(HUBPREQ0_DST_AFTER_SCALER, DST_Y_AFTER_SCALER, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_0, DST_Y_PER_VM_VBLANK, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_0, DST_Y_PER_ROW_VBLANK, mask_sh),\ + HUBP_SF(HUBPREQ0_REF_FREQ_TO_PIX_FREQ, REF_FREQ_TO_PIX_FREQ, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_1, REFCYC_PER_PTE_GROUP_VBLANK_L, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_3, REFCYC_PER_META_CHUNK_VBLANK_L, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_0, DST_Y_PER_PTE_ROW_NOM_L, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_1, REFCYC_PER_PTE_GROUP_NOM_L, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_4, DST_Y_PER_META_ROW_NOM_L, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_5, REFCYC_PER_META_CHUNK_NOM_L, mask_sh),\ + HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY_PRE, REFCYC_PER_LINE_DELIVERY_PRE_L, mask_sh),\ + HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY_PRE, REFCYC_PER_LINE_DELIVERY_PRE_C, mask_sh),\ + HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY, REFCYC_PER_LINE_DELIVERY_L, mask_sh),\ + HUBP_SF(HUBPREQ0_PER_LINE_DELIVERY, REFCYC_PER_LINE_DELIVERY_C, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_2, REFCYC_PER_PTE_GROUP_VBLANK_C, mask_sh),\ + HUBP_SF(HUBPREQ0_VBLANK_PARAMETERS_4, REFCYC_PER_META_CHUNK_VBLANK_C, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_2, DST_Y_PER_PTE_ROW_NOM_C, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_3, REFCYC_PER_PTE_GROUP_NOM_C, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_6, DST_Y_PER_META_ROW_NOM_C, mask_sh),\ + HUBP_SF(HUBPREQ0_NOM_PARAMETERS_7, REFCYC_PER_META_CHUNK_NOM_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_TTU_QOS_WM, QoS_LEVEL_LOW_WM, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_TTU_QOS_WM, QoS_LEVEL_HIGH_WM, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, MIN_TTU_VBLANK, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_GLOBAL_TTU_CNTL, QoS_LEVEL_FLIP, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, REFCYC_PER_REQ_DELIVERY, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, QoS_LEVEL_FIXED, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL0, QoS_RAMP_DISABLE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_SURF0_TTU_CNTL1, REFCYC_PER_REQ_DELIVERY_PRE, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_MX_L1_TLB_CNTL, ENABLE_L1_TLB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_MX_L1_TLB_CNTL, SYSTEM_ACCESS_MODE, mask_sh) + +#define HUBP_MASK_SH_LIST_DCN10(mask_sh)\ + HUBP_MASK_SH_LIST_DCN(mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINS, DST_Y_PREFETCH, mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINS, VRATIO_PREFETCH, mask_sh),\ + HUBP_SF(HUBPREQ0_PREFETCH_SETTINS_C, VRATIO_PREFETCH_C, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB, VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB, VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB, VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB, VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB, VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB, VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB, VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_SYSTEM, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB, VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, MC_VM_SYSTEM_APERTURE_LOW_ADDR_MSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, MC_VM_SYSTEM_APERTURE_LOW_ADDR_LSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, MC_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, MC_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB, mask_sh),\ + HUBP_SF(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, mask_sh),\ + HUBP_SF(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, MC_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, mask_sh),\ + HUBP_SF(HUBPREQ0_DCN_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, mask_sh),\ + HUBP_SF(HUBPREQ0_CURSOR_SETTINS, CURSOR0_DST_Y_OFFSET, mask_sh), \ + HUBP_SF(HUBPREQ0_CURSOR_SETTINS, CURSOR0_CHUNK_HDL_ADJUST, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_SIZE, CURSOR_WIDTH, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_SIZE, CURSOR_HEIGHT, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_2X_MAGNIFY, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_POSITION, CURSOR_X_POSITION, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_POSITION, CURSOR_Y_POSITION, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ + HUBP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh) + +#define DCN_HUBP_REG_FIELD_LIST(type) \ + type HUBP_BLANK_EN;\ + type HUBP_TTU_DISABLE;\ + type HUBP_NO_OUTSTANDING_REQ;\ + type HUBP_UNDERFLOW_STATUS;\ + type NUM_PIPES;\ + type NUM_BANKS;\ + type PIPE_INTERLEAVE;\ + type NUM_SE;\ + type NUM_RB_PER_SE;\ + type MAX_COMPRESSED_FRAGS;\ + type SW_MODE;\ + type META_LINEAR;\ + type RB_ALIGNED;\ + type PIPE_ALIGNED;\ + type PITCH;\ + type META_PITCH;\ + type PITCH_C;\ + type META_PITCH_C;\ + type ROTATION_ANGLE;\ + type H_MIRROR_EN;\ + type SURFACE_PIXEL_FORMAT;\ + type SURFACE_FLIP_TYPE;\ + type SURFACE_UPDATE_LOCK;\ + type SURFACE_FLIP_PENDING;\ + type PRI_VIEWPORT_WIDTH; \ + type PRI_VIEWPORT_HEIGHT; \ + type PRI_VIEWPORT_X_START; \ + type PRI_VIEWPORT_Y_START; \ + type SEC_VIEWPORT_WIDTH; \ + type SEC_VIEWPORT_HEIGHT; \ + type SEC_VIEWPORT_X_START; \ + type SEC_VIEWPORT_Y_START; \ + type PRI_VIEWPORT_WIDTH_C; \ + type PRI_VIEWPORT_HEIGHT_C; \ + type PRI_VIEWPORT_X_START_C; \ + type PRI_VIEWPORT_Y_START_C; \ + type PRIMARY_SURFACE_ADDRESS_HIGH;\ + type PRIMARY_SURFACE_ADDRESS;\ + type SECONDARY_SURFACE_ADDRESS_HIGH;\ + type SECONDARY_SURFACE_ADDRESS;\ + type PRIMARY_META_SURFACE_ADDRESS_HIGH;\ + type PRIMARY_META_SURFACE_ADDRESS;\ + type SECONDARY_META_SURFACE_ADDRESS_HIGH;\ + type SECONDARY_META_SURFACE_ADDRESS;\ + type PRIMARY_SURFACE_ADDRESS_HIGH_C;\ + type PRIMARY_SURFACE_ADDRESS_C;\ + type PRIMARY_META_SURFACE_ADDRESS_HIGH_C;\ + type PRIMARY_META_SURFACE_ADDRESS_C;\ + type SURFACE_INUSE_ADDRESS;\ + type SURFACE_INUSE_ADDRESS_HIGH;\ + type SURFACE_INUSE_ADDRESS_C;\ + type SURFACE_INUSE_ADDRESS_HIGH_C;\ + type SURFACE_EARLIEST_INUSE_ADDRESS;\ + type SURFACE_EARLIEST_INUSE_ADDRESS_HIGH;\ + type SURFACE_EARLIEST_INUSE_ADDRESS_C;\ + type SURFACE_EARLIEST_INUSE_ADDRESS_HIGH_C;\ + type PRIMARY_SURFACE_TMZ;\ + type PRIMARY_SURFACE_DCC_EN;\ + type PRIMARY_SURFACE_DCC_IND_64B_BLK;\ + type DET_BUF_PLANE1_BASE_ADDRESS;\ + type CROSSBAR_SRC_CB_B;\ + type CROSSBAR_SRC_CR_R;\ + type DRQ_EXPANSION_MODE;\ + type PRQ_EXPANSION_MODE;\ + type MRQ_EXPANSION_MODE;\ + type CRQ_EXPANSION_MODE;\ + type CHUNK_SIZE;\ + type MIN_CHUNK_SIZE;\ + type META_CHUNK_SIZE;\ + type MIN_META_CHUNK_SIZE;\ + type DPTE_GROUP_SIZE;\ + type MPTE_GROUP_SIZE;\ + type SWATH_HEIGHT;\ + type PTE_ROW_HEIGHT_LINEAR;\ + type CHUNK_SIZE_C;\ + type MIN_CHUNK_SIZE_C;\ + type META_CHUNK_SIZE_C;\ + type MIN_META_CHUNK_SIZE_C;\ + type DPTE_GROUP_SIZE_C;\ + type MPTE_GROUP_SIZE_C;\ + type SWATH_HEIGHT_C;\ + type PTE_ROW_HEIGHT_LINEAR_C;\ + type REFCYC_H_BLANK_END;\ + type DLG_V_BLANK_END;\ + type MIN_DST_Y_NEXT_START;\ + type REFCYC_PER_HTOTAL;\ + type REFCYC_X_AFTER_SCALER;\ + type DST_Y_AFTER_SCALER;\ + type DST_Y_PREFETCH;\ + type VRATIO_PREFETCH;\ + type DST_Y_PER_VM_VBLANK;\ + type DST_Y_PER_ROW_VBLANK;\ + type REF_FREQ_TO_PIX_FREQ;\ + type REFCYC_PER_PTE_GROUP_VBLANK_L;\ + type REFCYC_PER_META_CHUNK_VBLANK_L;\ + type DST_Y_PER_PTE_ROW_NOM_L;\ + type REFCYC_PER_PTE_GROUP_NOM_L;\ + type DST_Y_PER_META_ROW_NOM_L;\ + type REFCYC_PER_META_CHUNK_NOM_L;\ + type REFCYC_PER_LINE_DELIVERY_PRE_L;\ + type REFCYC_PER_LINE_DELIVERY_PRE_C;\ + type REFCYC_PER_LINE_DELIVERY_L;\ + type REFCYC_PER_LINE_DELIVERY_C;\ + type VRATIO_PREFETCH_C;\ + type REFCYC_PER_PTE_GROUP_VBLANK_C;\ + type REFCYC_PER_META_CHUNK_VBLANK_C;\ + type DST_Y_PER_PTE_ROW_NOM_C;\ + type REFCYC_PER_PTE_GROUP_NOM_C;\ + type DST_Y_PER_META_ROW_NOM_C;\ + type REFCYC_PER_META_CHUNK_NOM_C;\ + type QoS_LEVEL_LOW_WM;\ + type QoS_LEVEL_HIGH_WM;\ + type MIN_TTU_VBLANK;\ + type QoS_LEVEL_FLIP;\ + type REFCYC_PER_REQ_DELIVERY;\ + type QoS_LEVEL_FIXED;\ + type QoS_RAMP_DISABLE;\ + type REFCYC_PER_REQ_DELIVERY_PRE;\ + type VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_MSB;\ + type VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LSB;\ + type VM_CONTEXT0_PAGE_TABLE_START_ADDR_MSB;\ + type VM_CONTEXT0_PAGE_TABLE_START_ADDR_LSB;\ + type VM_CONTEXT0_PAGE_TABLE_END_ADDR_MSB;\ + type VM_CONTEXT0_PAGE_TABLE_END_ADDR_LSB;\ + type VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_MSB;\ + type VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_SYSTEM;\ + type VM_CONTEXT0_PROTECTION_FAULT_DEFAULT_ADDR_LSB;\ + type ENABLE_L1_TLB;\ + type SYSTEM_ACCESS_MODE;\ + type MC_VM_SYSTEM_APERTURE_DEFAULT_SYSTEM;\ + type MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB;\ + type MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB;\ + type MC_VM_SYSTEM_APERTURE_LOW_ADDR_MSB;\ + type MC_VM_SYSTEM_APERTURE_LOW_ADDR_LSB;\ + type MC_VM_SYSTEM_APERTURE_HIGH_ADDR_MSB;\ + type MC_VM_SYSTEM_APERTURE_HIGH_ADDR_LSB;\ + type MC_VM_SYSTEM_APERTURE_LOW_ADDR;\ + type MC_VM_SYSTEM_APERTURE_HIGH_ADDR;\ + type SDPIF_FB_TOP;\ + type SDPIF_FB_BASE;\ + type SDPIF_FB_OFFSET;\ + type SDPIF_AGP_BASE;\ + type SDPIF_AGP_BOT;\ + type SDPIF_AGP_TOP;\ + type FB_TOP;\ + type FB_BASE;\ + type FB_OFFSET;\ + type AGP_BASE;\ + type AGP_BOT;\ + type AGP_TOP;\ + /* todo: get these from GVM instead of reading registers ourselves */\ + type PAGE_DIRECTORY_ENTRY_HI32;\ + type PAGE_DIRECTORY_ENTRY_LO32;\ + type LOGICAL_PAGE_NUMBER_HI4;\ + type LOGICAL_PAGE_NUMBER_LO32;\ + type PHYSICAL_PAGE_ADDR_HI4;\ + type PHYSICAL_PAGE_ADDR_LO32;\ + type PHYSICAL_PAGE_NUMBER_MSB;\ + type PHYSICAL_PAGE_NUMBER_LSB;\ + type LOGICAL_ADDR;\ + type CURSOR0_DST_Y_OFFSET; \ + type CURSOR0_CHUNK_HDL_ADJUST; \ + type CURSOR_SURFACE_ADDRESS_HIGH; \ + type CURSOR_SURFACE_ADDRESS; \ + type CURSOR_WIDTH; \ + type CURSOR_HEIGHT; \ + type CURSOR_MODE; \ + type CURSOR_2X_MAGNIFY; \ + type CURSOR_PITCH; \ + type CURSOR_LINES_PER_CHUNK; \ + type CURSOR_ENABLE; \ + type CURSOR_X_POSITION; \ + type CURSOR_Y_POSITION; \ + type CURSOR_HOT_SPOT_X; \ + type CURSOR_HOT_SPOT_Y; \ + type CURSOR_DST_X_OFFSET; \ + type OUTPUT_FP + +struct dcn_mi_registers { + HUBP_COMMON_REG_VARIABLE_LIST; +}; + +struct dcn_mi_shift { + DCN_HUBP_REG_FIELD_LIST(uint8_t); +}; + +struct dcn_mi_mask { + DCN_HUBP_REG_FIELD_LIST(uint32_t); +}; + +struct dcn10_hubp { + struct hubp base; + const struct dcn_mi_registers *hubp_regs; + const struct dcn_mi_shift *hubp_shift; + const struct dcn_mi_mask *hubp_mask; +}; + +void hubp1_program_surface_config( + struct hubp *hubp, + enum surface_pixel_format format, + union dc_tiling_info *tiling_info, + union plane_size *plane_size, + enum dc_rotation_angle rotation, + struct dc_plane_dcc_param *dcc, + bool horizontal_mirror); + +void hubp1_program_deadline( + struct hubp *hubp, + struct _vcs_dpi_display_dlg_regs_st *dlg_attr, + struct _vcs_dpi_display_ttu_regs_st *ttu_attr); + +void hubp1_program_requestor( + struct hubp *hubp, + struct _vcs_dpi_display_rq_regs_st *rq_regs); + +void hubp1_program_pixel_format( + struct hubp *hubp, + enum surface_pixel_format format); + +void hubp1_program_size_and_rotation( + struct hubp *hubp, + enum dc_rotation_angle rotation, + enum surface_pixel_format format, + const union plane_size *plane_size, + struct dc_plane_dcc_param *dcc, + bool horizontal_mirror); + +void hubp1_program_tiling( + struct hubp *hubp, + const union dc_tiling_info *info, + const enum surface_pixel_format pixel_format); + +void hubp1_dcc_control(struct hubp *hubp, + bool enable, + bool independent_64b_blks); + +bool hubp1_program_surface_flip_and_addr( + struct hubp *hubp, + const struct dc_plane_address *address, + bool flip_immediate); + +bool hubp1_is_flip_pending(struct hubp *hubp); + +void hubp1_cursor_set_attributes( + struct hubp *hubp, + const struct dc_cursor_attributes *attr); + +void hubp1_cursor_set_position( + struct hubp *hubp, + const struct dc_cursor_position *pos, + const struct dc_cursor_mi_param *param); + +void hubp1_set_blank(struct hubp *hubp, bool blank); + +void min_set_viewport(struct hubp *hubp, + const struct rect *viewport, + const struct rect *viewport_c); + +void dcn10_hubp_construct( + struct dcn10_hubp *hubp1, + struct dc_context *ctx, + uint32_t inst, + const struct dcn_mi_registers *hubp_regs, + const struct dcn_mi_shift *hubp_shift, + const struct dcn_mi_mask *hubp_mask); + + +struct dcn_hubp_state { + uint32_t pixel_format; + uint32_t inuse_addr_hi; + uint32_t viewport_width; + uint32_t viewport_height; + uint32_t rotation_angle; + uint32_t h_mirror_en; + uint32_t sw_mode; + uint32_t dcc_en; + uint32_t blank_en; + uint32_t underflow_status; + uint32_t ttu_disable; + uint32_t min_ttu_vblank; + uint32_t qos_level_low_wm; + uint32_t qos_level_high_wm; +}; +void hubp1_read_state(struct dcn10_hubp *hubp1, + struct dcn_hubp_state *s); + +enum cursor_pitch hubp1_get_cursor_pitch(unsigned int pitch); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c new file mode 100644 index 000000000000..82572863acab --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -0,0 +1,2372 @@ +/* + * Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "core_types.h" +#include "resource.h" +#include "custom_float.h" +#include "dcn10_hw_sequencer.h" +#include "dce110/dce110_hw_sequencer.h" +#include "dce/dce_hwseq.h" +#include "abm.h" +#include "dmcu.h" +#include "dcn10_optc.h" +#include "dcn10/dcn10_dpp.h" +#include "dcn10/dcn10_mpc.h" +#include "timing_generator.h" +#include "opp.h" +#include "ipp.h" +#include "mpc.h" +#include "reg_helper.h" +#include "custom_float.h" +#include "dcn10_hubp.h" +#include "dcn10_hubbub.h" +#include "dcn10_cm_common.h" + +#define CTX \ + hws->ctx +#define REG(reg)\ + hws->regs->reg + +#undef FN +#define FN(reg_name, field_name) \ + hws->shifts->field_name, hws->masks->field_name + +#define DTN_INFO_MICRO_SEC(ref_cycle) \ + print_microsec(dc_ctx, ref_cycle) + +void print_microsec(struct dc_context *dc_ctx, uint32_t ref_cycle) +{ + static const uint32_t ref_clk_mhz = 48; + static const unsigned int frac = 10; + uint32_t us_x10 = (ref_cycle * frac) / ref_clk_mhz; + + DTN_INFO("%d.%d \t ", + us_x10 / frac, + us_x10 % frac); +} + + +static void log_mpc_crc(struct dc *dc) +{ + struct dc_context *dc_ctx = dc->ctx; + struct dce_hwseq *hws = dc->hwseq; + + if (REG(MPC_CRC_RESULT_GB)) + DTN_INFO("MPC_CRC_RESULT_GB:%d MPC_CRC_RESULT_C:%d MPC_CRC_RESULT_AR:%d\n", + REG_READ(MPC_CRC_RESULT_GB), REG_READ(MPC_CRC_RESULT_C), REG_READ(MPC_CRC_RESULT_AR)); + if (REG(DPP_TOP0_DPP_CRC_VAL_B_A)) + DTN_INFO("DPP_TOP0_DPP_CRC_VAL_B_A:%d DPP_TOP0_DPP_CRC_VAL_R_G:%d\n", + REG_READ(DPP_TOP0_DPP_CRC_VAL_B_A), REG_READ(DPP_TOP0_DPP_CRC_VAL_R_G)); +} + +void dcn10_log_hubbub_state(struct dc *dc) +{ + struct dc_context *dc_ctx = dc->ctx; + struct dcn_hubbub_wm wm; + int i; + + hubbub1_wm_read_state(dc->res_pool->hubbub, &wm); + + DTN_INFO("HUBBUB WM: \t data_urgent \t pte_meta_urgent \t " + "sr_enter \t sr_exit \t dram_clk_change \n"); + + for (i = 0; i < 4; i++) { + struct dcn_hubbub_wm_set *s; + + s = &wm.sets[i]; + DTN_INFO("WM_Set[%d]:\t ", s->wm_set); + DTN_INFO_MICRO_SEC(s->data_urgent); + DTN_INFO_MICRO_SEC(s->pte_meta_urgent); + DTN_INFO_MICRO_SEC(s->sr_enter); + DTN_INFO_MICRO_SEC(s->sr_exit); + DTN_INFO_MICRO_SEC(s->dram_clk_chanage); + DTN_INFO("\n"); + } + + DTN_INFO("\n"); +} + +void dcn10_log_hw_state(struct dc *dc) +{ + struct dc_context *dc_ctx = dc->ctx; + struct resource_pool *pool = dc->res_pool; + int i; + + DTN_INFO_BEGIN(); + + dcn10_log_hubbub_state(dc); + + DTN_INFO("HUBP:\t format \t addr_hi \t width \t height \t " + "rotation \t mirror \t sw_mode \t " + "dcc_en \t blank_en \t ttu_dis \t underflow \t " + "min_ttu_vblank \t qos_low_wm \t qos_high_wm \n"); + + for (i = 0; i < pool->pipe_count; i++) { + struct hubp *hubp = pool->hubps[i]; + struct dcn_hubp_state s; + + hubp1_read_state(TO_DCN10_HUBP(hubp), &s); + + DTN_INFO("[%d]:\t %xh \t %xh \t %d \t %d \t " + "%xh \t %xh \t %xh \t " + "%d \t %d \t %d \t %xh \t", + i, + s.pixel_format, + s.inuse_addr_hi, + s.viewport_width, + s.viewport_height, + s.rotation_angle, + s.h_mirror_en, + s.sw_mode, + s.dcc_en, + s.blank_en, + s.ttu_disable, + s.underflow_status); + DTN_INFO_MICRO_SEC(s.min_ttu_vblank); + DTN_INFO_MICRO_SEC(s.qos_level_low_wm); + DTN_INFO_MICRO_SEC(s.qos_level_high_wm); + DTN_INFO("\n"); + } + DTN_INFO("\n"); + + DTN_INFO("OTG:\t v_bs \t v_be \t v_ss \t v_se \t vpol \t vmax \t vmin \t " + "h_bs \t h_be \t h_ss \t h_se \t hpol \t htot \t vtot \t underflow\n"); + + for (i = 0; i < pool->res_cap->num_timing_generator; i++) { + struct timing_generator *tg = pool->timing_generators[i]; + struct dcn_otg_state s = {0}; + + optc1_read_otg_state(DCN10TG_FROM_TG(tg), &s); + + //only print if OTG master is enabled + if ((s.otg_enabled & 1) == 0) + continue; + + DTN_INFO("[%d]:\t %d \t %d \t %d \t %d \t " + "%d \t %d \t %d \t %d \t %d \t %d \t " + "%d \t %d \t %d \t %d \t %d \t ", + i, + s.v_blank_start, + s.v_blank_end, + s.v_sync_a_start, + s.v_sync_a_end, + s.v_sync_a_pol, + s.v_total_max, + s.v_total_min, + s.h_blank_start, + s.h_blank_end, + s.h_sync_a_start, + s.h_sync_a_end, + s.h_sync_a_pol, + s.h_total, + s.v_total, + s.underflow_occurred_status); + DTN_INFO("\n"); + } + DTN_INFO("\n"); + + log_mpc_crc(dc); + + DTN_INFO_END(); +} + +static void enable_dppclk( + struct dce_hwseq *hws, + uint8_t plane_id, + uint32_t requested_pix_clk, + bool dppclk_div) +{ + dm_logger_write(hws->ctx->logger, LOG_SURFACE, + "dppclk_rate_control for pipe %d programed to %d\n", + plane_id, + dppclk_div); + + if (hws->shifts->DPPCLK_RATE_CONTROL) + REG_UPDATE_2(DPP_CONTROL[plane_id], + DPPCLK_RATE_CONTROL, dppclk_div, + DPP_CLOCK_ENABLE, 1); + else + REG_UPDATE(DPP_CONTROL[plane_id], + DPP_CLOCK_ENABLE, 1); +} + +static void enable_power_gating_plane( + struct dce_hwseq *hws, + bool enable) +{ + bool force_on = 1; /* disable power gating */ + + if (enable) + force_on = 0; + + /* DCHUBP0/1/2/3 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN0_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN2_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN4_PG_CONFIG, DOMAIN4_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN6_PG_CONFIG, DOMAIN6_POWER_FORCEON, force_on); + + /* DPP0/1/2/3 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN1_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN3_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN5_PG_CONFIG, DOMAIN5_POWER_FORCEON, force_on); + REG_UPDATE(DOMAIN7_PG_CONFIG, DOMAIN7_POWER_FORCEON, force_on); +} + +static void disable_vga( + struct dce_hwseq *hws) +{ + REG_WRITE(D1VGA_CONTROL, 0); + REG_WRITE(D2VGA_CONTROL, 0); + REG_WRITE(D3VGA_CONTROL, 0); + REG_WRITE(D4VGA_CONTROL, 0); +} + +static void dpp_pg_control( + struct dce_hwseq *hws, + unsigned int dpp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_dpp_power_gate) + return; + + switch (dpp_inst) { + case 0: /* DPP0 */ + REG_UPDATE(DOMAIN1_PG_CONFIG, + DOMAIN1_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN1_PG_STATUS, + DOMAIN1_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DPP1 */ + REG_UPDATE(DOMAIN3_PG_CONFIG, + DOMAIN3_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN3_PG_STATUS, + DOMAIN3_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DPP2 */ + REG_UPDATE(DOMAIN5_PG_CONFIG, + DOMAIN5_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN5_PG_STATUS, + DOMAIN5_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DPP3 */ + REG_UPDATE(DOMAIN7_PG_CONFIG, + DOMAIN7_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN7_PG_STATUS, + DOMAIN7_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +static void hubp_pg_control( + struct dce_hwseq *hws, + unsigned int hubp_inst, + bool power_on) +{ + uint32_t power_gate = power_on ? 0 : 1; + uint32_t pwr_status = power_on ? 0 : 2; + + if (hws->ctx->dc->debug.disable_hubp_power_gate) + return; + + switch (hubp_inst) { + case 0: /* DCHUBP0 */ + REG_UPDATE(DOMAIN0_PG_CONFIG, + DOMAIN0_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN0_PG_STATUS, + DOMAIN0_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 1: /* DCHUBP1 */ + REG_UPDATE(DOMAIN2_PG_CONFIG, + DOMAIN2_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN2_PG_STATUS, + DOMAIN2_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 2: /* DCHUBP2 */ + REG_UPDATE(DOMAIN4_PG_CONFIG, + DOMAIN4_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN4_PG_STATUS, + DOMAIN4_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + case 3: /* DCHUBP3 */ + REG_UPDATE(DOMAIN6_PG_CONFIG, + DOMAIN6_POWER_GATE, power_gate); + + REG_WAIT(DOMAIN6_PG_STATUS, + DOMAIN6_PGFSM_PWR_STATUS, pwr_status, + 1, 1000); + break; + default: + BREAK_TO_DEBUGGER(); + break; + } +} + +static void power_on_plane( + struct dce_hwseq *hws, + int plane_id) +{ + if (REG(DC_IP_REQUEST_CNTL)) { + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + dpp_pg_control(hws, plane_id, true); + hubp_pg_control(hws, plane_id, true); + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + dm_logger_write(hws->ctx->logger, LOG_DEBUG, + "Un-gated front end for pipe %d\n", plane_id); + } +} + +static void undo_DEGVIDCN10_253_wa(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = dc->res_pool->hubps[0]; + + if (!hws->wa_state.DEGVIDCN10_253_applied) + return; + + hubp->funcs->set_blank(hubp, true); + + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + + hubp_pg_control(hws, 0, false); + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + + hws->wa_state.DEGVIDCN10_253_applied = false; +} + +static void apply_DEGVIDCN10_253_wa(struct dc *dc) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = dc->res_pool->hubps[0]; + int i; + + if (dc->debug.disable_stutter) + return; + + if (!hws->wa.DEGVIDCN10_253) + return; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + if (!dc->res_pool->hubps[i]->power_gated) + return; + } + + /* all pipe power gated, apply work around to enable stutter. */ + + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + + hubp_pg_control(hws, 0, true); + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + + hubp->funcs->set_hubp_blank_en(hubp, false); + hws->wa_state.DEGVIDCN10_253_applied = true; +} + +static void bios_golden_init(struct dc *dc) +{ + struct dc_bios *bp = dc->ctx->dc_bios; + int i; + + /* initialize dcn global */ + bp->funcs->enable_disp_power_gating(bp, + CONTROLLER_ID_D0, ASIC_PIPE_INIT); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + /* initialize dcn per pipe */ + bp->funcs->enable_disp_power_gating(bp, + CONTROLLER_ID_D0 + i, ASIC_PIPE_DISABLE); + } +} + +static void false_optc_underflow_wa( + struct dc *dc, + const struct dc_stream_state *stream, + struct timing_generator *tg) +{ + int i; + bool underflow; + + if (!dc->hwseq->wa.false_optc_underflow) + return; + + underflow = tg->funcs->is_optc_underflow_occurred(tg); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *old_pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i]; + + if (old_pipe_ctx->stream != stream) + continue; + + dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, old_pipe_ctx); + } + + tg->funcs->set_blank_data_double_buffer(tg, true); + + if (tg->funcs->is_optc_underflow_occurred(tg) && !underflow) + tg->funcs->clear_optc_underflow(tg); +} + +static enum dc_status dcn10_prog_pixclk_crtc_otg( + struct pipe_ctx *pipe_ctx, + struct dc_state *context, + struct dc *dc) +{ + struct dc_stream_state *stream = pipe_ctx->stream; + enum dc_color_space color_space; + struct tg_color black_color = {0}; + + /* by upper caller loop, pipe0 is parent pipe and be called first. + * back end is set up by for pipe0. Other children pipe share back end + * with pipe 0. No program is needed. + */ + if (pipe_ctx->top_pipe != NULL) + return DC_OK; + + /* TODO check if timing_changed, disable stream if timing changed */ + + /* HW program guide assume display already disable + * by unplug sequence. OTG assume stop. + */ + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, true); + + if (false == pipe_ctx->clock_source->funcs->program_pix_clk( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + &pipe_ctx->pll_settings)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; + pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; + pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset; + pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width; + + pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal; + + pipe_ctx->stream_res.tg->funcs->program_timing( + pipe_ctx->stream_res.tg, + &stream->timing, + true); + +#if 0 /* move to after enable_crtc */ + /* TODO: OPP FMT, ABM. etc. should be done here. */ + /* or FPGA now. instance 0 only. TODO: move to opp.c */ + + inst_offset = reg_offsets[pipe_ctx->stream_res.tg->inst].fmt; + + pipe_ctx->stream_res.opp->funcs->opp_program_fmt( + pipe_ctx->stream_res.opp, + &stream->bit_depth_params, + &stream->clamping); +#endif + /* program otg blank color */ + color_space = stream->output_color_space; + color_space_to_black_color(dc, color_space, &black_color); + + if (pipe_ctx->stream_res.tg->funcs->set_blank_color) + pipe_ctx->stream_res.tg->funcs->set_blank_color( + pipe_ctx->stream_res.tg, + &black_color); + + if (pipe_ctx->stream_res.tg->funcs->is_blanked && + !pipe_ctx->stream_res.tg->funcs->is_blanked(pipe_ctx->stream_res.tg)) { + pipe_ctx->stream_res.tg->funcs->set_blank(pipe_ctx->stream_res.tg, true); + hwss_wait_for_blank_complete(pipe_ctx->stream_res.tg); + false_optc_underflow_wa(dc, pipe_ctx->stream, pipe_ctx->stream_res.tg); + } + + /* VTG is within DCHUB command block. DCFCLK is always on */ + if (false == pipe_ctx->stream_res.tg->funcs->enable_crtc(pipe_ctx->stream_res.tg)) { + BREAK_TO_DEBUGGER(); + return DC_ERROR_UNEXPECTED; + } + + /* TODO program crtc source select for non-virtual signal*/ + /* TODO program FMT */ + /* TODO setup link_enc */ + /* TODO set stream attributes */ + /* TODO program audio */ + /* TODO enable stream if timing changed */ + /* TODO unblank stream if DP */ + + return DC_OK; +} + +static void reset_back_end_for_pipe( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + int i; + + if (pipe_ctx->stream_res.stream_enc == NULL) { + pipe_ctx->stream = NULL; + return; + } + + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + /* DPMS may already disable */ + if (!pipe_ctx->stream->dpms_off) + core_link_disable_stream(pipe_ctx, FREE_ACQUIRED_RESOURCE); + } + + /* by upper caller loop, parent pipe: pipe0, will be reset last. + * back end share by all pipes and will be disable only when disable + * parent pipe. + */ + if (pipe_ctx->top_pipe == NULL) { + pipe_ctx->stream_res.tg->funcs->disable_crtc(pipe_ctx->stream_res.tg); + + pipe_ctx->stream_res.tg->funcs->enable_optc_clock(pipe_ctx->stream_res.tg, false); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) + if (&dc->current_state->res_ctx.pipe_ctx[i] == pipe_ctx) + break; + + if (i == dc->res_pool->pipe_count) + return; + + pipe_ctx->stream = NULL; + dm_logger_write(dc->ctx->logger, LOG_DEBUG, + "Reset back end for pipe %d, tg:%d\n", + pipe_ctx->pipe_idx, pipe_ctx->stream_res.tg->inst); +} + +static void dcn10_verify_allow_pstate_change_high(struct dc *dc) +{ + static bool should_log_hw_state; /* prevent hw state log by default */ + + if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) { + if (should_log_hw_state) { + dcn10_log_hw_state(dc); + } + + BREAK_TO_DEBUGGER(); + } +} + +/* trigger HW to start disconnect plane from stream on the next vsync */ +static void plane_atomic_disconnect(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + int fe_idx = pipe_ctx->pipe_idx; + struct hubp *hubp = dc->res_pool->hubps[fe_idx]; + struct mpc *mpc = dc->res_pool->mpc; + int opp_id; + struct mpc_tree *mpc_tree_params; + struct mpcc *mpcc_to_remove = NULL; + + /* look at tree rather than mi here to know if we already reset */ + for (opp_id = 0; opp_id < dc->res_pool->pipe_count; opp_id++) { + struct output_pixel_processor *opp = dc->res_pool->opps[opp_id]; + + mpc_tree_params = &(opp->mpc_tree_params); + mpcc_to_remove = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, fe_idx); + if (mpcc_to_remove != NULL) + break; + } + + /*Already reset*/ + if (opp_id == dc->res_pool->pipe_count) + return; + + mpc->funcs->remove_mpcc(mpc, mpc_tree_params, mpcc_to_remove); + dc->res_pool->opps[opp_id]->mpcc_disconnect_pending[fe_idx] = true; + + dc->optimized_required = true; + + if (hubp->funcs->hubp_disconnect) + hubp->funcs->hubp_disconnect(hubp); + + if (dc->debug.sanity_checks) + dcn10_verify_allow_pstate_change_high(dc); +} + +static void plane_atomic_power_down(struct dc *dc, int fe_idx) +{ + struct dce_hwseq *hws = dc->hwseq; + struct dpp *dpp = dc->res_pool->dpps[fe_idx]; + + if (REG(DC_IP_REQUEST_CNTL)) { + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 1); + dpp_pg_control(hws, fe_idx, false); + hubp_pg_control(hws, fe_idx, false); + dpp->funcs->dpp_reset(dpp); + REG_SET(DC_IP_REQUEST_CNTL, 0, + IP_REQUEST_EN, 0); + dm_logger_write(dc->ctx->logger, LOG_DEBUG, + "Power gated front end %d\n", fe_idx); + } +} + +/* disable HW used by plane. + * note: cannot disable until disconnect is complete + */ +static void plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + int fe_idx = pipe_ctx->pipe_idx; + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = dc->res_pool->hubps[fe_idx]; + int opp_id = hubp->opp_id; + + dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx); + + REG_UPDATE(HUBP_CLK_CNTL[fe_idx], + HUBP_CLOCK_ENABLE, 0); + REG_UPDATE(DPP_CONTROL[fe_idx], + DPP_CLOCK_ENABLE, 0); + + if (opp_id != 0xf && dc->res_pool->opps[opp_id]->mpc_tree_params.opp_list == NULL) + REG_UPDATE(OPP_PIPE_CONTROL[opp_id], + OPP_PIPE_CLOCK_EN, 0); + + hubp->power_gated = true; + dc->optimized_required = false; /* We're powering off, no need to optimize */ + + plane_atomic_power_down(dc, fe_idx); + + pipe_ctx->stream = NULL; + memset(&pipe_ctx->stream_res, 0, sizeof(pipe_ctx->stream_res)); + memset(&pipe_ctx->plane_res, 0, sizeof(pipe_ctx->plane_res)); + pipe_ctx->top_pipe = NULL; + pipe_ctx->bottom_pipe = NULL; + pipe_ctx->plane_state = NULL; +} + +static void dcn10_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + if (dc->res_pool->hubps[pipe_ctx->pipe_idx]->power_gated) + return; + + plane_atomic_disable(dc, pipe_ctx); + + apply_DEGVIDCN10_253_wa(dc); + + dm_logger_write(dc->ctx->logger, LOG_DC, + "Power down front end %d\n", + pipe_ctx->pipe_idx); +} + +static void dcn10_init_hw(struct dc *dc) +{ + int i; + struct abm *abm = dc->res_pool->abm; + struct dmcu *dmcu = dc->res_pool->dmcu; + struct dce_hwseq *hws = dc->hwseq; + struct dc_bios *dcb = dc->ctx->dc_bios; + struct dc_state *context = dc->current_state; + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + REG_WRITE(REFCLK_CNTL, 0); + REG_UPDATE(DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_ENABLE, 1); + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + enable_power_gating_plane(dc->hwseq, true); + return; + } + /* end of FPGA. Below if real ASIC */ + + if (!dcb->funcs->is_accelerated_mode(dcb)) { + bios_golden_init(dc); + disable_vga(dc->hwseq); + } + + for (i = 0; i < dc->link_count; i++) { + /* Power up AND update implementation according to the + * required signal (which may be different from the + * default signal on connector). + */ + struct dc_link *link = dc->links[i]; + + if (link->link_enc->connector.id == CONNECTOR_ID_EDP) + dc->hwss.edp_power_control(link, true); + + link->link_enc->funcs->hw_init(link->link_enc); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->lock(tg); + } + + /* Blank controller using driver code instead of + * command table. + */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) { + tg->funcs->set_blank(tg, true); + hwss_wait_for_blank_complete(tg); + } + } + + /* Reset all MPCC muxes */ + dc->res_pool->mpc->funcs->mpc_init(dc->res_pool->mpc); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct hubp *hubp = dc->res_pool->hubps[i]; + + pipe_ctx->stream_res.tg = tg; + pipe_ctx->pipe_idx = i; + + pipe_ctx->plane_res.hubp = hubp; + hubp->mpcc_id = i; + hubp->opp_id = 0xf; + hubp->power_gated = false; + + dc->res_pool->opps[i]->mpc_tree_params.opp_id = dc->res_pool->opps[i]->inst; + dc->res_pool->opps[i]->mpc_tree_params.opp_list = NULL; + dc->res_pool->opps[i]->mpcc_disconnect_pending[i] = true; + pipe_ctx->stream_res.opp = dc->res_pool->opps[i]; + + plane_atomic_disconnect(dc, pipe_ctx); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + + if (tg->funcs->is_tg_enabled(tg)) + tg->funcs->unlock(tg); + } + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct timing_generator *tg = dc->res_pool->timing_generators[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + dcn10_disable_plane(dc, pipe_ctx); + + pipe_ctx->stream_res.tg = NULL; + pipe_ctx->plane_res.hubp = NULL; + + tg->funcs->tg_init(tg); + } + + for (i = 0; i < dc->res_pool->audio_count; i++) { + struct audio *audio = dc->res_pool->audios[i]; + + audio->funcs->hw_init(audio); + } + + if (abm != NULL) { + abm->funcs->init_backlight(abm); + abm->funcs->abm_init(abm); + } + + if (dmcu != NULL) + dmcu->funcs->dmcu_init(dmcu); + + /* power AFMT HDMI memory TODO: may move to dis/en output save power*/ + REG_WRITE(DIO_MEM_PWR_CTRL, 0); + + if (!dc->debug.disable_clock_gate) { + /* enable all DCN clock gating */ + REG_WRITE(DCCG_GATE_DISABLE_CNTL, 0); + + REG_WRITE(DCCG_GATE_DISABLE_CNTL2, 0); + + REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0); + } + + enable_power_gating_plane(dc->hwseq, true); +} + +static void reset_hw_ctx_wrap( + struct dc *dc, + struct dc_state *context) +{ + int i; + + /* Reset Back End*/ + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx_old->stream) + continue; + + if (pipe_ctx_old->top_pipe) + continue; + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) { + struct clock_source *old_clk = pipe_ctx_old->clock_source; + + reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_state); + if (old_clk) + old_clk->funcs->cs_power_down(old_clk); + } + } + +} + +static bool patch_address_for_sbs_tb_stereo( + struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + bool sec_split = pipe_ctx->top_pipe && + pipe_ctx->top_pipe->plane_state == pipe_ctx->plane_state; + if (sec_split && plane_state->address.type == PLN_ADDR_TYPE_GRPH_STEREO && + (pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_SIDE_BY_SIDE || + pipe_ctx->stream->timing.timing_3d_format == + TIMING_3D_FORMAT_TOP_AND_BOTTOM)) { + *addr = plane_state->address.grph_stereo.left_addr; + plane_state->address.grph_stereo.left_addr = + plane_state->address.grph_stereo.right_addr; + return true; + } else { + if (pipe_ctx->stream->view_format != VIEW_3D_FORMAT_NONE && + plane_state->address.type != PLN_ADDR_TYPE_GRPH_STEREO) { + plane_state->address.type = PLN_ADDR_TYPE_GRPH_STEREO; + plane_state->address.grph_stereo.right_addr = + plane_state->address.grph_stereo.left_addr; + } + } + return false; +} + + + +static void dcn10_update_plane_addr(const struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + bool addr_patched = false; + PHYSICAL_ADDRESS_LOC addr; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + + if (plane_state == NULL) + return; + addr_patched = patch_address_for_sbs_tb_stereo(pipe_ctx, &addr); + pipe_ctx->plane_res.hubp->funcs->hubp_program_surface_flip_and_addr( + pipe_ctx->plane_res.hubp, + &plane_state->address, + plane_state->flip_immediate); + plane_state->status.requested_address = plane_state->address; + if (addr_patched) + pipe_ctx->plane_state->address.grph_stereo.left_addr = addr; +} + +static bool dcn10_set_input_transfer_func(struct pipe_ctx *pipe_ctx, + const struct dc_plane_state *plane_state) +{ + struct dpp *dpp_base = pipe_ctx->plane_res.dpp; + const struct dc_transfer_func *tf = NULL; + bool result = true; + + if (dpp_base == NULL) + return false; + + if (plane_state->in_transfer_func) + tf = plane_state->in_transfer_func; + + if (plane_state->gamma_correction && dce_use_lut(plane_state)) + dpp_base->funcs->dpp_program_input_lut(dpp_base, plane_state->gamma_correction); + + if (tf == NULL) + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); + else if (tf->type == TF_TYPE_PREDEFINED) { + switch (tf->tf) { + case TRANSFER_FUNCTION_SRGB: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_sRGB); + break; + case TRANSFER_FUNCTION_BT709: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_HW_xvYCC); + break; + case TRANSFER_FUNCTION_LINEAR: + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); + break; + case TRANSFER_FUNCTION_PQ: + default: + result = false; + break; + } + } else if (tf->type == TF_TYPE_BYPASS) { + dpp_base->funcs->dpp_set_degamma(dpp_base, IPP_DEGAMMA_MODE_BYPASS); + } else { + /*TF_TYPE_DISTRIBUTED_POINTS*/ + result = false; + } + + return result; +} + + + + + +static bool +dcn10_set_output_transfer_func(struct pipe_ctx *pipe_ctx, + const struct dc_stream_state *stream) +{ + struct dpp *dpp = pipe_ctx->plane_res.dpp; + + if (dpp == NULL) + return false; + + dpp->regamma_params.hw_points_num = GAMMA_HW_POINTS_NUM; + + if (stream->out_transfer_func && + stream->out_transfer_func->type == TF_TYPE_PREDEFINED && + stream->out_transfer_func->tf == TRANSFER_FUNCTION_SRGB) + dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_SRGB); + + /* dcn10_translate_regamma_to_hw_format takes 750us, only do it when full + * update. + */ + else if (cm_helper_translate_curve_to_hw_format( + stream->out_transfer_func, + &dpp->regamma_params, false)) { + dpp->funcs->dpp_program_regamma_pwl( + dpp, + &dpp->regamma_params, OPP_REGAMMA_USER); + } else + dpp->funcs->dpp_program_regamma_pwl(dpp, NULL, OPP_REGAMMA_BYPASS); + + return true; +} + +static void dcn10_pipe_control_lock( + struct dc *dc, + struct pipe_ctx *pipe, + bool lock) +{ + struct hubp *hubp = NULL; + hubp = dc->res_pool->hubps[pipe->pipe_idx]; + /* use TG master update lock to lock everything on the TG + * therefore only top pipe need to lock + */ + if (pipe->top_pipe) + return; + + if (dc->debug.sanity_checks) + dcn10_verify_allow_pstate_change_high(dc); + + if (lock) + pipe->stream_res.tg->funcs->lock(pipe->stream_res.tg); + else + pipe->stream_res.tg->funcs->unlock(pipe->stream_res.tg); + + if (dc->debug.sanity_checks) + dcn10_verify_allow_pstate_change_high(dc); +} + +static bool wait_for_reset_trigger_to_occur( + struct dc_context *dc_ctx, + struct timing_generator *tg) +{ + bool rc = false; + + /* To avoid endless loop we wait at most + * frames_to_wait_on_triggered_reset frames for the reset to occur. */ + const uint32_t frames_to_wait_on_triggered_reset = 10; + int i; + + for (i = 0; i < frames_to_wait_on_triggered_reset; i++) { + + if (!tg->funcs->is_counter_moving(tg)) { + DC_ERROR("TG counter is not moving!\n"); + break; + } + + if (tg->funcs->did_triggered_reset_occur(tg)) { + rc = true; + /* usually occurs at i=1 */ + DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n", + i); + break; + } + + /* Wait for one frame. */ + tg->funcs->wait_for_state(tg, CRTC_STATE_VACTIVE); + tg->funcs->wait_for_state(tg, CRTC_STATE_VBLANK); + } + + if (false == rc) + DC_ERROR("GSL: Timeout on reset trigger!\n"); + + return rc; +} + +static void dcn10_enable_timing_synchronization( + struct dc *dc, + int group_index, + int group_size, + struct pipe_ctx *grouped_pipes[]) +{ + struct dc_context *dc_ctx = dc->ctx; + int i; + + DC_SYNC_INFO("Setting up OTG reset trigger\n"); + + for (i = 1; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->enable_reset_trigger( + grouped_pipes[i]->stream_res.tg, + grouped_pipes[0]->stream_res.tg->inst); + + DC_SYNC_INFO("Waiting for trigger\n"); + + /* Need to get only check 1 pipe for having reset as all the others are + * synchronized. Look at last pipe programmed to reset. + */ + + wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[1]->stream_res.tg); + for (i = 1; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->disable_reset_trigger( + grouped_pipes[i]->stream_res.tg); + + DC_SYNC_INFO("Sync complete\n"); +} + +static void dcn10_enable_per_frame_crtc_position_reset( + struct dc *dc, + int group_size, + struct pipe_ctx *grouped_pipes[]) +{ + struct dc_context *dc_ctx = dc->ctx; + int i; + + DC_SYNC_INFO("Setting up\n"); + for (i = 0; i < group_size; i++) + grouped_pipes[i]->stream_res.tg->funcs->enable_crtc_reset( + grouped_pipes[i]->stream_res.tg, + grouped_pipes[i]->stream->triggered_crtc_reset.event_source->status.primary_otg_inst, + &grouped_pipes[i]->stream->triggered_crtc_reset); + + DC_SYNC_INFO("Waiting for trigger\n"); + + for (i = 1; i < group_size; i++) + wait_for_reset_trigger_to_occur(dc_ctx, grouped_pipes[i]->stream_res.tg); + + DC_SYNC_INFO("Multi-display sync is complete\n"); +} + +/*static void print_rq_dlg_ttu( + struct dc *core_dc, + struct pipe_ctx *pipe_ctx) +{ + dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + "\n============== DML TTU Output parameters [%d] ==============\n" + "qos_level_low_wm: %d, \n" + "qos_level_high_wm: %d, \n" + "min_ttu_vblank: %d, \n" + "qos_level_flip: %d, \n" + "refcyc_per_req_delivery_l: %d, \n" + "qos_level_fixed_l: %d, \n" + "qos_ramp_disable_l: %d, \n" + "refcyc_per_req_delivery_pre_l: %d, \n" + "refcyc_per_req_delivery_c: %d, \n" + "qos_level_fixed_c: %d, \n" + "qos_ramp_disable_c: %d, \n" + "refcyc_per_req_delivery_pre_c: %d\n" + "=============================================================\n", + pipe_ctx->pipe_idx, + pipe_ctx->ttu_regs.qos_level_low_wm, + pipe_ctx->ttu_regs.qos_level_high_wm, + pipe_ctx->ttu_regs.min_ttu_vblank, + pipe_ctx->ttu_regs.qos_level_flip, + pipe_ctx->ttu_regs.refcyc_per_req_delivery_l, + pipe_ctx->ttu_regs.qos_level_fixed_l, + pipe_ctx->ttu_regs.qos_ramp_disable_l, + pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_l, + pipe_ctx->ttu_regs.refcyc_per_req_delivery_c, + pipe_ctx->ttu_regs.qos_level_fixed_c, + pipe_ctx->ttu_regs.qos_ramp_disable_c, + pipe_ctx->ttu_regs.refcyc_per_req_delivery_pre_c + ); + + dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + "\n============== DML DLG Output parameters [%d] ==============\n" + "refcyc_h_blank_end: %d, \n" + "dlg_vblank_end: %d, \n" + "min_dst_y_next_start: %d, \n" + "refcyc_per_htotal: %d, \n" + "refcyc_x_after_scaler: %d, \n" + "dst_y_after_scaler: %d, \n" + "dst_y_prefetch: %d, \n" + "dst_y_per_vm_vblank: %d, \n" + "dst_y_per_row_vblank: %d, \n" + "ref_freq_to_pix_freq: %d, \n" + "vratio_prefetch: %d, \n" + "refcyc_per_pte_group_vblank_l: %d, \n" + "refcyc_per_meta_chunk_vblank_l: %d, \n" + "dst_y_per_pte_row_nom_l: %d, \n" + "refcyc_per_pte_group_nom_l: %d, \n", + pipe_ctx->pipe_idx, + pipe_ctx->dlg_regs.refcyc_h_blank_end, + pipe_ctx->dlg_regs.dlg_vblank_end, + pipe_ctx->dlg_regs.min_dst_y_next_start, + pipe_ctx->dlg_regs.refcyc_per_htotal, + pipe_ctx->dlg_regs.refcyc_x_after_scaler, + pipe_ctx->dlg_regs.dst_y_after_scaler, + pipe_ctx->dlg_regs.dst_y_prefetch, + pipe_ctx->dlg_regs.dst_y_per_vm_vblank, + pipe_ctx->dlg_regs.dst_y_per_row_vblank, + pipe_ctx->dlg_regs.ref_freq_to_pix_freq, + pipe_ctx->dlg_regs.vratio_prefetch, + pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_l, + pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_l, + pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_l, + pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_l + ); + + dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + "\ndst_y_per_meta_row_nom_l: %d, \n" + "refcyc_per_meta_chunk_nom_l: %d, \n" + "refcyc_per_line_delivery_pre_l: %d, \n" + "refcyc_per_line_delivery_l: %d, \n" + "vratio_prefetch_c: %d, \n" + "refcyc_per_pte_group_vblank_c: %d, \n" + "refcyc_per_meta_chunk_vblank_c: %d, \n" + "dst_y_per_pte_row_nom_c: %d, \n" + "refcyc_per_pte_group_nom_c: %d, \n" + "dst_y_per_meta_row_nom_c: %d, \n" + "refcyc_per_meta_chunk_nom_c: %d, \n" + "refcyc_per_line_delivery_pre_c: %d, \n" + "refcyc_per_line_delivery_c: %d \n" + "========================================================\n", + pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_l, + pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_l, + pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_l, + pipe_ctx->dlg_regs.refcyc_per_line_delivery_l, + pipe_ctx->dlg_regs.vratio_prefetch_c, + pipe_ctx->dlg_regs.refcyc_per_pte_group_vblank_c, + pipe_ctx->dlg_regs.refcyc_per_meta_chunk_vblank_c, + pipe_ctx->dlg_regs.dst_y_per_pte_row_nom_c, + pipe_ctx->dlg_regs.refcyc_per_pte_group_nom_c, + pipe_ctx->dlg_regs.dst_y_per_meta_row_nom_c, + pipe_ctx->dlg_regs.refcyc_per_meta_chunk_nom_c, + pipe_ctx->dlg_regs.refcyc_per_line_delivery_pre_c, + pipe_ctx->dlg_regs.refcyc_per_line_delivery_c + ); + + dm_logger_write(core_dc->ctx->logger, LOG_BANDWIDTH_CALCS, + "\n============== DML RQ Output parameters [%d] ==============\n" + "chunk_size: %d \n" + "min_chunk_size: %d \n" + "meta_chunk_size: %d \n" + "min_meta_chunk_size: %d \n" + "dpte_group_size: %d \n" + "mpte_group_size: %d \n" + "swath_height: %d \n" + "pte_row_height_linear: %d \n" + "========================================================\n", + pipe_ctx->pipe_idx, + pipe_ctx->rq_regs.rq_regs_l.chunk_size, + pipe_ctx->rq_regs.rq_regs_l.min_chunk_size, + pipe_ctx->rq_regs.rq_regs_l.meta_chunk_size, + pipe_ctx->rq_regs.rq_regs_l.min_meta_chunk_size, + pipe_ctx->rq_regs.rq_regs_l.dpte_group_size, + pipe_ctx->rq_regs.rq_regs_l.mpte_group_size, + pipe_ctx->rq_regs.rq_regs_l.swath_height, + pipe_ctx->rq_regs.rq_regs_l.pte_row_height_linear + ); +} +*/ + +static void mmhub_read_vm_system_aperture_settings(struct dcn10_hubp *hubp1, + struct vm_system_aperture_param *apt, + struct dce_hwseq *hws) +{ + PHYSICAL_ADDRESS_LOC physical_page_number; + uint32_t logical_addr_low; + uint32_t logical_addr_high; + + REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_MSB, + PHYSICAL_PAGE_NUMBER_MSB, &physical_page_number.high_part); + REG_GET(MC_VM_SYSTEM_APERTURE_DEFAULT_ADDR_LSB, + PHYSICAL_PAGE_NUMBER_LSB, &physical_page_number.low_part); + + REG_GET(MC_VM_SYSTEM_APERTURE_LOW_ADDR, + LOGICAL_ADDR, &logical_addr_low); + + REG_GET(MC_VM_SYSTEM_APERTURE_HIGH_ADDR, + LOGICAL_ADDR, &logical_addr_high); + + apt->sys_default.quad_part = physical_page_number.quad_part << 12; + apt->sys_low.quad_part = (int64_t)logical_addr_low << 18; + apt->sys_high.quad_part = (int64_t)logical_addr_high << 18; +} + +/* Temporary read settings, future will get values from kmd directly */ +static void mmhub_read_vm_context0_settings(struct dcn10_hubp *hubp1, + struct vm_context0_param *vm0, + struct dce_hwseq *hws) +{ + PHYSICAL_ADDRESS_LOC fb_base; + PHYSICAL_ADDRESS_LOC fb_offset; + uint32_t fb_base_value; + uint32_t fb_offset_value; + + REG_GET(DCHUBBUB_SDPIF_FB_BASE, SDPIF_FB_BASE, &fb_base_value); + REG_GET(DCHUBBUB_SDPIF_FB_OFFSET, SDPIF_FB_OFFSET, &fb_offset_value); + + REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_HI32, + PAGE_DIRECTORY_ENTRY_HI32, &vm0->pte_base.high_part); + REG_GET(VM_CONTEXT0_PAGE_TABLE_BASE_ADDR_LO32, + PAGE_DIRECTORY_ENTRY_LO32, &vm0->pte_base.low_part); + + REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_HI32, + LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_start.high_part); + REG_GET(VM_CONTEXT0_PAGE_TABLE_START_ADDR_LO32, + LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_start.low_part); + + REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_HI32, + LOGICAL_PAGE_NUMBER_HI4, &vm0->pte_end.high_part); + REG_GET(VM_CONTEXT0_PAGE_TABLE_END_ADDR_LO32, + LOGICAL_PAGE_NUMBER_LO32, &vm0->pte_end.low_part); + + REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_HI32, + PHYSICAL_PAGE_ADDR_HI4, &vm0->fault_default.high_part); + REG_GET(VM_L2_PROTECTION_FAULT_DEFAULT_ADDR_LO32, + PHYSICAL_PAGE_ADDR_LO32, &vm0->fault_default.low_part); + + /* + * The values in VM_CONTEXT0_PAGE_TABLE_BASE_ADDR is in UMA space. + * Therefore we need to do + * DCN_VM_CONTEXT0_PAGE_TABLE_BASE_ADDR = VM_CONTEXT0_PAGE_TABLE_BASE_ADDR + * - DCHUBBUB_SDPIF_FB_OFFSET + DCHUBBUB_SDPIF_FB_BASE + */ + fb_base.quad_part = (uint64_t)fb_base_value << 24; + fb_offset.quad_part = (uint64_t)fb_offset_value << 24; + vm0->pte_base.quad_part += fb_base.quad_part; + vm0->pte_base.quad_part -= fb_offset.quad_part; +} + + +static void dcn10_program_pte_vm(struct dce_hwseq *hws, struct hubp *hubp) +{ + struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp); + struct vm_system_aperture_param apt = { {{ 0 } } }; + struct vm_context0_param vm0 = { { { 0 } } }; + + mmhub_read_vm_system_aperture_settings(hubp1, &apt, hws); + mmhub_read_vm_context0_settings(hubp1, &vm0, hws); + + hubp->funcs->hubp_set_vm_system_aperture_settings(hubp, &apt); + hubp->funcs->hubp_set_vm_context0_settings(hubp, &vm0); +} + +static void dcn10_enable_plane( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + + if (dc->debug.sanity_checks) { + dcn10_verify_allow_pstate_change_high(dc); + } + + undo_DEGVIDCN10_253_wa(dc); + + power_on_plane(dc->hwseq, + pipe_ctx->pipe_idx); + + /* enable DCFCLK current DCHUB */ + REG_UPDATE(HUBP_CLK_CNTL[pipe_ctx->pipe_idx], + HUBP_CLOCK_ENABLE, 1); + + /* make sure OPP_PIPE_CLOCK_EN = 1 */ + REG_UPDATE(OPP_PIPE_CONTROL[pipe_ctx->stream_res.tg->inst], + OPP_PIPE_CLOCK_EN, 1); + +/* TODO: enable/disable in dm as per update type. + if (plane_state) { + dm_logger_write(dc->ctx->logger, LOG_DC, + "Pipe:%d 0x%x: addr hi:0x%x, " + "addr low:0x%x, " + "src: %d, %d, %d," + " %d; dst: %d, %d, %d, %d;\n", + pipe_ctx->pipe_idx, + plane_state, + plane_state->address.grph.addr.high_part, + plane_state->address.grph.addr.low_part, + plane_state->src_rect.x, + plane_state->src_rect.y, + plane_state->src_rect.width, + plane_state->src_rect.height, + plane_state->dst_rect.x, + plane_state->dst_rect.y, + plane_state->dst_rect.width, + plane_state->dst_rect.height); + + dm_logger_write(dc->ctx->logger, LOG_DC, + "Pipe %d: width, height, x, y format:%d\n" + "viewport:%d, %d, %d, %d\n" + "recout: %d, %d, %d, %d\n", + pipe_ctx->pipe_idx, + plane_state->format, + pipe_ctx->plane_res.scl_data.viewport.width, + pipe_ctx->plane_res.scl_data.viewport.height, + pipe_ctx->plane_res.scl_data.viewport.x, + pipe_ctx->plane_res.scl_data.viewport.y, + pipe_ctx->plane_res.scl_data.recout.width, + pipe_ctx->plane_res.scl_data.recout.height, + pipe_ctx->plane_res.scl_data.recout.x, + pipe_ctx->plane_res.scl_data.recout.y); + print_rq_dlg_ttu(dc, pipe_ctx); + } +*/ + if (dc->config.gpu_vm_support) + dcn10_program_pte_vm(hws, pipe_ctx->plane_res.hubp); + + if (dc->debug.sanity_checks) { + dcn10_verify_allow_pstate_change_high(dc); + } +} + +static void program_gamut_remap(struct pipe_ctx *pipe_ctx) +{ + struct dpp_grph_csc_adjustment adjust; + memset(&adjust, 0, sizeof(adjust)); + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS; + + + if (pipe_ctx->stream->gamut_remap_matrix.enable_remap == true) { + adjust.gamut_adjust_type = GRAPHICS_GAMUT_ADJUST_TYPE_SW; + adjust.temperature_matrix[0] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[0]; + adjust.temperature_matrix[1] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[1]; + adjust.temperature_matrix[2] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[2]; + adjust.temperature_matrix[3] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[4]; + adjust.temperature_matrix[4] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[5]; + adjust.temperature_matrix[5] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[6]; + adjust.temperature_matrix[6] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[8]; + adjust.temperature_matrix[7] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[9]; + adjust.temperature_matrix[8] = + pipe_ctx->stream-> + gamut_remap_matrix.matrix[10]; + } + + pipe_ctx->plane_res.dpp->funcs->dpp_set_gamut_remap(pipe_ctx->plane_res.dpp, &adjust); +} + + +static void program_csc_matrix(struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix) +{ + if (pipe_ctx->stream->csc_color_matrix.enable_adjustment == true) { + if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) + pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment(pipe_ctx->plane_res.dpp, matrix); + } else { + if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default != NULL) + pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_default(pipe_ctx->plane_res.dpp, colorspace); + } +} + +static void program_output_csc(struct dc *dc, + struct pipe_ctx *pipe_ctx, + enum dc_color_space colorspace, + uint16_t *matrix, + int opp_id) +{ + if (pipe_ctx->plane_res.dpp->funcs->dpp_set_csc_adjustment != NULL) + program_csc_matrix(pipe_ctx, + colorspace, + matrix); +} + +static bool is_lower_pipe_tree_visible(struct pipe_ctx *pipe_ctx) +{ + if (pipe_ctx->plane_state->visible) + return true; + if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) + return true; + return false; +} + +static bool is_upper_pipe_tree_visible(struct pipe_ctx *pipe_ctx) +{ + if (pipe_ctx->plane_state->visible) + return true; + if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) + return true; + return false; +} + +static bool is_pipe_tree_visible(struct pipe_ctx *pipe_ctx) +{ + if (pipe_ctx->plane_state->visible) + return true; + if (pipe_ctx->top_pipe && is_upper_pipe_tree_visible(pipe_ctx->top_pipe)) + return true; + if (pipe_ctx->bottom_pipe && is_lower_pipe_tree_visible(pipe_ctx->bottom_pipe)) + return true; + return false; +} + +static bool is_rgb_cspace(enum dc_color_space output_color_space) +{ + switch (output_color_space) { + case COLOR_SPACE_SRGB: + case COLOR_SPACE_SRGB_LIMITED: + case COLOR_SPACE_2020_RGB_FULLRANGE: + case COLOR_SPACE_2020_RGB_LIMITEDRANGE: + case COLOR_SPACE_ADOBERGB: + return true; + case COLOR_SPACE_YCBCR601: + case COLOR_SPACE_YCBCR709: + case COLOR_SPACE_YCBCR601_LIMITED: + case COLOR_SPACE_YCBCR709_LIMITED: + case COLOR_SPACE_2020_YCBCR: + return false; + default: + /* Add a case to switch */ + BREAK_TO_DEBUGGER(); + return false; + } +} + +static void dcn10_get_surface_visual_confirm_color( + const struct pipe_ctx *pipe_ctx, + struct tg_color *color) +{ + uint32_t color_value = MAX_TG_COLOR_VALUE; + + switch (pipe_ctx->plane_res.scl_data.format) { + case PIXEL_FORMAT_ARGB8888: + /* set boarder color to red */ + color->color_r_cr = color_value; + break; + + case PIXEL_FORMAT_ARGB2101010: + /* set boarder color to blue */ + color->color_b_cb = color_value; + break; + case PIXEL_FORMAT_420BPP8: + /* set boarder color to green */ + color->color_g_y = color_value; + break; + case PIXEL_FORMAT_420BPP10: + /* set boarder color to yellow */ + color->color_g_y = color_value; + color->color_r_cr = color_value; + break; + case PIXEL_FORMAT_FP16: + /* set boarder color to white */ + color->color_r_cr = color_value; + color->color_b_cb = color_value; + color->color_g_y = color_value; + break; + default: + break; + } +} + +static uint16_t fixed_point_to_int_frac( + struct fixed31_32 arg, + uint8_t integer_bits, + uint8_t fractional_bits) +{ + int32_t numerator; + int32_t divisor = 1 << fractional_bits; + + uint16_t result; + + uint16_t d = (uint16_t)dal_fixed31_32_floor( + dal_fixed31_32_abs( + arg)); + + if (d <= (uint16_t)(1 << integer_bits) - (1 / (uint16_t)divisor)) + numerator = (uint16_t)dal_fixed31_32_floor( + dal_fixed31_32_mul_int( + arg, + divisor)); + else { + numerator = dal_fixed31_32_floor( + dal_fixed31_32_sub( + dal_fixed31_32_from_int( + 1LL << integer_bits), + dal_fixed31_32_recip( + dal_fixed31_32_from_int( + divisor)))); + } + + if (numerator >= 0) + result = (uint16_t)numerator; + else + result = (uint16_t)( + (1 << (integer_bits + fractional_bits + 1)) + numerator); + + if ((result != 0) && dal_fixed31_32_lt( + arg, dal_fixed31_32_zero)) + result |= 1 << (integer_bits + fractional_bits); + + return result; +} + +void build_prescale_params(struct dc_bias_and_scale *bias_and_scale, + const struct dc_plane_state *plane_state) +{ + if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN + && plane_state->format != SURFACE_PIXEL_FORMAT_INVALID + && plane_state->input_csc_color_matrix.enable_adjustment + && plane_state->coeff_reduction_factor.value != 0) { + bias_and_scale->scale_blue = fixed_point_to_int_frac( + dal_fixed31_32_mul(plane_state->coeff_reduction_factor, + dal_fixed31_32_from_fraction(256, 255)), + 2, + 13); + bias_and_scale->scale_red = bias_and_scale->scale_blue; + bias_and_scale->scale_green = bias_and_scale->scale_blue; + } else { + bias_and_scale->scale_blue = 0x2000; + bias_and_scale->scale_red = 0x2000; + bias_and_scale->scale_green = 0x2000; + } +} + +static void update_dpp(struct dpp *dpp, struct dc_plane_state *plane_state) +{ + struct dc_bias_and_scale bns_params = {0}; + + // program the input csc + dpp->funcs->dpp_setup(dpp, + plane_state->format, + EXPANSION_MODE_ZERO, + plane_state->input_csc_color_matrix, + COLOR_SPACE_YCBCR601_LIMITED); + + //set scale and bias registers + build_prescale_params(&bns_params, plane_state); + if (dpp->funcs->dpp_program_bias_and_scale) + dpp->funcs->dpp_program_bias_and_scale(dpp, &bns_params); +} + +static void update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx) +{ + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct mpcc_blnd_cfg blnd_cfg; + bool per_pixel_alpha = pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; + int mpcc_id; + struct mpcc *new_mpcc; + struct mpc *mpc = dc->res_pool->mpc; + struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params); + + /* TODO: proper fix once fpga works */ + + if (dc->debug.surface_visual_confirm) + dcn10_get_surface_visual_confirm_color( + pipe_ctx, &blnd_cfg.black_color); + else + color_space_to_black_color( + dc, pipe_ctx->stream->output_color_space, + &blnd_cfg.black_color); + + if (per_pixel_alpha) + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA; + else + blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA; + + blnd_cfg.overlap_only = false; + blnd_cfg.global_alpha = 0xff; + blnd_cfg.global_gain = 0xff; + + /* DCN1.0 has output CM before MPC which seems to screw with + * pre-multiplied alpha. + */ + blnd_cfg.pre_multiplied_alpha = is_rgb_cspace( + pipe_ctx->stream->output_color_space) + && per_pixel_alpha; + + /* + * TODO: remove hack + * Note: currently there is a bug in init_hw such that + * on resume from hibernate, BIOS sets up MPCC0, and + * we do mpcc_remove but the mpcc cannot go to idle + * after remove. This cause us to pick mpcc1 here, + * which causes a pstate hang for yet unknown reason. + */ + mpcc_id = hubp->inst; + + /* check if this MPCC is already being used */ + new_mpcc = mpc->funcs->get_mpcc_for_dpp(mpc_tree_params, mpcc_id); + /* remove MPCC if being used */ + if (new_mpcc != NULL) + mpc->funcs->remove_mpcc(mpc, mpc_tree_params, new_mpcc); + else + if (dc->debug.sanity_checks) + mpc->funcs->assert_mpcc_idle_before_connect( + dc->res_pool->mpc, mpcc_id); + + /* Call MPC to insert new plane */ + new_mpcc = mpc->funcs->insert_plane(dc->res_pool->mpc, + mpc_tree_params, + &blnd_cfg, + NULL, + NULL, + hubp->inst, + mpcc_id); + + ASSERT(new_mpcc != NULL); + + hubp->opp_id = pipe_ctx->stream_res.opp->inst; + hubp->mpcc_id = mpcc_id; +} + +static void update_scaler(struct pipe_ctx *pipe_ctx) +{ + bool per_pixel_alpha = + pipe_ctx->plane_state->per_pixel_alpha && pipe_ctx->bottom_pipe; + + /* TODO: proper fix once fpga works */ + + pipe_ctx->plane_res.scl_data.lb_params.alpha_en = per_pixel_alpha; + pipe_ctx->plane_res.scl_data.lb_params.depth = LB_PIXEL_DEPTH_30BPP; + /* scaler configuration */ + pipe_ctx->plane_res.dpp->funcs->dpp_set_scaler( + pipe_ctx->plane_res.dpp, &pipe_ctx->plane_res.scl_data); +} + +static void update_dchubp_dpp( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + struct dce_hwseq *hws = dc->hwseq; + struct hubp *hubp = pipe_ctx->plane_res.hubp; + struct dpp *dpp = pipe_ctx->plane_res.dpp; + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + union plane_size size = plane_state->plane_size; + + /* depends on DML calculation, DPP clock value may change dynamically */ + if (plane_state->update_flags.bits.full_update) { + enable_dppclk( + dc->hwseq, + pipe_ctx->pipe_idx, + pipe_ctx->stream_res.pix_clk_params.requested_pix_clk, + context->bw.dcn.calc_clk.dppclk_div); + dc->current_state->bw.dcn.cur_clk.dppclk_div = + context->bw.dcn.calc_clk.dppclk_div; + context->bw.dcn.cur_clk.dppclk_div = context->bw.dcn.calc_clk.dppclk_div; + } + + /* TODO: Need input parameter to tell current DCHUB pipe tie to which OTG + * VTG is within DCHUBBUB which is commond block share by each pipe HUBP. + * VTG is 1:1 mapping with OTG. Each pipe HUBP will select which VTG + */ + if (plane_state->update_flags.bits.full_update) { + REG_UPDATE(DCHUBP_CNTL[pipe_ctx->pipe_idx], HUBP_VTG_SEL, pipe_ctx->stream_res.tg->inst); + + hubp->funcs->hubp_setup( + hubp, + &pipe_ctx->dlg_regs, + &pipe_ctx->ttu_regs, + &pipe_ctx->rq_regs, + &pipe_ctx->pipe_dlg_param); + } + + size.grph.surface_size = pipe_ctx->plane_res.scl_data.viewport; + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.bpp_change) + update_dpp(dpp, plane_state); + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.per_pixel_alpha_change) + update_mpcc(dc, pipe_ctx); + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.per_pixel_alpha_change || + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.position_change) { + update_scaler(pipe_ctx); + } + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.scaling_change || + plane_state->update_flags.bits.position_change) { + hubp->funcs->mem_program_viewport( + hubp, + &pipe_ctx->plane_res.scl_data.viewport, + &pipe_ctx->plane_res.scl_data.viewport_c); + } + + if (plane_state->update_flags.bits.full_update) { + /*gamut remap*/ + program_gamut_remap(pipe_ctx); + + program_output_csc(dc, + pipe_ctx, + pipe_ctx->stream->output_color_space, + pipe_ctx->stream->csc_color_matrix.matrix, + hubp->opp_id); + } + + if (plane_state->update_flags.bits.full_update || + plane_state->update_flags.bits.horizontal_mirror_change || + plane_state->update_flags.bits.rotation_change || + plane_state->update_flags.bits.swizzle_change || + plane_state->update_flags.bits.dcc_change || + plane_state->update_flags.bits.bpp_change || + plane_state->update_flags.bits.scaling_change) { + hubp->funcs->hubp_program_surface_config( + hubp, + plane_state->format, + &plane_state->tiling_info, + &size, + plane_state->rotation, + &plane_state->dcc, + plane_state->horizontal_mirror); + } + + hubp->power_gated = false; + + dc->hwss.update_plane_addr(dc, pipe_ctx); + + if (is_pipe_tree_visible(pipe_ctx)) + hubp->funcs->set_blank(hubp, false); +} + + +static void program_all_pipe_in_tree( + struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct dc_state *context) +{ + + if (pipe_ctx->top_pipe == NULL) { + + pipe_ctx->stream_res.tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; + pipe_ctx->stream_res.tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; + pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_offset = pipe_ctx->pipe_dlg_param.vupdate_offset; + pipe_ctx->stream_res.tg->dlg_otg_param.vupdate_width = pipe_ctx->pipe_dlg_param.vupdate_width; + pipe_ctx->stream_res.tg->dlg_otg_param.signal = pipe_ctx->stream->signal; + + pipe_ctx->stream_res.tg->funcs->program_global_sync( + pipe_ctx->stream_res.tg); + + if (pipe_ctx->stream_res.tg->funcs->set_blank) + pipe_ctx->stream_res.tg->funcs->set_blank( + pipe_ctx->stream_res.tg, + !is_pipe_tree_visible(pipe_ctx)); + } + + if (pipe_ctx->plane_state != NULL) { + struct pipe_ctx *cur_pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[pipe_ctx->pipe_idx]; + + if (pipe_ctx->plane_state->update_flags.bits.full_update) + dcn10_enable_plane(dc, pipe_ctx, context); + + update_dchubp_dpp(dc, pipe_ctx, context); + + if (cur_pipe_ctx->plane_state != pipe_ctx->plane_state) + dc->hwss.set_input_transfer_func(pipe_ctx, pipe_ctx->plane_state); + + /* dcn10_translate_regamma_to_hw_format takes 750us to finish + * only do gamma programming for full update. + * TODO: This can be further optimized/cleaned up + * Always call this for now since it does memcmp inside before + * doing heavy calculation and programming + */ + if (pipe_ctx->plane_state->update_flags.bits.full_update) + dc->hwss.set_output_transfer_func(pipe_ctx, pipe_ctx->stream); + } + + if (pipe_ctx->bottom_pipe != NULL && pipe_ctx->bottom_pipe != pipe_ctx) + program_all_pipe_in_tree(dc, pipe_ctx->bottom_pipe, context); +} + +static void dcn10_pplib_apply_display_requirements( + struct dc *dc, + struct dc_state *context) +{ + struct dm_pp_display_configuration *pp_display_cfg = &context->pp_display_cfg; + + pp_display_cfg->all_displays_in_sync = false;/*todo*/ + pp_display_cfg->nb_pstate_switch_disable = false; + pp_display_cfg->min_engine_clock_khz = context->bw.dcn.cur_clk.dcfclk_khz; + pp_display_cfg->min_memory_clock_khz = context->bw.dcn.cur_clk.fclk_khz; + pp_display_cfg->min_engine_clock_deep_sleep_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; + pp_display_cfg->min_dcfc_deep_sleep_clock_khz = context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz; + pp_display_cfg->avail_mclk_switch_time_us = + context->bw.dcn.cur_clk.dram_ccm_us > 0 ? context->bw.dcn.cur_clk.dram_ccm_us : 0; + pp_display_cfg->avail_mclk_switch_time_in_disp_active_us = + context->bw.dcn.cur_clk.min_active_dram_ccm_us > 0 ? context->bw.dcn.cur_clk.min_active_dram_ccm_us : 0; + pp_display_cfg->min_dcfclock_khz = context->bw.dcn.cur_clk.dcfclk_khz; + pp_display_cfg->disp_clk_khz = context->bw.dcn.cur_clk.dispclk_khz; + dce110_fill_display_configs(context, pp_display_cfg); + + if (memcmp(&dc->prev_display_config, pp_display_cfg, sizeof( + struct dm_pp_display_configuration)) != 0) + dm_pp_apply_display_requirements(dc->ctx, pp_display_cfg); + + dc->prev_display_config = *pp_display_cfg; +} + +static void optimize_shared_resources(struct dc *dc) +{ + if (dc->current_state->stream_count == 0) { + /* S0i2 message */ + dcn10_pplib_apply_display_requirements(dc, dc->current_state); + } + + if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) + dcn_bw_notify_pplib_of_wm_ranges(dc); +} + +static void ready_shared_resources(struct dc *dc, struct dc_state *context) +{ + /* S0i2 message */ + if (dc->current_state->stream_count == 0 && + context->stream_count != 0) + dcn10_pplib_apply_display_requirements(dc, context); +} + +static struct pipe_ctx *find_top_pipe_for_stream( + struct dc *dc, + struct dc_state *context, + const struct dc_stream_state *stream) +{ + int i; + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *old_pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + + if (!pipe_ctx->plane_state && !old_pipe_ctx->plane_state) + continue; + + if (pipe_ctx->stream != stream) + continue; + + if (!pipe_ctx->top_pipe) + return pipe_ctx; + } + return NULL; +} + +static void dcn10_apply_ctx_for_surface( + struct dc *dc, + const struct dc_stream_state *stream, + int num_planes, + struct dc_state *context) +{ + int i; + struct timing_generator *tg; + struct output_pixel_processor *opp; + bool removed_pipe[4] = { false }; + unsigned int ref_clk_mhz = dc->res_pool->ref_clock_inKhz/1000; + bool program_water_mark = false; + + struct pipe_ctx *top_pipe_to_program = + find_top_pipe_for_stream(dc, context, stream); + + if (!top_pipe_to_program) + return; + + opp = top_pipe_to_program->stream_res.opp; + + tg = top_pipe_to_program->stream_res.tg; + + tg->funcs->lock(tg); + + if (num_planes == 0) { + + /* OTG blank before remove all front end */ + if (tg->funcs->set_blank) + tg->funcs->set_blank(tg, true); + } + + /* Disconnect unused mpcc */ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + struct pipe_ctx *old_pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + /* + * Powergate reused pipes that are not powergated + * fairly hacky right now, using opp_id as indicator + * TODO: After move dc_post to dc_update, this will + * be removed. + */ + if (pipe_ctx->plane_state && !old_pipe_ctx->plane_state) { + if (old_pipe_ctx->stream_res.tg == tg && + old_pipe_ctx->plane_res.hubp && + old_pipe_ctx->plane_res.hubp->opp_id != 0xf) { + dcn10_disable_plane(dc, pipe_ctx); + /* + * power down fe will unlock when calling reset, need + * to lock it back here. Messy, need rework. + */ + pipe_ctx->stream_res.tg->funcs->lock(pipe_ctx->stream_res.tg); + } + } + + if (!pipe_ctx->plane_state && + old_pipe_ctx->plane_state && + old_pipe_ctx->stream_res.tg == tg) { + + plane_atomic_disconnect(dc, old_pipe_ctx); + removed_pipe[i] = true; + + dm_logger_write(dc->ctx->logger, LOG_DC, + "Reset mpcc for pipe %d\n", + old_pipe_ctx->pipe_idx); + } + } + + if (num_planes > 0) + program_all_pipe_in_tree(dc, top_pipe_to_program, context); + + tg->funcs->unlock(tg); + + if (num_planes == 0) + false_optc_underflow_wa(dc, stream, tg); + + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *old_pipe_ctx = + &dc->current_state->res_ctx.pipe_ctx[i]; + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + + if (pipe_ctx->stream == stream && + pipe_ctx->plane_state && + pipe_ctx->plane_state->update_flags.bits.full_update) + program_water_mark = true; + + if (removed_pipe[i]) + dcn10_disable_plane(dc, old_pipe_ctx); + } + + if (program_water_mark) { + if (dc->debug.sanity_checks) { + /* pstate stuck check after watermark update */ + dcn10_verify_allow_pstate_change_high(dc); + } + + /* watermark is for all pipes */ + hubbub1_program_watermarks(dc->res_pool->hubbub, + &context->bw.dcn.watermarks, ref_clk_mhz); + + if (dc->debug.sanity_checks) { + /* pstate stuck check after watermark update */ + dcn10_verify_allow_pstate_change_high(dc); + } + } +/* dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, + "\n============== Watermark parameters ==============\n" + "a.urgent_ns: %d \n" + "a.cstate_enter_plus_exit: %d \n" + "a.cstate_exit: %d \n" + "a.pstate_change: %d \n" + "a.pte_meta_urgent: %d \n" + "b.urgent_ns: %d \n" + "b.cstate_enter_plus_exit: %d \n" + "b.cstate_exit: %d \n" + "b.pstate_change: %d \n" + "b.pte_meta_urgent: %d \n", + context->bw.dcn.watermarks.a.urgent_ns, + context->bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns, + context->bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns, + context->bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns, + context->bw.dcn.watermarks.a.pte_meta_urgent_ns, + context->bw.dcn.watermarks.b.urgent_ns, + context->bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns, + context->bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns, + context->bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns, + context->bw.dcn.watermarks.b.pte_meta_urgent_ns + ); + dm_logger_write(dc->ctx->logger, LOG_BANDWIDTH_CALCS, + "\nc.urgent_ns: %d \n" + "c.cstate_enter_plus_exit: %d \n" + "c.cstate_exit: %d \n" + "c.pstate_change: %d \n" + "c.pte_meta_urgent: %d \n" + "d.urgent_ns: %d \n" + "d.cstate_enter_plus_exit: %d \n" + "d.cstate_exit: %d \n" + "d.pstate_change: %d \n" + "d.pte_meta_urgent: %d \n" + "========================================================\n", + context->bw.dcn.watermarks.c.urgent_ns, + context->bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns, + context->bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns, + context->bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns, + context->bw.dcn.watermarks.c.pte_meta_urgent_ns, + context->bw.dcn.watermarks.d.urgent_ns, + context->bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns, + context->bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns, + context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns, + context->bw.dcn.watermarks.d.pte_meta_urgent_ns + ); +*/ +} + +static void dcn10_set_bandwidth( + struct dc *dc, + struct dc_state *context, + bool decrease_allowed) +{ + struct pp_smu_display_requirement_rv *smu_req_cur = + &dc->res_pool->pp_smu_req; + struct pp_smu_display_requirement_rv smu_req = *smu_req_cur; + struct pp_smu_funcs_rv *pp_smu = dc->res_pool->pp_smu; + + if (dc->debug.sanity_checks) { + dcn10_verify_allow_pstate_change_high(dc); + } + + if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) + return; + + if (decrease_allowed || context->bw.dcn.calc_clk.dispclk_khz + > dc->current_state->bw.dcn.cur_clk.dispclk_khz) { + dc->res_pool->display_clock->funcs->set_clock( + dc->res_pool->display_clock, + context->bw.dcn.calc_clk.dispclk_khz); + dc->current_state->bw.dcn.cur_clk.dispclk_khz = + context->bw.dcn.calc_clk.dispclk_khz; + } + if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_khz + > dc->current_state->bw.dcn.cur_clk.dcfclk_khz) { + smu_req.hard_min_dcefclk_khz = + context->bw.dcn.calc_clk.dcfclk_khz; + } + if (decrease_allowed || context->bw.dcn.calc_clk.fclk_khz + > dc->current_state->bw.dcn.cur_clk.fclk_khz) { + smu_req.hard_min_fclk_khz = context->bw.dcn.calc_clk.fclk_khz; + } + if (decrease_allowed || context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz + > dc->current_state->bw.dcn.cur_clk.dcfclk_deep_sleep_khz) { + dc->current_state->bw.dcn.calc_clk.dcfclk_deep_sleep_khz = + context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; + context->bw.dcn.cur_clk.dcfclk_deep_sleep_khz = + context->bw.dcn.calc_clk.dcfclk_deep_sleep_khz; + } + + smu_req.display_count = context->stream_count; + + if (pp_smu->set_display_requirement) + pp_smu->set_display_requirement(&pp_smu->pp_smu, &smu_req); + + *smu_req_cur = smu_req; + + /* Decrease in freq is increase in period so opposite comparison for dram_ccm */ + if (decrease_allowed || context->bw.dcn.calc_clk.dram_ccm_us + < dc->current_state->bw.dcn.cur_clk.dram_ccm_us) { + dc->current_state->bw.dcn.calc_clk.dram_ccm_us = + context->bw.dcn.calc_clk.dram_ccm_us; + context->bw.dcn.cur_clk.dram_ccm_us = + context->bw.dcn.calc_clk.dram_ccm_us; + } + if (decrease_allowed || context->bw.dcn.calc_clk.min_active_dram_ccm_us + < dc->current_state->bw.dcn.cur_clk.min_active_dram_ccm_us) { + dc->current_state->bw.dcn.calc_clk.min_active_dram_ccm_us = + context->bw.dcn.calc_clk.min_active_dram_ccm_us; + context->bw.dcn.cur_clk.min_active_dram_ccm_us = + context->bw.dcn.calc_clk.min_active_dram_ccm_us; + } + dcn10_pplib_apply_display_requirements(dc, context); + + if (dc->debug.sanity_checks) { + dcn10_verify_allow_pstate_change_high(dc); + } + + /* need to fix this function. not doing the right thing here */ +} + +static void set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, int vmin, int vmax) +{ + int i = 0; + struct drr_params params = {0}; + + params.vertical_total_max = vmax; + params.vertical_total_min = vmin; + + /* TODO: If multiple pipes are to be supported, you need + * some GSL stuff + */ + for (i = 0; i < num_pipes; i++) { + pipe_ctx[i]->stream_res.tg->funcs->set_drr(pipe_ctx[i]->stream_res.tg, ¶ms); + } +} + +static void get_position(struct pipe_ctx **pipe_ctx, + int num_pipes, + struct crtc_position *position) +{ + int i = 0; + + /* TODO: handle pipes > 1 + */ + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs->get_position(pipe_ctx[i]->stream_res.tg, position); +} + +static void set_static_screen_control(struct pipe_ctx **pipe_ctx, + int num_pipes, const struct dc_static_screen_events *events) +{ + unsigned int i; + unsigned int value = 0; + + if (events->surface_update) + value |= 0x80; + if (events->cursor_update) + value |= 0x2; + + for (i = 0; i < num_pipes; i++) + pipe_ctx[i]->stream_res.tg->funcs-> + set_static_screen_control(pipe_ctx[i]->stream_res.tg, value); +} + +static void set_plane_config( + const struct dc *dc, + struct pipe_ctx *pipe_ctx, + struct resource_context *res_ctx) +{ + /* TODO */ + program_gamut_remap(pipe_ctx); +} + +static void dcn10_config_stereo_parameters( + struct dc_stream_state *stream, struct crtc_stereo_flags *flags) +{ + enum view_3d_format view_format = stream->view_format; + enum dc_timing_3d_format timing_3d_format =\ + stream->timing.timing_3d_format; + bool non_stereo_timing = false; + + if (timing_3d_format == TIMING_3D_FORMAT_NONE || + timing_3d_format == TIMING_3D_FORMAT_SIDE_BY_SIDE || + timing_3d_format == TIMING_3D_FORMAT_TOP_AND_BOTTOM) + non_stereo_timing = true; + + if (non_stereo_timing == false && + view_format == VIEW_3D_FORMAT_FRAME_SEQUENTIAL) { + + flags->PROGRAM_STEREO = 1; + flags->PROGRAM_POLARITY = 1; + if (timing_3d_format == TIMING_3D_FORMAT_INBAND_FA || + timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA || + timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) { + enum display_dongle_type dongle = \ + stream->sink->link->ddc->dongle_type; + if (dongle == DISPLAY_DONGLE_DP_VGA_CONVERTER || + dongle == DISPLAY_DONGLE_DP_DVI_CONVERTER || + dongle == DISPLAY_DONGLE_DP_HDMI_CONVERTER) + flags->DISABLE_STEREO_DP_SYNC = 1; + } + flags->RIGHT_EYE_POLARITY =\ + stream->timing.flags.RIGHT_EYE_3D_POLARITY; + if (timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) + flags->FRAME_PACKED = 1; + } + + return; +} + +static void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc) +{ + struct crtc_stereo_flags flags = { 0 }; + struct dc_stream_state *stream = pipe_ctx->stream; + + dcn10_config_stereo_parameters(stream, &flags); + + pipe_ctx->stream_res.opp->funcs->opp_program_stereo( + pipe_ctx->stream_res.opp, + flags.PROGRAM_STEREO == 1 ? true:false, + &stream->timing); + + pipe_ctx->stream_res.tg->funcs->program_stereo( + pipe_ctx->stream_res.tg, + &stream->timing, + &flags); + + return; +} + +static void dcn10_wait_for_mpcc_disconnect( + struct dc *dc, + struct resource_pool *res_pool, + struct pipe_ctx *pipe_ctx) +{ + int i; + + if (dc->debug.sanity_checks) { + dcn10_verify_allow_pstate_change_high(dc); + } + + if (!pipe_ctx->stream_res.opp) + return; + + for (i = 0; i < MAX_PIPES; i++) { + if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[i]) { + res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, i); + pipe_ctx->stream_res.opp->mpcc_disconnect_pending[i] = false; + res_pool->hubps[i]->funcs->set_blank(res_pool->hubps[i], true); + /*dm_logger_write(dc->ctx->logger, LOG_ERROR, + "[debug_mpo: wait_for_mpcc finished waiting on mpcc %d]\n", + i);*/ + } + } + + if (dc->debug.sanity_checks) { + dcn10_verify_allow_pstate_change_high(dc); + } + +} + +static bool dcn10_dummy_display_power_gating( + struct dc *dc, + uint8_t controller_id, + struct dc_bios *dcb, + enum pipe_gating_control power_gating) +{ + return true; +} + +void dcn10_update_pending_status(struct pipe_ctx *pipe_ctx) +{ + struct dc_plane_state *plane_state = pipe_ctx->plane_state; + struct timing_generator *tg = pipe_ctx->stream_res.tg; + + if (plane_state == NULL) + return; + + plane_state->status.is_flip_pending = + pipe_ctx->plane_res.hubp->funcs->hubp_is_flip_pending( + pipe_ctx->plane_res.hubp); + + plane_state->status.current_address = pipe_ctx->plane_res.hubp->current_address; + if (pipe_ctx->plane_res.hubp->current_address.type == PLN_ADDR_TYPE_GRPH_STEREO && + tg->funcs->is_stereo_left_eye) { + plane_state->status.is_right_eye = + !tg->funcs->is_stereo_left_eye(pipe_ctx->stream_res.tg); + } +} + +void dcn10_update_dchub(struct dce_hwseq *hws, struct dchub_init_data *dh_data) +{ + if (hws->ctx->dc->res_pool->hubbub != NULL) + hubbub1_update_dchub(hws->ctx->dc->res_pool->hubbub, dh_data); +} + +static const struct hw_sequencer_funcs dcn10_funcs = { + .program_gamut_remap = program_gamut_remap, + .program_csc_matrix = program_csc_matrix, + .init_hw = dcn10_init_hw, + .apply_ctx_to_hw = dce110_apply_ctx_to_hw, + .apply_ctx_for_surface = dcn10_apply_ctx_for_surface, + .set_plane_config = set_plane_config, + .update_plane_addr = dcn10_update_plane_addr, + .update_dchub = dcn10_update_dchub, + .update_pending_status = dcn10_update_pending_status, + .set_input_transfer_func = dcn10_set_input_transfer_func, + .set_output_transfer_func = dcn10_set_output_transfer_func, + .power_down = dce110_power_down, + .enable_accelerated_mode = dce110_enable_accelerated_mode, + .enable_timing_synchronization = dcn10_enable_timing_synchronization, + .enable_per_frame_crtc_position_reset = dcn10_enable_per_frame_crtc_position_reset, + .update_info_frame = dce110_update_info_frame, + .enable_stream = dce110_enable_stream, + .disable_stream = dce110_disable_stream, + .unblank_stream = dce110_unblank_stream, + .enable_display_power_gating = dcn10_dummy_display_power_gating, + .disable_plane = dcn10_disable_plane, + .pipe_control_lock = dcn10_pipe_control_lock, + .set_bandwidth = dcn10_set_bandwidth, + .reset_hw_ctx_wrap = reset_hw_ctx_wrap, + .prog_pixclk_crtc_otg = dcn10_prog_pixclk_crtc_otg, + .set_drr = set_drr, + .get_position = get_position, + .set_static_screen_control = set_static_screen_control, + .setup_stereo = dcn10_setup_stereo, + .set_avmute = dce110_set_avmute, + .log_hw_state = dcn10_log_hw_state, + .wait_for_mpcc_disconnect = dcn10_wait_for_mpcc_disconnect, + .ready_shared_resources = ready_shared_resources, + .optimize_shared_resources = optimize_shared_resources, + .pplib_apply_display_requirements = + dcn10_pplib_apply_display_requirements, + .edp_backlight_control = hwss_edp_backlight_control, + .edp_power_control = hwss_edp_power_control, + .edp_wait_for_hpd_ready = hwss_edp_wait_for_hpd_ready, +}; + + +void dcn10_hw_sequencer_construct(struct dc *dc) +{ + dc->hwss = dcn10_funcs; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h new file mode 100644 index 000000000000..b9d326082717 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h @@ -0,0 +1,39 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_HWSS_DCN10_H__ +#define __DC_HWSS_DCN10_H__ + +#include "core_types.h" + +struct dc; + +void dcn10_hw_sequencer_construct(struct dc *dc); +extern void fill_display_configs( + const struct dc_state *context, + struct dm_pp_display_configuration *pp_display_cfg); + + +#endif /* __DC_HWSS_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c new file mode 100644 index 000000000000..08db1e6b5166 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c @@ -0,0 +1,70 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dcn10_ipp.h" +#include "reg_helper.h" + +#define REG(reg) \ + (ippn10->regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + ippn10->ipp_shift->field_name, ippn10->ipp_mask->field_name + +#define CTX \ + ippn10->base.ctx + +/*****************************************/ +/* Constructor, Destructor */ +/*****************************************/ + +static void dcn10_ipp_destroy(struct input_pixel_processor **ipp) +{ + kfree(TO_DCN10_IPP(*ipp)); + *ipp = NULL; +} + +static const struct ipp_funcs dcn10_ipp_funcs = { + .ipp_destroy = dcn10_ipp_destroy +}; + +void dcn10_ipp_construct( + struct dcn10_ipp *ippn10, + struct dc_context *ctx, + int inst, + const struct dcn10_ipp_registers *regs, + const struct dcn10_ipp_shift *ipp_shift, + const struct dcn10_ipp_mask *ipp_mask) +{ + ippn10->base.ctx = ctx; + ippn10->base.inst = inst; + ippn10->base.funcs = &dcn10_ipp_funcs; + + ippn10->regs = regs; + ippn10->ipp_shift = ipp_shift; + ippn10->ipp_mask = ipp_mask; +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h new file mode 100644 index 000000000000..d7b5bd20352a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h @@ -0,0 +1,167 @@ +/* + * Copyright 2017 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef _DCN10_IPP_H_ +#define _DCN10_IPP_H_ + +#include "ipp.h" + +#define TO_DCN10_IPP(ipp)\ + container_of(ipp, struct dcn10_ipp, base) + +#define IPP_REG_LIST_DCN(id) \ + SRI(FORMAT_CONTROL, CNVC_CFG, id), \ + SRI(DPP_CONTROL, DPP_TOP, id), \ + SRI(CNVC_SURFACE_PIXEL_FORMAT, CNVC_CFG, id), \ + SRI(CURSOR0_CONTROL, CNVC_CUR, id), \ + SRI(CURSOR0_COLOR0, CNVC_CUR, id), \ + SRI(CURSOR0_COLOR1, CNVC_CUR, id) + +#define IPP_REG_LIST_DCN10(id) \ + IPP_REG_LIST_DCN(id), \ + SRI(CURSOR_SETTINS, HUBPREQ, id), \ + SRI(CURSOR_SURFACE_ADDRESS_HIGH, CURSOR, id), \ + SRI(CURSOR_SURFACE_ADDRESS, CURSOR, id), \ + SRI(CURSOR_SIZE, CURSOR, id), \ + SRI(CURSOR_CONTROL, CURSOR, id), \ + SRI(CURSOR_POSITION, CURSOR, id), \ + SRI(CURSOR_HOT_SPOT, CURSOR, id), \ + SRI(CURSOR_DST_OFFSET, CURSOR, id) + +#define CURSOR0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY__SHIFT 0x4 +#define CURSOR0_CURSOR_CONTROL__CURSOR_2X_MAGNIFY_MASK 0x00000010L +#define CURSOR1_CURSOR_CONTROL__CURSOR_2X_MAGNIFY__SHIFT 0x4 +#define CURSOR1_CURSOR_CONTROL__CURSOR_2X_MAGNIFY_MASK 0x00000010L +#define CURSOR2_CURSOR_CONTROL__CURSOR_2X_MAGNIFY__SHIFT 0x4 +#define CURSOR2_CURSOR_CONTROL__CURSOR_2X_MAGNIFY_MASK 0x00000010L +#define CURSOR3_CURSOR_CONTROL__CURSOR_2X_MAGNIFY__SHIFT 0x4 +#define CURSOR3_CURSOR_CONTROL__CURSOR_2X_MAGNIFY_MASK 0x00000010L + +#define IPP_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define IPP_MASK_SH_LIST_DCN(mask_sh) \ + IPP_SF(CNVC_CFG0_CNVC_SURFACE_PIXEL_FORMAT, CNVC_SURFACE_PIXEL_FORMAT, mask_sh), \ + IPP_SF(CNVC_CFG0_FORMAT_CONTROL, CNVC_BYPASS, mask_sh), \ + IPP_SF(CNVC_CFG0_FORMAT_CONTROL, ALPHA_EN, mask_sh), \ + IPP_SF(CNVC_CFG0_FORMAT_CONTROL, FORMAT_EXPANSION_MODE, mask_sh), \ + IPP_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_MODE, mask_sh), \ + IPP_SF(CNVC_CUR0_CURSOR0_COLOR0, CUR0_COLOR0, mask_sh), \ + IPP_SF(CNVC_CUR0_CURSOR0_COLOR1, CUR0_COLOR1, mask_sh), \ + IPP_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_EXPANSION_MODE, mask_sh), \ + IPP_SF(CNVC_CUR0_CURSOR0_CONTROL, CUR0_ENABLE, mask_sh) + +#define IPP_MASK_SH_LIST_DCN10(mask_sh) \ + IPP_MASK_SH_LIST_DCN(mask_sh),\ + IPP_SF(HUBPREQ0_CURSOR_SETTINS, CURSOR0_DST_Y_OFFSET, mask_sh), \ + IPP_SF(HUBPREQ0_CURSOR_SETTINS, CURSOR0_CHUNK_HDL_ADJUST, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_SURFACE_ADDRESS_HIGH, CURSOR_SURFACE_ADDRESS_HIGH, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_SURFACE_ADDRESS, CURSOR_SURFACE_ADDRESS, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_SIZE, CURSOR_WIDTH, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_SIZE, CURSOR_HEIGHT, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_MODE, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_2X_MAGNIFY, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_PITCH, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_LINES_PER_CHUNK, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_CONTROL, CURSOR_ENABLE, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_POSITION, CURSOR_X_POSITION, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_POSITION, CURSOR_Y_POSITION, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_X, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_HOT_SPOT, CURSOR_HOT_SPOT_Y, mask_sh), \ + IPP_SF(CURSOR0_CURSOR_DST_OFFSET, CURSOR_DST_X_OFFSET, mask_sh), \ + IPP_SF(CNVC_CFG0_FORMAT_CONTROL, OUTPUT_FP, mask_sh) + +#define IPP_DCN10_REG_FIELD_LIST(type) \ + type CNVC_SURFACE_PIXEL_FORMAT; \ + type CNVC_BYPASS; \ + type ALPHA_EN; \ + type FORMAT_EXPANSION_MODE; \ + type CURSOR0_DST_Y_OFFSET; \ + type CURSOR0_CHUNK_HDL_ADJUST; \ + type CUR0_MODE; \ + type CUR0_COLOR0; \ + type CUR0_COLOR1; \ + type CUR0_EXPANSION_MODE; \ + type CURSOR_SURFACE_ADDRESS_HIGH; \ + type CURSOR_SURFACE_ADDRESS; \ + type CURSOR_WIDTH; \ + type CURSOR_HEIGHT; \ + type CURSOR_MODE; \ + type CURSOR_2X_MAGNIFY; \ + type CURSOR_PITCH; \ + type CURSOR_LINES_PER_CHUNK; \ + type CURSOR_ENABLE; \ + type CUR0_ENABLE; \ + type CURSOR_X_POSITION; \ + type CURSOR_Y_POSITION; \ + type CURSOR_HOT_SPOT_X; \ + type CURSOR_HOT_SPOT_Y; \ + type CURSOR_DST_X_OFFSET; \ + type OUTPUT_FP + +struct dcn10_ipp_shift { + IPP_DCN10_REG_FIELD_LIST(uint8_t); +}; + +struct dcn10_ipp_mask { + IPP_DCN10_REG_FIELD_LIST(uint32_t); +}; + +struct dcn10_ipp_registers { + uint32_t DPP_CONTROL; + uint32_t CURSOR_SETTINS; + uint32_t CURSOR_SETTINGS; + uint32_t CNVC_SURFACE_PIXEL_FORMAT; + uint32_t CURSOR0_CONTROL; + uint32_t CURSOR0_COLOR0; + uint32_t CURSOR0_COLOR1; + uint32_t FORMAT_CONTROL; + uint32_t CURSOR_SURFACE_ADDRESS_HIGH; + uint32_t CURSOR_SURFACE_ADDRESS; + uint32_t CURSOR_SIZE; + uint32_t CURSOR_CONTROL; + uint32_t CURSOR_POSITION; + uint32_t CURSOR_HOT_SPOT; + uint32_t CURSOR_DST_OFFSET; +}; + +struct dcn10_ipp { + struct input_pixel_processor base; + + const struct dcn10_ipp_registers *regs; + const struct dcn10_ipp_shift *ipp_shift; + const struct dcn10_ipp_mask *ipp_mask; + + struct dc_cursor_attributes curs_attr; +}; + +void dcn10_ipp_construct(struct dcn10_ipp *ippn10, + struct dc_context *ctx, + int inst, + const struct dcn10_ipp_registers *regs, + const struct dcn10_ipp_shift *ipp_shift, + const struct dcn10_ipp_mask *ipp_mask); + +#endif /* _DCN10_IPP_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c new file mode 100644 index 000000000000..179890b1a8c4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c @@ -0,0 +1,446 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "reg_helper.h" +#include "dcn10_mpc.h" + +#define REG(reg)\ + mpc10->mpc_regs->reg + +#define CTX \ + mpc10->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + mpc10->mpc_shift->field_name, mpc10->mpc_mask->field_name + + +void mpc1_set_bg_color(struct mpc *mpc, + struct tg_color *bg_color, + int mpcc_id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + + /* mpc color is 12 bit. tg_color is 10 bit */ + /* todo: might want to use 16 bit to represent color and have each + * hw block translate to correct color depth. + */ + uint32_t bg_r_cr = bg_color->color_r_cr << 2; + uint32_t bg_g_y = bg_color->color_g_y << 2; + uint32_t bg_b_cb = bg_color->color_b_cb << 2; + + REG_SET(MPCC_BG_R_CR[mpcc_id], 0, + MPCC_BG_R_CR, bg_r_cr); + REG_SET(MPCC_BG_G_Y[mpcc_id], 0, + MPCC_BG_G_Y, bg_g_y); + REG_SET(MPCC_BG_B_CB[mpcc_id], 0, + MPCC_BG_B_CB, bg_b_cb); +} + +static void mpc1_update_blending( + struct mpc *mpc, + struct mpcc_blnd_cfg *blnd_cfg, + int mpcc_id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + + REG_UPDATE_5(MPCC_CONTROL[mpcc_id], + MPCC_ALPHA_BLND_MODE, blnd_cfg->alpha_mode, + MPCC_ALPHA_MULTIPLIED_MODE, blnd_cfg->pre_multiplied_alpha, + MPCC_BLND_ACTIVE_OVERLAP_ONLY, blnd_cfg->overlap_only, + MPCC_GLOBAL_ALPHA, blnd_cfg->global_alpha, + MPCC_GLOBAL_GAIN, blnd_cfg->global_gain); + + mpc1_set_bg_color(mpc, &blnd_cfg->black_color, mpcc_id); +} + +void mpc1_update_stereo_mix( + struct mpc *mpc, + struct mpcc_sm_cfg *sm_cfg, + int mpcc_id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + + REG_UPDATE_6(MPCC_SM_CONTROL[mpcc_id], + MPCC_SM_EN, sm_cfg->enable, + MPCC_SM_MODE, sm_cfg->sm_mode, + MPCC_SM_FRAME_ALT, sm_cfg->frame_alt, + MPCC_SM_FIELD_ALT, sm_cfg->field_alt, + MPCC_SM_FORCE_NEXT_FRAME_POL, sm_cfg->force_next_frame_porlarity, + MPCC_SM_FORCE_NEXT_TOP_POL, sm_cfg->force_next_field_polarity); +} +void mpc1_assert_idle_mpcc(struct mpc *mpc, int id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + + ASSERT(!(mpc10->mpcc_in_use_mask & 1 << id)); + REG_WAIT(MPCC_STATUS[id], + MPCC_IDLE, 1, + 1, 100000); +} + +struct mpcc *mpc1_get_mpcc(struct mpc *mpc, int mpcc_id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + + ASSERT(mpcc_id < mpc10->num_mpcc); + return &(mpc->mpcc_array[mpcc_id]); +} + +struct mpcc *mpc1_get_mpcc_for_dpp(struct mpc_tree *tree, int dpp_id) +{ + struct mpcc *tmp_mpcc = tree->opp_list; + + while (tmp_mpcc != NULL) { + if (tmp_mpcc->dpp_id == dpp_id) + return tmp_mpcc; + tmp_mpcc = tmp_mpcc->mpcc_bot; + } + return NULL; +} + +bool mpc1_is_mpcc_idle(struct mpc *mpc, int mpcc_id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + unsigned int top_sel; + unsigned int opp_id; + unsigned int idle; + + REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel); + REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id); + REG_GET(MPCC_STATUS[mpcc_id], MPCC_IDLE, &idle); + if (top_sel == 0xf && opp_id == 0xf && idle) + return true; + else + return false; +} + +void mpc1_assert_mpcc_idle_before_connect(struct mpc *mpc, int mpcc_id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + unsigned int top_sel, mpc_busy, mpc_idle; + + REG_GET(MPCC_TOP_SEL[mpcc_id], + MPCC_TOP_SEL, &top_sel); + + if (top_sel == 0xf) { + REG_GET_2(MPCC_STATUS[mpcc_id], + MPCC_BUSY, &mpc_busy, + MPCC_IDLE, &mpc_idle); + + ASSERT(mpc_busy == 0); + ASSERT(mpc_idle == 1); + } +} + +/* + * Insert DPP into MPC tree based on specified blending position. + * Only used for planes that are part of blending chain for OPP output + * + * Parameters: + * [in/out] mpc - MPC context. + * [in/out] tree - MPC tree structure that plane will be added to. + * [in] blnd_cfg - MPCC blending configuration for the new blending layer. + * [in] sm_cfg - MPCC stereo mix configuration for the new blending layer. + * stereo mix must disable for the very bottom layer of the tree config. + * [in] insert_above_mpcc - Insert new plane above this MPCC. If NULL, insert as bottom plane. + * [in] dpp_id - DPP instance for the plane to be added. + * [in] mpcc_id - The MPCC physical instance to use for blending. + * + * Return: struct mpcc* - MPCC that was added. + */ +struct mpcc *mpc1_insert_plane( + struct mpc *mpc, + struct mpc_tree *tree, + struct mpcc_blnd_cfg *blnd_cfg, + struct mpcc_sm_cfg *sm_cfg, + struct mpcc *insert_above_mpcc, + int dpp_id, + int mpcc_id) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + struct mpcc *new_mpcc = NULL; + + /* sanity check parameters */ + ASSERT(mpcc_id < mpc10->num_mpcc); + ASSERT(!(mpc10->mpcc_in_use_mask & 1 << mpcc_id)); + + if (insert_above_mpcc) { + /* check insert_above_mpcc exist in tree->opp_list */ + struct mpcc *temp_mpcc = tree->opp_list; + + while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc) + temp_mpcc = temp_mpcc->mpcc_bot; + if (temp_mpcc == NULL) + return NULL; + } + + /* Get and update MPCC struct parameters */ + new_mpcc = mpc1_get_mpcc(mpc, mpcc_id); + new_mpcc->dpp_id = dpp_id; + + /* program mux and MPCC_MODE */ + if (insert_above_mpcc) { + new_mpcc->mpcc_bot = insert_above_mpcc; + REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, insert_above_mpcc->mpcc_id); + REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING); + } else { + new_mpcc->mpcc_bot = NULL; + REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf); + REG_UPDATE(MPCC_CONTROL[mpcc_id], MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH); + } + REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, dpp_id); + REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, tree->opp_id); + + /* update mpc tree mux setting */ + if (tree->opp_list == insert_above_mpcc) { + /* insert the toppest mpcc */ + tree->opp_list = new_mpcc; + REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, mpcc_id); + } else { + /* find insert position */ + struct mpcc *temp_mpcc = tree->opp_list; + + while (temp_mpcc && temp_mpcc->mpcc_bot != insert_above_mpcc) + temp_mpcc = temp_mpcc->mpcc_bot; + if (temp_mpcc && temp_mpcc->mpcc_bot == insert_above_mpcc) { + REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, MPCC_BOT_SEL, mpcc_id); + temp_mpcc->mpcc_bot = new_mpcc; + if (!insert_above_mpcc) + REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id], + MPCC_MODE, MPCC_BLEND_MODE_TOP_BOT_BLENDING); + } + } + + /* update the blending configuration */ + new_mpcc->blnd_cfg = *blnd_cfg; + mpc->funcs->update_blending(mpc, &new_mpcc->blnd_cfg, mpcc_id); + + /* update the stereo mix settings, if provided */ + if (sm_cfg != NULL) { + new_mpcc->sm_cfg = *sm_cfg; + mpc1_update_stereo_mix(mpc, sm_cfg, mpcc_id); + } + + /* mark this mpcc as in use */ + mpc10->mpcc_in_use_mask |= 1 << mpcc_id; + + return new_mpcc; +} + +/* + * Remove a specified MPCC from the MPC tree. + * + * Parameters: + * [in/out] mpc - MPC context. + * [in/out] tree - MPC tree structure that plane will be removed from. + * [in/out] mpcc - MPCC to be removed from tree. + * + * Return: void + */ +void mpc1_remove_mpcc( + struct mpc *mpc, + struct mpc_tree *tree, + struct mpcc *mpcc_to_remove) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + bool found = false; + int mpcc_id = mpcc_to_remove->mpcc_id; + + if (tree->opp_list == mpcc_to_remove) { + found = true; + /* remove MPCC from top of tree */ + if (mpcc_to_remove->mpcc_bot) { + /* set the next MPCC in list to be the top MPCC */ + tree->opp_list = mpcc_to_remove->mpcc_bot; + REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, tree->opp_list->mpcc_id); + } else { + /* there are no other MPCC is list */ + tree->opp_list = NULL; + REG_UPDATE(MUX[tree->opp_id], MPC_OUT_MUX, 0xf); + } + } else { + /* find mpcc to remove MPCC list */ + struct mpcc *temp_mpcc = tree->opp_list; + + while (temp_mpcc && temp_mpcc->mpcc_bot != mpcc_to_remove) + temp_mpcc = temp_mpcc->mpcc_bot; + + if (temp_mpcc && temp_mpcc->mpcc_bot == mpcc_to_remove) { + found = true; + temp_mpcc->mpcc_bot = mpcc_to_remove->mpcc_bot; + if (mpcc_to_remove->mpcc_bot) { + /* remove MPCC in middle of list */ + REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, + MPCC_BOT_SEL, mpcc_to_remove->mpcc_bot->mpcc_id); + } else { + /* remove MPCC from bottom of list */ + REG_SET(MPCC_BOT_SEL[temp_mpcc->mpcc_id], 0, + MPCC_BOT_SEL, 0xf); + REG_UPDATE(MPCC_CONTROL[temp_mpcc->mpcc_id], + MPCC_MODE, MPCC_BLEND_MODE_TOP_LAYER_PASSTHROUGH); + } + } + } + + if (found) { + /* turn off MPCC mux registers */ + REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf); + REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf); + REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf); + + /* mark this mpcc as not in use */ + mpc10->mpcc_in_use_mask &= ~(1 << mpcc_id); + mpcc_to_remove->dpp_id = 0xf; + mpcc_to_remove->mpcc_bot = NULL; + } else { + /* In case of resume from S3/S4, remove mpcc from bios left over */ + REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf); + REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf); + REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf); + } +} + +static void mpc1_init_mpcc(struct mpcc *mpcc, int mpcc_inst) +{ + mpcc->mpcc_id = mpcc_inst; + mpcc->dpp_id = 0xf; + mpcc->mpcc_bot = NULL; + mpcc->blnd_cfg.overlap_only = false; + mpcc->blnd_cfg.global_alpha = 0xff; + mpcc->blnd_cfg.global_gain = 0xff; + mpcc->sm_cfg.enable = false; +} + +/* + * Reset the MPCC HW status by disconnecting all muxes. + * + * Parameters: + * [in/out] mpc - MPC context. + * + * Return: void + */ +void mpc1_mpc_init(struct mpc *mpc) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + int mpcc_id; + int opp_id; + + mpc10->mpcc_in_use_mask = 0; + for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) { + REG_SET(MPCC_TOP_SEL[mpcc_id], 0, MPCC_TOP_SEL, 0xf); + REG_SET(MPCC_BOT_SEL[mpcc_id], 0, MPCC_BOT_SEL, 0xf); + REG_SET(MPCC_OPP_ID[mpcc_id], 0, MPCC_OPP_ID, 0xf); + + mpc1_init_mpcc(&(mpc->mpcc_array[mpcc_id]), mpcc_id); + } + + for (opp_id = 0; opp_id < MAX_OPP; opp_id++) { + if (REG(MUX[opp_id])) + REG_UPDATE(MUX[opp_id], MPC_OUT_MUX, 0xf); + } +} + +void mpc1_init_mpcc_list_from_hw( + struct mpc *mpc, + struct mpc_tree *tree) +{ + struct dcn10_mpc *mpc10 = TO_DCN10_MPC(mpc); + unsigned int opp_id; + unsigned int top_sel; + unsigned int bot_sel; + unsigned int out_mux; + struct mpcc *mpcc; + int mpcc_id; + int bot_mpcc_id; + + REG_GET(MUX[tree->opp_id], MPC_OUT_MUX, &out_mux); + + if (out_mux != 0xf) { + for (mpcc_id = 0; mpcc_id < mpc10->num_mpcc; mpcc_id++) { + REG_GET(MPCC_OPP_ID[mpcc_id], MPCC_OPP_ID, &opp_id); + REG_GET(MPCC_TOP_SEL[mpcc_id], MPCC_TOP_SEL, &top_sel); + REG_GET(MPCC_BOT_SEL[mpcc_id], MPCC_BOT_SEL, &bot_sel); + + if (bot_sel == mpcc_id) + bot_sel = 0xf; + + if ((opp_id == tree->opp_id) && (top_sel != 0xf)) { + mpcc = mpc1_get_mpcc(mpc, mpcc_id); + mpcc->dpp_id = top_sel; + mpc10->mpcc_in_use_mask |= 1 << mpcc_id; + + if (out_mux == mpcc_id) + tree->opp_list = mpcc; + if (bot_sel != 0xf && bot_sel < mpc10->num_mpcc) { + bot_mpcc_id = bot_sel; + REG_GET(MPCC_OPP_ID[bot_mpcc_id], MPCC_OPP_ID, &opp_id); + REG_GET(MPCC_TOP_SEL[bot_mpcc_id], MPCC_TOP_SEL, &top_sel); + if ((opp_id == tree->opp_id) && (top_sel != 0xf)) { + struct mpcc *mpcc_bottom = mpc1_get_mpcc(mpc, bot_mpcc_id); + + mpcc->mpcc_bot = mpcc_bottom; + } + } + } + } + } +} + +const struct mpc_funcs dcn10_mpc_funcs = { + .insert_plane = mpc1_insert_plane, + .remove_mpcc = mpc1_remove_mpcc, + .mpc_init = mpc1_mpc_init, + .get_mpcc_for_dpp = mpc1_get_mpcc_for_dpp, + .wait_for_idle = mpc1_assert_idle_mpcc, + .assert_mpcc_idle_before_connect = mpc1_assert_mpcc_idle_before_connect, + .init_mpcc_list_from_hw = mpc1_init_mpcc_list_from_hw, + .update_blending = mpc1_update_blending, +}; + +void dcn10_mpc_construct(struct dcn10_mpc *mpc10, + struct dc_context *ctx, + const struct dcn_mpc_registers *mpc_regs, + const struct dcn_mpc_shift *mpc_shift, + const struct dcn_mpc_mask *mpc_mask, + int num_mpcc) +{ + int i; + + mpc10->base.ctx = ctx; + + mpc10->base.funcs = &dcn10_mpc_funcs; + + mpc10->mpc_regs = mpc_regs; + mpc10->mpc_shift = mpc_shift; + mpc10->mpc_mask = mpc_mask; + + mpc10->mpcc_in_use_mask = 0; + mpc10->num_mpcc = num_mpcc; + + for (i = 0; i < MAX_MPCC; i++) + mpc1_init_mpcc(&mpc10->base.mpcc_array[i], i); +} + diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h new file mode 100644 index 000000000000..267a2995ef6e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h @@ -0,0 +1,186 @@ +/* Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_MPCC_DCN10_H__ +#define __DC_MPCC_DCN10_H__ + +#include "mpc.h" + +#define TO_DCN10_MPC(mpc_base) \ + container_of(mpc_base, struct dcn10_mpc, base) + +#define MPC_COMMON_REG_LIST_DCN1_0(inst) \ + SRII(MPCC_TOP_SEL, MPCC, inst),\ + SRII(MPCC_BOT_SEL, MPCC, inst),\ + SRII(MPCC_CONTROL, MPCC, inst),\ + SRII(MPCC_STATUS, MPCC, inst),\ + SRII(MPCC_OPP_ID, MPCC, inst),\ + SRII(MPCC_BG_G_Y, MPCC, inst),\ + SRII(MPCC_BG_R_CR, MPCC, inst),\ + SRII(MPCC_BG_B_CB, MPCC, inst),\ + SRII(MPCC_BG_B_CB, MPCC, inst),\ + SRII(MPCC_SM_CONTROL, MPCC, inst) + +#define MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(inst) \ + SRII(MUX, MPC_OUT, inst) + +#define MPC_COMMON_REG_VARIABLE_LIST \ + uint32_t MPCC_TOP_SEL[MAX_MPCC]; \ + uint32_t MPCC_BOT_SEL[MAX_MPCC]; \ + uint32_t MPCC_CONTROL[MAX_MPCC]; \ + uint32_t MPCC_STATUS[MAX_MPCC]; \ + uint32_t MPCC_OPP_ID[MAX_MPCC]; \ + uint32_t MPCC_BG_G_Y[MAX_MPCC]; \ + uint32_t MPCC_BG_R_CR[MAX_MPCC]; \ + uint32_t MPCC_BG_B_CB[MAX_MPCC]; \ + uint32_t MPCC_SM_CONTROL[MAX_MPCC]; \ + uint32_t MUX[MAX_OPP]; + +#define MPC_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\ + SF(MPCC0_MPCC_TOP_SEL, MPCC_TOP_SEL, mask_sh),\ + SF(MPCC0_MPCC_BOT_SEL, MPCC_BOT_SEL, mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_MODE, mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_ALPHA_BLND_MODE, mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_ALPHA_MULTIPLIED_MODE, mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_BLND_ACTIVE_OVERLAP_ONLY, mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_GLOBAL_ALPHA, mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_GLOBAL_GAIN, mask_sh),\ + SF(MPCC0_MPCC_STATUS, MPCC_IDLE, mask_sh),\ + SF(MPCC0_MPCC_STATUS, MPCC_BUSY, mask_sh),\ + SF(MPCC0_MPCC_OPP_ID, MPCC_OPP_ID, mask_sh),\ + SF(MPCC0_MPCC_BG_G_Y, MPCC_BG_G_Y, mask_sh),\ + SF(MPCC0_MPCC_BG_R_CR, MPCC_BG_R_CR, mask_sh),\ + SF(MPCC0_MPCC_BG_B_CB, MPCC_BG_B_CB, mask_sh),\ + SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_EN, mask_sh),\ + SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_MODE, mask_sh),\ + SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FRAME_ALT, mask_sh),\ + SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FIELD_ALT, mask_sh),\ + SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FORCE_NEXT_FRAME_POL, mask_sh),\ + SF(MPCC0_MPCC_SM_CONTROL, MPCC_SM_FORCE_NEXT_TOP_POL, mask_sh),\ + SF(MPC_OUT0_MUX, MPC_OUT_MUX, mask_sh) + +#define MPC_REG_FIELD_LIST(type) \ + type MPCC_TOP_SEL;\ + type MPCC_BOT_SEL;\ + type MPCC_MODE;\ + type MPCC_ALPHA_BLND_MODE;\ + type MPCC_ALPHA_MULTIPLIED_MODE;\ + type MPCC_BLND_ACTIVE_OVERLAP_ONLY;\ + type MPCC_GLOBAL_ALPHA;\ + type MPCC_GLOBAL_GAIN;\ + type MPCC_IDLE;\ + type MPCC_BUSY;\ + type MPCC_OPP_ID;\ + type MPCC_BG_G_Y;\ + type MPCC_BG_R_CR;\ + type MPCC_BG_B_CB;\ + type MPCC_SM_EN;\ + type MPCC_SM_MODE;\ + type MPCC_SM_FRAME_ALT;\ + type MPCC_SM_FIELD_ALT;\ + type MPCC_SM_FORCE_NEXT_FRAME_POL;\ + type MPCC_SM_FORCE_NEXT_TOP_POL;\ + type MPC_OUT_MUX; + +struct dcn_mpc_registers { + MPC_COMMON_REG_VARIABLE_LIST +}; + +struct dcn_mpc_shift { + MPC_REG_FIELD_LIST(uint8_t) +}; + +struct dcn_mpc_mask { + MPC_REG_FIELD_LIST(uint32_t) +}; + +struct dcn10_mpc { + struct mpc base; + + int mpcc_in_use_mask; + int num_mpcc; + const struct dcn_mpc_registers *mpc_regs; + const struct dcn_mpc_shift *mpc_shift; + const struct dcn_mpc_mask *mpc_mask; +}; + +void dcn10_mpc_construct(struct dcn10_mpc *mpcc10, + struct dc_context *ctx, + const struct dcn_mpc_registers *mpc_regs, + const struct dcn_mpc_shift *mpc_shift, + const struct dcn_mpc_mask *mpc_mask, + int num_mpcc); + +struct mpcc *mpc1_insert_plane( + struct mpc *mpc, + struct mpc_tree *tree, + struct mpcc_blnd_cfg *blnd_cfg, + struct mpcc_sm_cfg *sm_cfg, + struct mpcc *insert_above_mpcc, + int dpp_id, + int mpcc_id); + +void mpc1_remove_mpcc( + struct mpc *mpc, + struct mpc_tree *tree, + struct mpcc *mpcc); + +void mpc1_mpc_init( + struct mpc *mpc); + +void mpc1_assert_idle_mpcc( + struct mpc *mpc, + int id); + +void mpc1_set_bg_color( + struct mpc *mpc, + struct tg_color *bg_color, + int id); + +void mpc1_update_stereo_mix( + struct mpc *mpc, + struct mpcc_sm_cfg *sm_cfg, + int mpcc_id); + +bool mpc1_is_mpcc_idle( + struct mpc *mpc, + int mpcc_id); + +void mpc1_assert_mpcc_idle_before_connect( + struct mpc *mpc, + int mpcc_id); + +void mpc1_init_mpcc_list_from_hw( + struct mpc *mpc, + struct mpc_tree *tree); + +struct mpcc *mpc1_get_mpcc( + struct mpc *mpc, + int mpcc_id); + +struct mpcc *mpc1_get_mpcc_for_dpp( + struct mpc_tree *tree, + int dpp_id); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c new file mode 100644 index 000000000000..f6ba0eef4489 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c @@ -0,0 +1,403 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dcn10_opp.h" +#include "reg_helper.h" + +#define REG(reg) \ + (oppn10->regs->reg) + +#undef FN +#define FN(reg_name, field_name) \ + oppn10->opp_shift->field_name, oppn10->opp_mask->field_name + +#define CTX \ + oppn10->base.ctx + + +/************* FORMATTER ************/ + +/** + * set_truncation + * 1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp + * 2) enable truncation + * 3) HW remove 12bit FMT support for DCE11 power saving reason. + */ +static void opp1_set_truncation( + struct dcn10_opp *oppn10, + const struct bit_depth_reduction_params *params) +{ + REG_UPDATE_3(FMT_BIT_DEPTH_CONTROL, + FMT_TRUNCATE_EN, params->flags.TRUNCATE_ENABLED, + FMT_TRUNCATE_DEPTH, params->flags.TRUNCATE_DEPTH, + FMT_TRUNCATE_MODE, params->flags.TRUNCATE_MODE); +} + +static void opp1_set_spatial_dither( + struct dcn10_opp *oppn10, + const struct bit_depth_reduction_params *params) +{ + /*Disable spatial (random) dithering*/ + REG_UPDATE_7(FMT_BIT_DEPTH_CONTROL, + FMT_SPATIAL_DITHER_EN, 0, + FMT_SPATIAL_DITHER_MODE, 0, + FMT_SPATIAL_DITHER_DEPTH, 0, + FMT_TEMPORAL_DITHER_EN, 0, + FMT_HIGHPASS_RANDOM_ENABLE, 0, + FMT_FRAME_RANDOM_ENABLE, 0, + FMT_RGB_RANDOM_ENABLE, 0); + + + /* only use FRAME_COUNTER_MAX if frameRandom == 1*/ + if (params->flags.FRAME_RANDOM == 1) { + if (params->flags.SPATIAL_DITHER_DEPTH == 0 || params->flags.SPATIAL_DITHER_DEPTH == 1) { + REG_UPDATE_2(FMT_CONTROL, + FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 15, + FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 2); + } else if (params->flags.SPATIAL_DITHER_DEPTH == 2) { + REG_UPDATE_2(FMT_CONTROL, + FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 3, + FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 1); + } else { + return; + } + } else { + REG_UPDATE_2(FMT_CONTROL, + FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, 0, + FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, 0); + } + + /*Set seed for random values for + * spatial dithering for R,G,B channels*/ + + REG_SET(FMT_DITHER_RAND_R_SEED, 0, + FMT_RAND_R_SEED, params->r_seed_value); + + REG_SET(FMT_DITHER_RAND_G_SEED, 0, + FMT_RAND_G_SEED, params->g_seed_value); + + REG_SET(FMT_DITHER_RAND_B_SEED, 0, + FMT_RAND_B_SEED, params->b_seed_value); + + /* FMT_OFFSET_R_Cr 31:16 0x0 Setting the zero + * offset for the R/Cr channel, lower 4LSB + * is forced to zeros. Typically set to 0 + * RGB and 0x80000 YCbCr. + */ + /* FMT_OFFSET_G_Y 31:16 0x0 Setting the zero + * offset for the G/Y channel, lower 4LSB is + * forced to zeros. Typically set to 0 RGB + * and 0x80000 YCbCr. + */ + /* FMT_OFFSET_B_Cb 31:16 0x0 Setting the zero + * offset for the B/Cb channel, lower 4LSB is + * forced to zeros. Typically set to 0 RGB and + * 0x80000 YCbCr. + */ + + REG_UPDATE_6(FMT_BIT_DEPTH_CONTROL, + /*Enable spatial dithering*/ + FMT_SPATIAL_DITHER_EN, params->flags.SPATIAL_DITHER_ENABLED, + /* Set spatial dithering mode + * (default is Seed patterrn AAAA...) + */ + FMT_SPATIAL_DITHER_MODE, params->flags.SPATIAL_DITHER_MODE, + /*Set spatial dithering bit depth*/ + FMT_SPATIAL_DITHER_DEPTH, params->flags.SPATIAL_DITHER_DEPTH, + /*Disable High pass filter*/ + FMT_HIGHPASS_RANDOM_ENABLE, params->flags.HIGHPASS_RANDOM, + /*Reset only at startup*/ + FMT_FRAME_RANDOM_ENABLE, params->flags.FRAME_RANDOM, + /*Set RGB data dithered with x^28+x^3+1*/ + FMT_RGB_RANDOM_ENABLE, params->flags.RGB_RANDOM); +} + +void opp1_program_bit_depth_reduction( + struct output_pixel_processor *opp, + const struct bit_depth_reduction_params *params) +{ + struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp); + + opp1_set_truncation(oppn10, params); + opp1_set_spatial_dither(oppn10, params); + /* TODO + * set_temporal_dither(oppn10, params); + */ +} + +/** + * set_pixel_encoding + * + * Set Pixel Encoding + * 0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly + * 1: YCbCr 4:2:2 + */ +static void opp1_set_pixel_encoding( + struct dcn10_opp *oppn10, + const struct clamping_and_pixel_encoding_params *params) +{ + switch (params->pixel_encoding) { + + case PIXEL_ENCODING_RGB: + case PIXEL_ENCODING_YCBCR444: + REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 0); + break; + case PIXEL_ENCODING_YCBCR422: + REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 1); + break; + case PIXEL_ENCODING_YCBCR420: + REG_UPDATE(FMT_CONTROL, FMT_PIXEL_ENCODING, 2); + break; + default: + break; + } +} + +/** + * Set Clamping + * 1) Set clamping format based on bpc - 0 for 6bpc (No clamping) + * 1 for 8 bpc + * 2 for 10 bpc + * 3 for 12 bpc + * 7 for programable + * 2) Enable clamp if Limited range requested + */ +static void opp1_set_clamping( + struct dcn10_opp *oppn10, + const struct clamping_and_pixel_encoding_params *params) +{ + REG_UPDATE_2(FMT_CLAMP_CNTL, + FMT_CLAMP_DATA_EN, 0, + FMT_CLAMP_COLOR_FORMAT, 0); + + switch (params->clamping_level) { + case CLAMPING_FULL_RANGE: + REG_UPDATE_2(FMT_CLAMP_CNTL, + FMT_CLAMP_DATA_EN, 1, + FMT_CLAMP_COLOR_FORMAT, 0); + break; + case CLAMPING_LIMITED_RANGE_8BPC: + REG_UPDATE_2(FMT_CLAMP_CNTL, + FMT_CLAMP_DATA_EN, 1, + FMT_CLAMP_COLOR_FORMAT, 1); + break; + case CLAMPING_LIMITED_RANGE_10BPC: + REG_UPDATE_2(FMT_CLAMP_CNTL, + FMT_CLAMP_DATA_EN, 1, + FMT_CLAMP_COLOR_FORMAT, 2); + + break; + case CLAMPING_LIMITED_RANGE_12BPC: + REG_UPDATE_2(FMT_CLAMP_CNTL, + FMT_CLAMP_DATA_EN, 1, + FMT_CLAMP_COLOR_FORMAT, 3); + break; + case CLAMPING_LIMITED_RANGE_PROGRAMMABLE: + /* TODO */ + default: + break; + } + +} + +void opp1_set_dyn_expansion( + struct output_pixel_processor *opp, + enum dc_color_space color_sp, + enum dc_color_depth color_dpth, + enum signal_type signal) +{ + struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp); + + REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, + FMT_DYNAMIC_EXP_EN, 0, + FMT_DYNAMIC_EXP_MODE, 0); + + /*00 - 10-bit -> 12-bit dynamic expansion*/ + /*01 - 8-bit -> 12-bit dynamic expansion*/ + if (signal == SIGNAL_TYPE_HDMI_TYPE_A || + signal == SIGNAL_TYPE_DISPLAY_PORT || + signal == SIGNAL_TYPE_DISPLAY_PORT_MST || + signal == SIGNAL_TYPE_VIRTUAL) { + switch (color_dpth) { + case COLOR_DEPTH_888: + REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, + FMT_DYNAMIC_EXP_EN, 1, + FMT_DYNAMIC_EXP_MODE, 1); + break; + case COLOR_DEPTH_101010: + REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, + FMT_DYNAMIC_EXP_EN, 1, + FMT_DYNAMIC_EXP_MODE, 0); + break; + case COLOR_DEPTH_121212: + REG_UPDATE_2(FMT_DYNAMIC_EXP_CNTL, + FMT_DYNAMIC_EXP_EN, 1,/*otherwise last two bits are zero*/ + FMT_DYNAMIC_EXP_MODE, 0); + break; + default: + break; + } + } +} + +static void opp1_program_clamping_and_pixel_encoding( + struct output_pixel_processor *opp, + const struct clamping_and_pixel_encoding_params *params) +{ + struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp); + + opp1_set_clamping(oppn10, params); + opp1_set_pixel_encoding(oppn10, params); +} + +void opp1_program_fmt( + struct output_pixel_processor *opp, + struct bit_depth_reduction_params *fmt_bit_depth, + struct clamping_and_pixel_encoding_params *clamping) +{ + struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp); + + if (clamping->pixel_encoding == PIXEL_ENCODING_YCBCR420) + REG_UPDATE(FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, 0); + + /* dithering is affected by <CrtcSourceSelect>, hence should be + * programmed afterwards */ + opp1_program_bit_depth_reduction( + opp, + fmt_bit_depth); + + opp1_program_clamping_and_pixel_encoding( + opp, + clamping); + + return; +} + +void opp1_program_stereo( + struct output_pixel_processor *opp, + bool enable, + const struct dc_crtc_timing *timing) +{ + struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp); + + uint32_t active_width = timing->h_addressable - timing->h_border_right - timing->h_border_right; + uint32_t space1_size = timing->v_total - timing->v_addressable; + /* TODO: confirm computation of space2_size */ + uint32_t space2_size = timing->v_total - timing->v_addressable; + + if (!enable) { + active_width = 0; + space1_size = 0; + space2_size = 0; + } + + /* TODO: for which cases should FMT_STEREOSYNC_OVERRIDE be set? */ + REG_UPDATE(FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, 0); + + REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, active_width); + + /* Program OPPBUF_3D_VACT_SPACE1_SIZE and OPPBUF_VACT_SPACE2_SIZE registers + * In 3D progressive frames, Vactive space happens only in between the 2 frames, + * so only need to program OPPBUF_3D_VACT_SPACE1_SIZE + * In 3D alternative frames, left and right frames, top and bottom field. + */ + if (timing->timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE) + REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, space2_size); + else + REG_UPDATE(OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, space1_size); + + /* TODO: Is programming of OPPBUF_DUMMY_DATA_R/G/B needed? */ + /* + REG_UPDATE(OPPBUF_3D_PARAMETERS_0, + OPPBUF_DUMMY_DATA_R, data_r); + REG_UPDATE(OPPBUF_3D_PARAMETERS_1, + OPPBUF_DUMMY_DATA_G, data_g); + REG_UPDATE(OPPBUF_3D_PARAMETERS_1, + OPPBUF_DUMMY_DATA_B, _data_b); + */ +} + +void opp1_program_oppbuf( + struct output_pixel_processor *opp, + struct oppbuf_params *oppbuf) +{ + struct dcn10_opp *oppn10 = TO_DCN10_OPP(opp); + + /* Program the oppbuf active width to be the frame width from mpc */ + REG_UPDATE(OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, oppbuf->active_width); + + /* Specifies the number of segments in multi-segment mode (DP-MSO operation) + * description "In 1/2/4 segment mode, specifies the horizontal active width in pixels of the display panel. + * In 4 segment split left/right mode, specifies the horizontal 1/2 active width in pixels of the display panel. + * Used to determine segment boundaries in multi-segment mode. Used to determine the width of the vertical active space in 3D frame packed modes. + * OPPBUF_ACTIVE_WIDTH must be integer divisible by the total number of segments." + */ + REG_UPDATE(OPPBUF_CONTROL, OPPBUF_DISPLAY_SEGMENTATION, oppbuf->mso_segmentation); + + /* description "Specifies the number of overlap pixels (1-8 overlapping pixels supported), used in multi-segment mode (DP-MSO operation)" */ + REG_UPDATE(OPPBUF_CONTROL, OPPBUF_OVERLAP_PIXEL_NUM, oppbuf->mso_overlap_pixel_num); + + /* description "Specifies the number of times a pixel is replicated (0-15 pixel replications supported). + * A value of 0 disables replication. The total number of times a pixel is output is OPPBUF_PIXEL_REPETITION + 1." + */ + REG_UPDATE(OPPBUF_CONTROL, OPPBUF_PIXEL_REPETITION, oppbuf->pixel_repetition); + +} + +/*****************************************/ +/* Constructor, Destructor */ +/*****************************************/ + +void opp1_destroy(struct output_pixel_processor **opp) +{ + kfree(TO_DCN10_OPP(*opp)); + *opp = NULL; +} + +static struct opp_funcs dcn10_opp_funcs = { + .opp_set_dyn_expansion = opp1_set_dyn_expansion, + .opp_program_fmt = opp1_program_fmt, + .opp_program_bit_depth_reduction = opp1_program_bit_depth_reduction, + .opp_program_stereo = opp1_program_stereo, + .opp_destroy = opp1_destroy +}; + +void dcn10_opp_construct(struct dcn10_opp *oppn10, + struct dc_context *ctx, + uint32_t inst, + const struct dcn10_opp_registers *regs, + const struct dcn10_opp_shift *opp_shift, + const struct dcn10_opp_mask *opp_mask) +{ + + oppn10->base.ctx = ctx; + oppn10->base.inst = inst; + oppn10->base.funcs = &dcn10_opp_funcs; + + oppn10->regs = regs; + oppn10->opp_shift = opp_shift; + oppn10->opp_mask = opp_mask; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h new file mode 100644 index 000000000000..bc5058af6266 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h @@ -0,0 +1,181 @@ +/* Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_OPP_DCN10_H__ +#define __DC_OPP_DCN10_H__ + +#include "opp.h" + +#define TO_DCN10_OPP(opp)\ + container_of(opp, struct dcn10_opp, base) + +#define OPP_SF(reg_name, field_name, post_fix)\ + .field_name = reg_name ## __ ## field_name ## post_fix + +#define OPP_REG_LIST_DCN(id) \ + SRI(FMT_BIT_DEPTH_CONTROL, FMT, id), \ + SRI(FMT_CONTROL, FMT, id), \ + SRI(FMT_DITHER_RAND_R_SEED, FMT, id), \ + SRI(FMT_DITHER_RAND_G_SEED, FMT, id), \ + SRI(FMT_DITHER_RAND_B_SEED, FMT, id), \ + SRI(FMT_CLAMP_CNTL, FMT, id), \ + SRI(FMT_DYNAMIC_EXP_CNTL, FMT, id), \ + SRI(FMT_MAP420_MEMORY_CONTROL, FMT, id), \ + SRI(OPPBUF_CONTROL, OPPBUF, id),\ + SRI(OPPBUF_3D_PARAMETERS_0, OPPBUF, id), \ + SRI(OPPBUF_3D_PARAMETERS_1, OPPBUF, id) + +#define OPP_REG_LIST_DCN10(id) \ + OPP_REG_LIST_DCN(id) + +#define OPP_COMMON_REG_VARIABLE_LIST \ + uint32_t FMT_BIT_DEPTH_CONTROL; \ + uint32_t FMT_CONTROL; \ + uint32_t FMT_DITHER_RAND_R_SEED; \ + uint32_t FMT_DITHER_RAND_G_SEED; \ + uint32_t FMT_DITHER_RAND_B_SEED; \ + uint32_t FMT_CLAMP_CNTL; \ + uint32_t FMT_DYNAMIC_EXP_CNTL; \ + uint32_t FMT_MAP420_MEMORY_CONTROL; \ + uint32_t OPPBUF_CONTROL; \ + uint32_t OPPBUF_CONTROL1; \ + uint32_t OPPBUF_3D_PARAMETERS_0; \ + uint32_t OPPBUF_3D_PARAMETERS_1 + +#define OPP_MASK_SH_LIST_DCN(mask_sh) \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_MODE, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_MODE, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_EN, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE, mask_sh), \ + OPP_SF(FMT0_FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE, mask_sh), \ + OPP_SF(FMT0_FMT_CONTROL, FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX, mask_sh), \ + OPP_SF(FMT0_FMT_CONTROL, FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP, mask_sh), \ + OPP_SF(FMT0_FMT_CONTROL, FMT_PIXEL_ENCODING, mask_sh), \ + OPP_SF(FMT0_FMT_CONTROL, FMT_STEREOSYNC_OVERRIDE, mask_sh), \ + OPP_SF(FMT0_FMT_DITHER_RAND_R_SEED, FMT_RAND_R_SEED, mask_sh), \ + OPP_SF(FMT0_FMT_DITHER_RAND_G_SEED, FMT_RAND_G_SEED, mask_sh), \ + OPP_SF(FMT0_FMT_DITHER_RAND_B_SEED, FMT_RAND_B_SEED, mask_sh), \ + OPP_SF(FMT0_FMT_CLAMP_CNTL, FMT_CLAMP_DATA_EN, mask_sh), \ + OPP_SF(FMT0_FMT_CLAMP_CNTL, FMT_CLAMP_COLOR_FORMAT, mask_sh), \ + OPP_SF(FMT0_FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN, mask_sh), \ + OPP_SF(FMT0_FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE, mask_sh), \ + OPP_SF(FMT0_FMT_MAP420_MEMORY_CONTROL, FMT_MAP420MEM_PWR_FORCE, mask_sh), \ + OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_ACTIVE_WIDTH, mask_sh),\ + OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_PIXEL_REPETITION, mask_sh),\ + OPP_SF(OPPBUF0_OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE1_SIZE, mask_sh), \ + OPP_SF(OPPBUF0_OPPBUF_3D_PARAMETERS_0, OPPBUF_3D_VACT_SPACE2_SIZE, mask_sh) + +#define OPP_MASK_SH_LIST_DCN10(mask_sh) \ + OPP_MASK_SH_LIST_DCN(mask_sh), \ + OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_DISPLAY_SEGMENTATION, mask_sh),\ + OPP_SF(OPPBUF0_OPPBUF_CONTROL, OPPBUF_OVERLAP_PIXEL_NUM, mask_sh) + +#define OPP_DCN10_REG_FIELD_LIST(type) \ + type FMT_TRUNCATE_EN; \ + type FMT_TRUNCATE_DEPTH; \ + type FMT_TRUNCATE_MODE; \ + type FMT_SPATIAL_DITHER_EN; \ + type FMT_SPATIAL_DITHER_MODE; \ + type FMT_SPATIAL_DITHER_DEPTH; \ + type FMT_TEMPORAL_DITHER_EN; \ + type FMT_HIGHPASS_RANDOM_ENABLE; \ + type FMT_FRAME_RANDOM_ENABLE; \ + type FMT_RGB_RANDOM_ENABLE; \ + type FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX; \ + type FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP; \ + type FMT_RAND_R_SEED; \ + type FMT_RAND_G_SEED; \ + type FMT_RAND_B_SEED; \ + type FMT_PIXEL_ENCODING; \ + type FMT_CLAMP_DATA_EN; \ + type FMT_CLAMP_COLOR_FORMAT; \ + type FMT_DYNAMIC_EXP_EN; \ + type FMT_DYNAMIC_EXP_MODE; \ + type FMT_MAP420MEM_PWR_FORCE; \ + type FMT_STEREOSYNC_OVERRIDE; \ + type OPPBUF_ACTIVE_WIDTH;\ + type OPPBUF_PIXEL_REPETITION;\ + type OPPBUF_DISPLAY_SEGMENTATION;\ + type OPPBUF_OVERLAP_PIXEL_NUM;\ + type OPPBUF_NUM_SEGMENT_PADDED_PIXELS; \ + type OPPBUF_3D_VACT_SPACE1_SIZE; \ + type OPPBUF_3D_VACT_SPACE2_SIZE + +struct dcn10_opp_registers { + OPP_COMMON_REG_VARIABLE_LIST; +}; + +struct dcn10_opp_shift { + OPP_DCN10_REG_FIELD_LIST(uint8_t); +}; + +struct dcn10_opp_mask { + OPP_DCN10_REG_FIELD_LIST(uint32_t); +}; + +struct dcn10_opp { + struct output_pixel_processor base; + + const struct dcn10_opp_registers *regs; + const struct dcn10_opp_shift *opp_shift; + const struct dcn10_opp_mask *opp_mask; + + bool is_write_to_ram_a_safe; +}; + +void dcn10_opp_construct(struct dcn10_opp *oppn10, + struct dc_context *ctx, + uint32_t inst, + const struct dcn10_opp_registers *regs, + const struct dcn10_opp_shift *opp_shift, + const struct dcn10_opp_mask *opp_mask); + +void opp1_set_dyn_expansion( + struct output_pixel_processor *opp, + enum dc_color_space color_sp, + enum dc_color_depth color_dpth, + enum signal_type signal); + +void opp1_program_fmt( + struct output_pixel_processor *opp, + struct bit_depth_reduction_params *fmt_bit_depth, + struct clamping_and_pixel_encoding_params *clamping); + +void opp1_program_bit_depth_reduction( + struct output_pixel_processor *opp, + const struct bit_depth_reduction_params *params); + +void opp1_program_stereo( + struct output_pixel_processor *opp, + bool enable, + const struct dc_crtc_timing *timing); + +void opp1_destroy(struct output_pixel_processor **opp); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c new file mode 100644 index 000000000000..4bf64d1b2c60 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.c @@ -0,0 +1,1263 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + + +#include "reg_helper.h" +#include "dcn10_optc.h" +#include "dc.h" + +#define REG(reg)\ + optc1->tg_regs->reg + +#define CTX \ + optc1->base.ctx + +#undef FN +#define FN(reg_name, field_name) \ + optc1->tg_shift->field_name, optc1->tg_mask->field_name + +#define STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN 0x100 + +/** +* apply_front_porch_workaround TODO FPGA still need? +* +* This is a workaround for a bug that has existed since R5xx and has not been +* fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive. +*/ +static void optc1_apply_front_porch_workaround( + struct timing_generator *optc, + struct dc_crtc_timing *timing) +{ + if (timing->flags.INTERLACE == 1) { + if (timing->v_front_porch < 2) + timing->v_front_porch = 2; + } else { + if (timing->v_front_porch < 1) + timing->v_front_porch = 1; + } +} + +void optc1_program_global_sync( + struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (optc->dlg_otg_param.vstartup_start == 0) { + BREAK_TO_DEBUGGER(); + return; + } + + REG_SET(OTG_VSTARTUP_PARAM, 0, + VSTARTUP_START, optc->dlg_otg_param.vstartup_start); + + REG_SET_2(OTG_VUPDATE_PARAM, 0, + VUPDATE_OFFSET, optc->dlg_otg_param.vupdate_offset, + VUPDATE_WIDTH, optc->dlg_otg_param.vupdate_width); + + REG_SET(OTG_VREADY_PARAM, 0, + VREADY_OFFSET, optc->dlg_otg_param.vready_offset); +} + +static void optc1_disable_stereo(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_STEREO_CONTROL, 0, + OTG_STEREO_EN, 0); + + REG_SET_3(OTG_3D_STRUCTURE_CONTROL, 0, + OTG_3D_STRUCTURE_EN, 0, + OTG_3D_STRUCTURE_V_UPDATE_MODE, 0, + OTG_3D_STRUCTURE_STEREO_SEL_OVR, 0); +} + +/** + * program_timing_generator used by mode timing set + * Program CRTC Timing Registers - OTG_H_*, OTG_V_*, Pixel repetition. + * Including SYNC. Call BIOS command table to program Timings. + */ +void optc1_program_timing( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, + bool use_vbios) +{ + struct dc_crtc_timing patched_crtc_timing; + uint32_t vesa_sync_start; + uint32_t asic_blank_end; + uint32_t asic_blank_start; + uint32_t v_total; + uint32_t v_sync_end; + uint32_t v_init, v_fp2; + uint32_t h_sync_polarity, v_sync_polarity; + uint32_t interlace_factor; + uint32_t start_point = 0; + uint32_t field_num = 0; + uint32_t h_div_2; + int32_t vertical_line_start; + + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + patched_crtc_timing = *dc_crtc_timing; + optc1_apply_front_porch_workaround(optc, &patched_crtc_timing); + + /* Load horizontal timing */ + + /* CRTC_H_TOTAL = vesa.h_total - 1 */ + REG_SET(OTG_H_TOTAL, 0, + OTG_H_TOTAL, patched_crtc_timing.h_total - 1); + + /* h_sync_start = 0, h_sync_end = vesa.h_sync_width */ + REG_UPDATE_2(OTG_H_SYNC_A, + OTG_H_SYNC_A_START, 0, + OTG_H_SYNC_A_END, patched_crtc_timing.h_sync_width); + + /* asic_h_blank_end = HsyncWidth + HbackPorch = + * vesa. usHorizontalTotal - vesa. usHorizontalSyncStart - + * vesa.h_left_border + */ + vesa_sync_start = patched_crtc_timing.h_addressable + + patched_crtc_timing.h_border_right + + patched_crtc_timing.h_front_porch; + + asic_blank_end = patched_crtc_timing.h_total - + vesa_sync_start - + patched_crtc_timing.h_border_left; + + /* h_blank_start = v_blank_end + v_active */ + asic_blank_start = asic_blank_end + + patched_crtc_timing.h_border_left + + patched_crtc_timing.h_addressable + + patched_crtc_timing.h_border_right; + + REG_UPDATE_2(OTG_H_BLANK_START_END, + OTG_H_BLANK_START, asic_blank_start, + OTG_H_BLANK_END, asic_blank_end); + + /* h_sync polarity */ + h_sync_polarity = patched_crtc_timing.flags.HSYNC_POSITIVE_POLARITY ? + 0 : 1; + + REG_UPDATE(OTG_H_SYNC_A_CNTL, + OTG_H_SYNC_A_POL, h_sync_polarity); + + /* Load vertical timing */ + + /* CRTC_V_TOTAL = v_total - 1 */ + if (patched_crtc_timing.flags.INTERLACE) { + interlace_factor = 2; + v_total = 2 * patched_crtc_timing.v_total; + } else { + interlace_factor = 1; + v_total = patched_crtc_timing.v_total - 1; + } + REG_SET(OTG_V_TOTAL, 0, + OTG_V_TOTAL, v_total); + + /* In case of V_TOTAL_CONTROL is on, make sure OTG_V_TOTAL_MAX and + * OTG_V_TOTAL_MIN are equal to V_TOTAL. + */ + REG_SET(OTG_V_TOTAL_MAX, 0, + OTG_V_TOTAL_MAX, v_total); + REG_SET(OTG_V_TOTAL_MIN, 0, + OTG_V_TOTAL_MIN, v_total); + + /* v_sync_start = 0, v_sync_end = v_sync_width */ + v_sync_end = patched_crtc_timing.v_sync_width * interlace_factor; + + REG_UPDATE_2(OTG_V_SYNC_A, + OTG_V_SYNC_A_START, 0, + OTG_V_SYNC_A_END, v_sync_end); + + vesa_sync_start = patched_crtc_timing.v_addressable + + patched_crtc_timing.v_border_bottom + + patched_crtc_timing.v_front_porch; + + asic_blank_end = (patched_crtc_timing.v_total - + vesa_sync_start - + patched_crtc_timing.v_border_top) + * interlace_factor; + + /* v_blank_start = v_blank_end + v_active */ + asic_blank_start = asic_blank_end + + (patched_crtc_timing.v_border_top + + patched_crtc_timing.v_addressable + + patched_crtc_timing.v_border_bottom) + * interlace_factor; + + REG_UPDATE_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, asic_blank_start, + OTG_V_BLANK_END, asic_blank_end); + + /* Use OTG_VERTICAL_INTERRUPT2 replace VUPDATE interrupt, + * program the reg for interrupt postition. + */ + vertical_line_start = asic_blank_end - optc->dlg_otg_param.vstartup_start + 1; + if (vertical_line_start < 0) { + ASSERT(0); + vertical_line_start = 0; + } + REG_SET(OTG_VERTICAL_INTERRUPT2_POSITION, 0, + OTG_VERTICAL_INTERRUPT2_LINE_START, vertical_line_start); + + /* v_sync polarity */ + v_sync_polarity = patched_crtc_timing.flags.VSYNC_POSITIVE_POLARITY ? + 0 : 1; + + REG_UPDATE(OTG_V_SYNC_A_CNTL, + OTG_V_SYNC_A_POL, v_sync_polarity); + + v_init = asic_blank_start; + if (optc->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT || + optc->dlg_otg_param.signal == SIGNAL_TYPE_DISPLAY_PORT_MST || + optc->dlg_otg_param.signal == SIGNAL_TYPE_EDP) { + start_point = 1; + if (patched_crtc_timing.flags.INTERLACE == 1) + field_num = 1; + } + v_fp2 = 0; + if (optc->dlg_otg_param.vstartup_start > asic_blank_end) + v_fp2 = optc->dlg_otg_param.vstartup_start > asic_blank_end; + + /* Interlace */ + if (patched_crtc_timing.flags.INTERLACE == 1) { + REG_UPDATE(OTG_INTERLACE_CONTROL, + OTG_INTERLACE_ENABLE, 1); + v_init = v_init / 2; + if ((optc->dlg_otg_param.vstartup_start/2)*2 > asic_blank_end) + v_fp2 = v_fp2 / 2; + } else + REG_UPDATE(OTG_INTERLACE_CONTROL, + OTG_INTERLACE_ENABLE, 0); + + + /* VTG enable set to 0 first VInit */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + REG_UPDATE_2(CONTROL, + VTG0_FP2, v_fp2, + VTG0_VCOUNT_INIT, v_init); + + /* original code is using VTG offset to address OTG reg, seems wrong */ + REG_UPDATE_2(OTG_CONTROL, + OTG_START_POINT_CNTL, start_point, + OTG_FIELD_NUMBER_CNTL, field_num); + + optc1_program_global_sync(optc); + + /* TODO + * patched_crtc_timing.flags.HORZ_COUNT_BY_TWO == 1 + * program_horz_count_by_2 + * for DVI 30bpp mode, 0 otherwise + * program_horz_count_by_2(optc, &patched_crtc_timing); + */ + + /* Enable stereo - only when we need to pack 3D frame. Other types + * of stereo handled in explicit call + */ + h_div_2 = (dc_crtc_timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ? + 1 : 0; + + REG_UPDATE(OTG_H_TIMING_CNTL, + OTG_H_TIMING_DIV_BY2, h_div_2); + +} + +static void optc1_set_blank_data_double_buffer(struct timing_generator *optc, bool enable) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + uint32_t blank_data_double_buffer_enable = enable ? 1 : 0; + + REG_UPDATE(OTG_DOUBLE_BUFFER_CONTROL, + OTG_BLANK_DATA_DOUBLE_BUFFER_EN, blank_data_double_buffer_enable); +} + +/** + * unblank_crtc + * Call ASIC Control Object to UnBlank CRTC. + */ +static void optc1_unblank_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t vertical_interrupt_enable = 0; + + REG_GET(OTG_VERTICAL_INTERRUPT2_CONTROL, + OTG_VERTICAL_INTERRUPT2_INT_ENABLE, &vertical_interrupt_enable); + + /* temporary work around for vertical interrupt, once vertical interrupt enabled, + * this check will be removed. + */ + if (vertical_interrupt_enable) + optc1_set_blank_data_double_buffer(optc, true); + + REG_UPDATE_2(OTG_BLANK_CONTROL, + OTG_BLANK_DATA_EN, 0, + OTG_BLANK_DE_MODE, 0); +} + +/** + * blank_crtc + * Call ASIC Control Object to Blank CRTC. + */ + +static void optc1_blank_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE_2(OTG_BLANK_CONTROL, + OTG_BLANK_DATA_EN, 1, + OTG_BLANK_DE_MODE, 0); + + optc1_set_blank_data_double_buffer(optc, false); +} + +void optc1_set_blank(struct timing_generator *optc, + bool enable_blanking) +{ + if (enable_blanking) + optc1_blank_crtc(optc); + else + optc1_unblank_crtc(optc); +} + +bool optc1_is_blanked(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t blank_en; + uint32_t blank_state; + + REG_GET_2(OTG_BLANK_CONTROL, + OTG_BLANK_DATA_EN, &blank_en, + OTG_CURRENT_BLANK_STATE, &blank_state); + + return blank_en && blank_state; +} + +void optc1_enable_optc_clock(struct timing_generator *optc, bool enable) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (enable) { + REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL, + OPTC_INPUT_CLK_EN, 1, + OPTC_INPUT_CLK_GATE_DIS, 1); + + REG_WAIT(OPTC_INPUT_CLOCK_CONTROL, + OPTC_INPUT_CLK_ON, 1, + 1, 1000); + + /* Enable clock */ + REG_UPDATE_2(OTG_CLOCK_CONTROL, + OTG_CLOCK_EN, 1, + OTG_CLOCK_GATE_DIS, 1); + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_CLOCK_ON, 1, + 1, 1000); + } else { + REG_UPDATE_2(OTG_CLOCK_CONTROL, + OTG_CLOCK_GATE_DIS, 0, + OTG_CLOCK_EN, 0); + + REG_UPDATE_2(OPTC_INPUT_CLOCK_CONTROL, + OPTC_INPUT_CLK_GATE_DIS, 0, + OPTC_INPUT_CLK_EN, 0); + } +} + +/** + * Enable CRTC + * Enable CRTC - call ASIC Control Object to enable Timing generator. + */ +static bool optc1_enable_crtc(struct timing_generator *optc) +{ + /* TODO FPGA wait for answer + * OTG_MASTER_UPDATE_MODE != CRTC_MASTER_UPDATE_MODE + * OTG_MASTER_UPDATE_LOCK != CRTC_MASTER_UPDATE_LOCK + */ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* opp instance for OTG. For DCN1.0, ODM is remoed. + * OPP and OPTC should 1:1 mapping + */ + REG_UPDATE(OPTC_DATA_SOURCE_SELECT, + OPTC_SRC_SEL, optc->inst); + + /* VTG enable first is for HW workaround */ + REG_UPDATE(CONTROL, + VTG0_ENABLE, 1); + + /* Enable CRTC */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 3, + OTG_MASTER_EN, 1); + + return true; +} + +/* disable_crtc - call ASIC Control Object to disable Timing generator. */ +bool optc1_disable_crtc(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* disable otg request until end of the first line + * in the vertical blank region + */ + REG_UPDATE_2(OTG_CONTROL, + OTG_DISABLE_POINT_CNTL, 3, + OTG_MASTER_EN, 0); + + REG_UPDATE(CONTROL, + VTG0_ENABLE, 0); + + /* CRTC disabled, so disable clock. */ + REG_WAIT(OTG_CLOCK_CONTROL, + OTG_BUSY, 0, + 1, 100000); + + return true; +} + + +void optc1_program_blank_color( + struct timing_generator *optc, + const struct tg_color *black_color) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET_3(OTG_BLACK_COLOR, 0, + OTG_BLACK_COLOR_B_CB, black_color->color_b_cb, + OTG_BLACK_COLOR_G_Y, black_color->color_g_y, + OTG_BLACK_COLOR_R_CR, black_color->color_r_cr); +} + +bool optc1_validate_timing( + struct timing_generator *optc, + const struct dc_crtc_timing *timing) +{ + uint32_t interlace_factor; + uint32_t v_blank; + uint32_t h_blank; + uint32_t min_v_blank; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + ASSERT(timing != NULL); + + interlace_factor = timing->flags.INTERLACE ? 2 : 1; + v_blank = (timing->v_total - timing->v_addressable - + timing->v_border_top - timing->v_border_bottom) * + interlace_factor; + + h_blank = (timing->h_total - timing->h_addressable - + timing->h_border_right - + timing->h_border_left); + + if (timing->timing_3d_format != TIMING_3D_FORMAT_NONE && + timing->timing_3d_format != TIMING_3D_FORMAT_HW_FRAME_PACKING && + timing->timing_3d_format != TIMING_3D_FORMAT_TOP_AND_BOTTOM && + timing->timing_3d_format != TIMING_3D_FORMAT_SIDE_BY_SIDE && + timing->timing_3d_format != TIMING_3D_FORMAT_FRAME_ALTERNATE && + timing->timing_3d_format != TIMING_3D_FORMAT_INBAND_FA) + return false; + + /* Temporarily blocking interlacing mode until it's supported */ + if (timing->flags.INTERLACE == 1) + return false; + + /* Check maximum number of pixels supported by Timing Generator + * (Currently will never fail, in order to fail needs display which + * needs more than 8192 horizontal and + * more than 8192 vertical total pixels) + */ + if (timing->h_total > optc1->max_h_total || + timing->v_total > optc1->max_v_total) + return false; + + + if (h_blank < optc1->min_h_blank) + return false; + + if (timing->h_sync_width < optc1->min_h_sync_width || + timing->v_sync_width < optc1->min_v_sync_width) + return false; + + min_v_blank = timing->flags.INTERLACE?optc1->min_v_blank_interlace:optc1->min_v_blank; + + if (v_blank < min_v_blank) + return false; + + return true; + +} + +/* + * get_vblank_counter + * + * @brief + * Get counter for vertical blanks. use register CRTC_STATUS_FRAME_COUNT which + * holds the counter of frames. + * + * @param + * struct timing_generator *optc - [in] timing generator which controls the + * desired CRTC + * + * @return + * Counter of frames, which should equal to number of vblanks. + */ +uint32_t optc1_get_vblank_counter(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t frame_count; + + REG_GET(OTG_STATUS_FRAME_COUNT, + OTG_FRAME_COUNT, &frame_count); + + return frame_count; +} + +void optc1_lock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_GLOBAL_CONTROL0, 0, + OTG_MASTER_UPDATE_LOCK_SEL, optc->inst); + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + + /* Should be fast, status does not update on maximus */ + if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS) + REG_WAIT(OTG_MASTER_UPDATE_LOCK, + UPDATE_LOCK_STATUS, 1, + 1, 10); +} + +void optc1_unlock(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 0); +} + +void optc1_get_position(struct timing_generator *optc, + struct crtc_position *position) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET_2(OTG_STATUS_POSITION, + OTG_HORZ_COUNT, &position->horizontal_count, + OTG_VERT_COUNT, &position->vertical_count); + + REG_GET(OTG_NOM_VERT_POSITION, + OTG_VERT_COUNT_NOM, &position->nominal_vcount); +} + +bool optc1_is_counter_moving(struct timing_generator *optc) +{ + struct crtc_position position1, position2; + + optc->funcs->get_position(optc, &position1); + optc->funcs->get_position(optc, &position2); + + if (position1.horizontal_count == position2.horizontal_count && + position1.vertical_count == position2.vertical_count) + return false; + else + return true; +} + +bool optc1_did_triggered_reset_occur( + struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t occurred_force, occurred_vsync; + + REG_GET(OTG_FORCE_COUNT_NOW_CNTL, + OTG_FORCE_COUNT_NOW_OCCURRED, &occurred_force); + + REG_GET(OTG_VERT_SYNC_CONTROL, + OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, &occurred_vsync); + + return occurred_vsync != 0 || occurred_force != 0; +} + +void optc1_disable_reset_trigger(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_WRITE(OTG_TRIGA_CNTL, 0); + + REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, + OTG_FORCE_COUNT_NOW_CLEAR, 1); + + REG_SET(OTG_VERT_SYNC_CONTROL, 0, + OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, 1); +} + +void optc1_enable_reset_trigger(struct timing_generator *optc, int source_tg_inst) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t falling_edge; + + REG_GET(OTG_V_SYNC_A_CNTL, + OTG_V_SYNC_A_POL, &falling_edge); + + if (falling_edge) + REG_SET_3(OTG_TRIGA_CNTL, 0, + /* vsync signal from selected OTG pipe based + * on OTG_TRIG_SOURCE_PIPE_SELECT setting + */ + OTG_TRIGA_SOURCE_SELECT, 20, + OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, + /* always detect falling edge */ + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 1); + else + REG_SET_3(OTG_TRIGA_CNTL, 0, + /* vsync signal from selected OTG pipe based + * on OTG_TRIG_SOURCE_PIPE_SELECT setting + */ + OTG_TRIGA_SOURCE_SELECT, 20, + OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, + /* always detect rising edge */ + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1); + + REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, + /* force H count to H_TOTAL and V count to V_TOTAL in + * progressive mode and V_TOTAL-1 in interlaced mode + */ + OTG_FORCE_COUNT_NOW_MODE, 2); +} + +void optc1_enable_crtc_reset( + struct timing_generator *optc, + int source_tg_inst, + struct crtc_trigger_info *crtc_tp) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t falling_edge = 0; + uint32_t rising_edge = 0; + + switch (crtc_tp->event) { + + case CRTC_EVENT_VSYNC_RISING: + rising_edge = 1; + break; + + case CRTC_EVENT_VSYNC_FALLING: + falling_edge = 1; + break; + } + + REG_SET_4(OTG_TRIGA_CNTL, 0, + /* vsync signal from selected OTG pipe based + * on OTG_TRIG_SOURCE_PIPE_SELECT setting + */ + OTG_TRIGA_SOURCE_SELECT, 20, + OTG_TRIGA_SOURCE_PIPE_SELECT, source_tg_inst, + /* always detect falling edge */ + OTG_TRIGA_RISING_EDGE_DETECT_CNTL, rising_edge, + OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, falling_edge); + + switch (crtc_tp->delay) { + case TRIGGER_DELAY_NEXT_LINE: + REG_SET(OTG_VERT_SYNC_CONTROL, 0, + OTG_AUTO_FORCE_VSYNC_MODE, 1); + break; + case TRIGGER_DELAY_NEXT_PIXEL: + REG_SET(OTG_FORCE_COUNT_NOW_CNTL, 0, + /* force H count to H_TOTAL and V count to V_TOTAL in + * progressive mode and V_TOTAL-1 in interlaced mode + */ + OTG_FORCE_COUNT_NOW_MODE, 2); + break; + } +} + +void optc1_wait_for_state(struct timing_generator *optc, + enum crtc_state state) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + switch (state) { + case CRTC_STATE_VBLANK: + REG_WAIT(OTG_STATUS, + OTG_V_BLANK, 1, + 1, 100000); /* 1 vupdate at 10hz */ + break; + + case CRTC_STATE_VACTIVE: + REG_WAIT(OTG_STATUS, + OTG_V_ACTIVE_DISP, 1, + 1, 100000); /* 1 vupdate at 10hz */ + break; + + default: + break; + } +} + +void optc1_set_early_control( + struct timing_generator *optc, + uint32_t early_cntl) +{ + /* asic design change, do not need this control + * empty for share caller logic + */ +} + + +void optc1_set_static_screen_control( + struct timing_generator *optc, + uint32_t value) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + /* Bit 8 is no longer applicable in RV for PSR case, + * set bit 8 to 0 if given + */ + if ((value & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN) + != 0) + value = value & + ~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN; + + REG_SET_2(OTG_STATIC_SCREEN_CONTROL, 0, + OTG_STATIC_SCREEN_EVENT_MASK, value, + OTG_STATIC_SCREEN_FRAME_COUNT, 2); +} + + +/** + ***************************************************************************** + * Function: set_drr + * + * @brief + * Program dynamic refresh rate registers m_OTGx_OTG_V_TOTAL_*. + * + ***************************************************************************** + */ +void optc1_set_drr( + struct timing_generator *optc, + const struct drr_params *params) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (params != NULL && + params->vertical_total_max > 0 && + params->vertical_total_min > 0) { + + REG_SET(OTG_V_TOTAL_MAX, 0, + OTG_V_TOTAL_MAX, params->vertical_total_max - 1); + + REG_SET(OTG_V_TOTAL_MIN, 0, + OTG_V_TOTAL_MIN, params->vertical_total_min - 1); + + REG_UPDATE_5(OTG_V_TOTAL_CONTROL, + OTG_V_TOTAL_MIN_SEL, 1, + OTG_V_TOTAL_MAX_SEL, 1, + OTG_FORCE_LOCK_ON_EVENT, 0, + OTG_SET_V_TOTAL_MIN_MASK_EN, 0, + OTG_SET_V_TOTAL_MIN_MASK, 0); + } else { + REG_SET(OTG_V_TOTAL_MIN, 0, + OTG_V_TOTAL_MIN, 0); + + REG_SET(OTG_V_TOTAL_MAX, 0, + OTG_V_TOTAL_MAX, 0); + + REG_UPDATE_4(OTG_V_TOTAL_CONTROL, + OTG_SET_V_TOTAL_MIN_MASK, 0, + OTG_V_TOTAL_MIN_SEL, 0, + OTG_V_TOTAL_MAX_SEL, 0, + OTG_FORCE_LOCK_ON_EVENT, 0); + } +} + +static void optc1_set_test_pattern( + struct timing_generator *optc, + /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode' + * because this is not DP-specific (which is probably somewhere in DP + * encoder) */ + enum controller_dp_test_pattern test_pattern, + enum dc_color_depth color_depth) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + enum test_pattern_color_format bit_depth; + enum test_pattern_dyn_range dyn_range; + enum test_pattern_mode mode; + uint32_t pattern_mask; + uint32_t pattern_data; + /* color ramp generator mixes 16-bits color */ + uint32_t src_bpc = 16; + /* requested bpc */ + uint32_t dst_bpc; + uint32_t index; + /* RGB values of the color bars. + * Produce two RGB colors: RGB0 - white (all Fs) + * and RGB1 - black (all 0s) + * (three RGB components for two colors) + */ + uint16_t src_color[6] = {0xFFFF, 0xFFFF, 0xFFFF, 0x0000, + 0x0000, 0x0000}; + /* dest color (converted to the specified color format) */ + uint16_t dst_color[6]; + uint32_t inc_base; + + /* translate to bit depth */ + switch (color_depth) { + case COLOR_DEPTH_666: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_6; + break; + case COLOR_DEPTH_888: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; + break; + case COLOR_DEPTH_101010: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_10; + break; + case COLOR_DEPTH_121212: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_12; + break; + default: + bit_depth = TEST_PATTERN_COLOR_FORMAT_BPC_8; + break; + } + + switch (test_pattern) { + case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES: + case CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA: + { + dyn_range = (test_pattern == + CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA ? + TEST_PATTERN_DYN_RANGE_CEA : + TEST_PATTERN_DYN_RANGE_VESA); + mode = TEST_PATTERN_MODE_COLORSQUARES_RGB; + + REG_UPDATE_2(OTG_TEST_PATTERN_PARAMETERS, + OTG_TEST_PATTERN_VRES, 6, + OTG_TEST_PATTERN_HRES, 6); + + REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL, + OTG_TEST_PATTERN_EN, 1, + OTG_TEST_PATTERN_MODE, mode, + OTG_TEST_PATTERN_DYNAMIC_RANGE, dyn_range, + OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); + } + break; + + case CONTROLLER_DP_TEST_PATTERN_VERTICALBARS: + case CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS: + { + mode = (test_pattern == + CONTROLLER_DP_TEST_PATTERN_VERTICALBARS ? + TEST_PATTERN_MODE_VERTICALBARS : + TEST_PATTERN_MODE_HORIZONTALBARS); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + dst_bpc = 6; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + dst_bpc = 8; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + dst_bpc = 10; + break; + default: + dst_bpc = 8; + break; + } + + /* adjust color to the required colorFormat */ + for (index = 0; index < 6; index++) { + /* dst = 2^dstBpc * src / 2^srcBpc = src >> + * (srcBpc - dstBpc); + */ + dst_color[index] = + src_color[index] >> (src_bpc - dst_bpc); + /* CRTC_TEST_PATTERN_DATA has 16 bits, + * lowest 6 are hardwired to ZERO + * color bits should be left aligned aligned to MSB + * XXXXXXXXXX000000 for 10 bit, + * XXXXXXXX00000000 for 8 bit and XXXXXX0000000000 for 6 + */ + dst_color[index] <<= (16 - dst_bpc); + } + + REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0); + + /* We have to write the mask before data, similar to pipeline. + * For example, for 8 bpc, if we want RGB0 to be magenta, + * and RGB1 to be cyan, + * we need to make 7 writes: + * MASK DATA + * 000001 00000000 00000000 set mask to R0 + * 000010 11111111 00000000 R0 255, 0xFF00, set mask to G0 + * 000100 00000000 00000000 G0 0, 0x0000, set mask to B0 + * 001000 11111111 00000000 B0 255, 0xFF00, set mask to R1 + * 010000 00000000 00000000 R1 0, 0x0000, set mask to G1 + * 100000 11111111 00000000 G1 255, 0xFF00, set mask to B1 + * 100000 11111111 00000000 B1 255, 0xFF00 + * + * we will make a loop of 6 in which we prepare the mask, + * then write, then prepare the color for next write. + * first iteration will write mask only, + * but each next iteration color prepared in + * previous iteration will be written within new mask, + * the last component will written separately, + * mask is not changing between 6th and 7th write + * and color will be prepared by last iteration + */ + + /* write color, color values mask in CRTC_TEST_PATTERN_MASK + * is B1, G1, R1, B0, G0, R0 + */ + pattern_data = 0; + for (index = 0; index < 6; index++) { + /* prepare color mask, first write PATTERN_DATA + * will have all zeros + */ + pattern_mask = (1 << index); + + /* write color component */ + REG_SET_2(OTG_TEST_PATTERN_COLOR, 0, + OTG_TEST_PATTERN_MASK, pattern_mask, + OTG_TEST_PATTERN_DATA, pattern_data); + + /* prepare next color component, + * will be written in the next iteration + */ + pattern_data = dst_color[index]; + } + /* write last color component, + * it's been already prepared in the loop + */ + REG_SET_2(OTG_TEST_PATTERN_COLOR, 0, + OTG_TEST_PATTERN_MASK, pattern_mask, + OTG_TEST_PATTERN_DATA, pattern_data); + + /* enable test pattern */ + REG_UPDATE_4(OTG_TEST_PATTERN_CONTROL, + OTG_TEST_PATTERN_EN, 1, + OTG_TEST_PATTERN_MODE, mode, + OTG_TEST_PATTERN_DYNAMIC_RANGE, 0, + OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); + } + break; + + case CONTROLLER_DP_TEST_PATTERN_COLORRAMP: + { + mode = (bit_depth == + TEST_PATTERN_COLOR_FORMAT_BPC_10 ? + TEST_PATTERN_MODE_DUALRAMP_RGB : + TEST_PATTERN_MODE_SINGLERAMP_RGB); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + dst_bpc = 6; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + dst_bpc = 8; + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + dst_bpc = 10; + break; + default: + dst_bpc = 8; + break; + } + + /* increment for the first ramp for one color gradation + * 1 gradation for 6-bit color is 2^10 + * gradations in 16-bit color + */ + inc_base = (src_bpc - dst_bpc); + + switch (bit_depth) { + case TEST_PATTERN_COLOR_FORMAT_BPC_6: + { + REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, + OTG_TEST_PATTERN_INC0, inc_base, + OTG_TEST_PATTERN_INC1, 0, + OTG_TEST_PATTERN_HRES, 6, + OTG_TEST_PATTERN_VRES, 6, + OTG_TEST_PATTERN_RAMP0_OFFSET, 0); + } + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_8: + { + REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, + OTG_TEST_PATTERN_INC0, inc_base, + OTG_TEST_PATTERN_INC1, 0, + OTG_TEST_PATTERN_HRES, 8, + OTG_TEST_PATTERN_VRES, 6, + OTG_TEST_PATTERN_RAMP0_OFFSET, 0); + } + break; + case TEST_PATTERN_COLOR_FORMAT_BPC_10: + { + REG_UPDATE_5(OTG_TEST_PATTERN_PARAMETERS, + OTG_TEST_PATTERN_INC0, inc_base, + OTG_TEST_PATTERN_INC1, inc_base + 2, + OTG_TEST_PATTERN_HRES, 8, + OTG_TEST_PATTERN_VRES, 5, + OTG_TEST_PATTERN_RAMP0_OFFSET, 384 << 6); + } + break; + default: + break; + } + + REG_WRITE(OTG_TEST_PATTERN_COLOR, 0); + + /* enable test pattern */ + REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0); + + REG_SET_4(OTG_TEST_PATTERN_CONTROL, 0, + OTG_TEST_PATTERN_EN, 1, + OTG_TEST_PATTERN_MODE, mode, + OTG_TEST_PATTERN_DYNAMIC_RANGE, 0, + OTG_TEST_PATTERN_COLOR_FORMAT, bit_depth); + } + break; + case CONTROLLER_DP_TEST_PATTERN_VIDEOMODE: + { + REG_WRITE(OTG_TEST_PATTERN_CONTROL, 0); + REG_WRITE(OTG_TEST_PATTERN_COLOR, 0); + REG_WRITE(OTG_TEST_PATTERN_PARAMETERS, 0); + } + break; + default: + break; + + } +} + +void optc1_get_crtc_scanoutpos( + struct timing_generator *optc, + uint32_t *v_blank_start, + uint32_t *v_blank_end, + uint32_t *h_position, + uint32_t *v_position) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + struct crtc_position position; + + REG_GET_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, v_blank_start, + OTG_V_BLANK_END, v_blank_end); + + optc1_get_position(optc, &position); + + *h_position = position.horizontal_count; + *v_position = position.vertical_count; +} + +static void optc1_enable_stereo(struct timing_generator *optc, + const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + if (flags) { + uint32_t stereo_en; + stereo_en = flags->FRAME_PACKED == 0 ? 1 : 0; + + if (flags->PROGRAM_STEREO) + REG_UPDATE_3(OTG_STEREO_CONTROL, + OTG_STEREO_EN, stereo_en, + OTG_STEREO_SYNC_OUTPUT_LINE_NUM, 0, + OTG_STEREO_SYNC_OUTPUT_POLARITY, 0); + + if (flags->PROGRAM_POLARITY) + REG_UPDATE(OTG_STEREO_CONTROL, + OTG_STEREO_EYE_FLAG_POLARITY, + flags->RIGHT_EYE_POLARITY == 0 ? 0 : 1); + + if (flags->DISABLE_STEREO_DP_SYNC) + REG_UPDATE(OTG_STEREO_CONTROL, + OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, 1); + + if (flags->PROGRAM_STEREO) + REG_UPDATE_3(OTG_3D_STRUCTURE_CONTROL, + OTG_3D_STRUCTURE_EN, flags->FRAME_PACKED, + OTG_3D_STRUCTURE_V_UPDATE_MODE, flags->FRAME_PACKED, + OTG_3D_STRUCTURE_STEREO_SEL_OVR, flags->FRAME_PACKED); + + } +} + +void optc1_program_stereo(struct timing_generator *optc, + const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags) +{ + if (flags->PROGRAM_STEREO) + optc1_enable_stereo(optc, timing, flags); + else + optc1_disable_stereo(optc); +} + + +bool optc1_is_stereo_left_eye(struct timing_generator *optc) +{ + bool ret = false; + uint32_t left_eye = 0; + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_GET(OTG_STEREO_STATUS, + OTG_STEREO_CURRENT_EYE, &left_eye); + if (left_eye == 1) + ret = true; + else + ret = false; + + return ret; +} + +void optc1_read_otg_state(struct optc *optc1, + struct dcn_otg_state *s) +{ + REG_GET(OTG_CONTROL, + OTG_MASTER_EN, &s->otg_enabled); + + REG_GET_2(OTG_V_BLANK_START_END, + OTG_V_BLANK_START, &s->v_blank_start, + OTG_V_BLANK_END, &s->v_blank_end); + + REG_GET(OTG_V_SYNC_A_CNTL, + OTG_V_SYNC_A_POL, &s->v_sync_a_pol); + + REG_GET(OTG_V_TOTAL, + OTG_V_TOTAL, &s->v_total); + + REG_GET(OTG_V_TOTAL_MAX, + OTG_V_TOTAL_MAX, &s->v_total_max); + + REG_GET(OTG_V_TOTAL_MIN, + OTG_V_TOTAL_MIN, &s->v_total_min); + + REG_GET_2(OTG_V_SYNC_A, + OTG_V_SYNC_A_START, &s->v_sync_a_start, + OTG_V_SYNC_A_END, &s->v_sync_a_end); + + REG_GET_2(OTG_H_BLANK_START_END, + OTG_H_BLANK_START, &s->h_blank_start, + OTG_H_BLANK_END, &s->h_blank_end); + + REG_GET_2(OTG_H_SYNC_A, + OTG_H_SYNC_A_START, &s->h_sync_a_start, + OTG_H_SYNC_A_END, &s->h_sync_a_end); + + REG_GET(OTG_H_SYNC_A_CNTL, + OTG_H_SYNC_A_POL, &s->h_sync_a_pol); + + REG_GET(OTG_H_TOTAL, + OTG_H_TOTAL, &s->h_total); + + REG_GET(OPTC_INPUT_GLOBAL_CONTROL, + OPTC_UNDERFLOW_OCCURRED_STATUS, &s->underflow_occurred_status); +} + +static void optc1_clear_optc_underflow(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + + REG_UPDATE(OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, 1); +} + +static void optc1_tg_init(struct timing_generator *optc) +{ + optc1_set_blank_data_double_buffer(optc, true); + optc1_clear_optc_underflow(optc); +} + +static bool optc1_is_tg_enabled(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t otg_enabled = 0; + + REG_GET(OTG_CONTROL, OTG_MASTER_EN, &otg_enabled); + + return (otg_enabled != 0); + +} + +static bool optc1_is_optc_underflow_occurred(struct timing_generator *optc) +{ + struct optc *optc1 = DCN10TG_FROM_TG(optc); + uint32_t underflow_occurred = 0; + + REG_GET(OPTC_INPUT_GLOBAL_CONTROL, + OPTC_UNDERFLOW_OCCURRED_STATUS, + &underflow_occurred); + + return (underflow_occurred == 1); +} + +static const struct timing_generator_funcs dcn10_tg_funcs = { + .validate_timing = optc1_validate_timing, + .program_timing = optc1_program_timing, + .program_global_sync = optc1_program_global_sync, + .enable_crtc = optc1_enable_crtc, + .disable_crtc = optc1_disable_crtc, + /* used by enable_timing_synchronization. Not need for FPGA */ + .is_counter_moving = optc1_is_counter_moving, + .get_position = optc1_get_position, + .get_frame_count = optc1_get_vblank_counter, + .get_scanoutpos = optc1_get_crtc_scanoutpos, + .set_early_control = optc1_set_early_control, + /* used by enable_timing_synchronization. Not need for FPGA */ + .wait_for_state = optc1_wait_for_state, + .set_blank = optc1_set_blank, + .is_blanked = optc1_is_blanked, + .set_blank_color = optc1_program_blank_color, + .did_triggered_reset_occur = optc1_did_triggered_reset_occur, + .enable_reset_trigger = optc1_enable_reset_trigger, + .enable_crtc_reset = optc1_enable_crtc_reset, + .disable_reset_trigger = optc1_disable_reset_trigger, + .lock = optc1_lock, + .unlock = optc1_unlock, + .enable_optc_clock = optc1_enable_optc_clock, + .set_drr = optc1_set_drr, + .set_static_screen_control = optc1_set_static_screen_control, + .set_test_pattern = optc1_set_test_pattern, + .program_stereo = optc1_program_stereo, + .is_stereo_left_eye = optc1_is_stereo_left_eye, + .set_blank_data_double_buffer = optc1_set_blank_data_double_buffer, + .tg_init = optc1_tg_init, + .is_tg_enabled = optc1_is_tg_enabled, + .is_optc_underflow_occurred = optc1_is_optc_underflow_occurred, + .clear_optc_underflow = optc1_clear_optc_underflow, +}; + +void dcn10_timing_generator_init(struct optc *optc1) +{ + optc1->base.funcs = &dcn10_tg_funcs; + + optc1->max_h_total = optc1->tg_mask->OTG_H_TOTAL + 1; + optc1->max_v_total = optc1->tg_mask->OTG_V_TOTAL + 1; + + optc1->min_h_blank = 32; + optc1->min_v_blank = 3; + optc1->min_v_blank_interlace = 5; + optc1->min_h_sync_width = 8; + optc1->min_v_sync_width = 1; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h new file mode 100644 index 000000000000..a3c7c2012f05 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_optc.h @@ -0,0 +1,482 @@ +/* + * Copyright 2012-15 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_TIMING_GENERATOR_DCN10_H__ +#define __DC_TIMING_GENERATOR_DCN10_H__ + +#include "timing_generator.h" + +#define DCN10TG_FROM_TG(tg)\ + container_of(tg, struct optc, base) + +#define TG_COMMON_REG_LIST_DCN(inst) \ + SRI(OTG_VSTARTUP_PARAM, OTG, inst),\ + SRI(OTG_VUPDATE_PARAM, OTG, inst),\ + SRI(OTG_VREADY_PARAM, OTG, inst),\ + SRI(OTG_BLANK_CONTROL, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ + SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ + SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ + SRI(OTG_H_TOTAL, OTG, inst),\ + SRI(OTG_H_BLANK_START_END, OTG, inst),\ + SRI(OTG_H_SYNC_A, OTG, inst),\ + SRI(OTG_H_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_H_TIMING_CNTL, OTG, inst),\ + SRI(OTG_V_TOTAL, OTG, inst),\ + SRI(OTG_V_BLANK_START_END, OTG, inst),\ + SRI(OTG_V_SYNC_A, OTG, inst),\ + SRI(OTG_V_SYNC_A_CNTL, OTG, inst),\ + SRI(OTG_INTERLACE_CONTROL, OTG, inst),\ + SRI(OTG_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_CONTROL, OTG, inst),\ + SRI(OTG_3D_STRUCTURE_CONTROL, OTG, inst),\ + SRI(OTG_STEREO_STATUS, OTG, inst),\ + SRI(OTG_V_TOTAL_MAX, OTG, inst),\ + SRI(OTG_V_TOTAL_MIN, OTG, inst),\ + SRI(OTG_V_TOTAL_CONTROL, OTG, inst),\ + SRI(OTG_TRIGA_CNTL, OTG, inst),\ + SRI(OTG_FORCE_COUNT_NOW_CNTL, OTG, inst),\ + SRI(OTG_STATIC_SCREEN_CONTROL, OTG, inst),\ + SRI(OTG_STATUS_FRAME_COUNT, OTG, inst),\ + SRI(OTG_STATUS, OTG, inst),\ + SRI(OTG_STATUS_POSITION, OTG, inst),\ + SRI(OTG_NOM_VERT_POSITION, OTG, inst),\ + SRI(OTG_BLACK_COLOR, OTG, inst),\ + SRI(OTG_CLOCK_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_CONTROL, OTG, inst),\ + SRI(OTG_VERTICAL_INTERRUPT2_POSITION, OTG, inst),\ + SRI(OPTC_INPUT_CLOCK_CONTROL, ODM, inst),\ + SRI(OPTC_DATA_SOURCE_SELECT, ODM, inst),\ + SRI(OPTC_INPUT_GLOBAL_CONTROL, ODM, inst),\ + SRI(CONTROL, VTG, inst),\ + SRI(OTG_VERT_SYNC_CONTROL, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_MODE, OTG, inst),\ + SRI(OTG_GSL_CONTROL, OTG, inst) + +#define TG_COMMON_REG_LIST_DCN1_0(inst) \ + TG_COMMON_REG_LIST_DCN(inst),\ + SRI(OTG_TEST_PATTERN_PARAMETERS, OTG, inst),\ + SRI(OTG_TEST_PATTERN_CONTROL, OTG, inst),\ + SRI(OTG_TEST_PATTERN_COLOR, OTG, inst) + + +struct dcn_optc_registers { + uint32_t OTG_VERT_SYNC_CONTROL; + uint32_t OTG_MASTER_UPDATE_MODE; + uint32_t OTG_GSL_CONTROL; + uint32_t OTG_VSTARTUP_PARAM; + uint32_t OTG_VUPDATE_PARAM; + uint32_t OTG_VREADY_PARAM; + uint32_t OTG_BLANK_CONTROL; + uint32_t OTG_MASTER_UPDATE_LOCK; + uint32_t OTG_GLOBAL_CONTROL0; + uint32_t OTG_DOUBLE_BUFFER_CONTROL; + uint32_t OTG_H_TOTAL; + uint32_t OTG_H_BLANK_START_END; + uint32_t OTG_H_SYNC_A; + uint32_t OTG_H_SYNC_A_CNTL; + uint32_t OTG_H_TIMING_CNTL; + uint32_t OTG_V_TOTAL; + uint32_t OTG_V_BLANK_START_END; + uint32_t OTG_V_SYNC_A; + uint32_t OTG_V_SYNC_A_CNTL; + uint32_t OTG_INTERLACE_CONTROL; + uint32_t OTG_CONTROL; + uint32_t OTG_STEREO_CONTROL; + uint32_t OTG_3D_STRUCTURE_CONTROL; + uint32_t OTG_STEREO_STATUS; + uint32_t OTG_V_TOTAL_MAX; + uint32_t OTG_V_TOTAL_MIN; + uint32_t OTG_V_TOTAL_CONTROL; + uint32_t OTG_TRIGA_CNTL; + uint32_t OTG_FORCE_COUNT_NOW_CNTL; + uint32_t OTG_STATIC_SCREEN_CONTROL; + uint32_t OTG_STATUS_FRAME_COUNT; + uint32_t OTG_STATUS; + uint32_t OTG_STATUS_POSITION; + uint32_t OTG_NOM_VERT_POSITION; + uint32_t OTG_BLACK_COLOR; + uint32_t OTG_TEST_PATTERN_PARAMETERS; + uint32_t OTG_TEST_PATTERN_CONTROL; + uint32_t OTG_TEST_PATTERN_COLOR; + uint32_t OTG_CLOCK_CONTROL; + uint32_t OTG_VERTICAL_INTERRUPT2_CONTROL; + uint32_t OTG_VERTICAL_INTERRUPT2_POSITION; + uint32_t OPTC_INPUT_CLOCK_CONTROL; + uint32_t OPTC_DATA_SOURCE_SELECT; + uint32_t OPTC_INPUT_GLOBAL_CONTROL; + uint32_t CONTROL; + uint32_t OTG_GSL_WINDOW_X; + uint32_t OTG_GSL_WINDOW_Y; + uint32_t OTG_VUPDATE_KEEPOUT; + uint32_t OTG_DSC_START_POSITION; +}; + +#define TG_COMMON_MASK_SH_LIST_DCN(mask_sh)\ + SF(OTG0_OTG_VSTARTUP_PARAM, VSTARTUP_START, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_OFFSET, mask_sh),\ + SF(OTG0_OTG_VUPDATE_PARAM, VUPDATE_WIDTH, mask_sh),\ + SF(OTG0_OTG_VREADY_PARAM, VREADY_OFFSET, mask_sh),\ + SF(OTG0_OTG_BLANK_CONTROL, OTG_BLANK_DATA_EN, mask_sh),\ + SF(OTG0_OTG_BLANK_CONTROL, OTG_BLANK_DE_MODE, mask_sh),\ + SF(OTG0_OTG_BLANK_CONTROL, OTG_CURRENT_BLANK_STATE, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, UPDATE_LOCK_STATUS, mask_sh),\ + SF(OTG0_OTG_GLOBAL_CONTROL0, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_BLANK_DATA_DOUBLE_BUFFER_EN, mask_sh),\ + SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_START, mask_sh),\ + SF(OTG0_OTG_H_BLANK_START_END, OTG_H_BLANK_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A, OTG_H_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_H_SYNC_A_CNTL, OTG_H_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, mask_sh),\ + SF(OTG0_OTG_V_TOTAL, OTG_V_TOTAL, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_START, mask_sh),\ + SF(OTG0_OTG_V_BLANK_START_END, OTG_V_BLANK_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_START, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A, OTG_V_SYNC_A_END, mask_sh),\ + SF(OTG0_OTG_V_SYNC_A_CNTL, OTG_V_SYNC_A_POL, mask_sh),\ + SF(OTG0_OTG_INTERLACE_CONTROL, OTG_INTERLACE_ENABLE, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_START_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_DISABLE_POINT_CNTL, mask_sh),\ + SF(OTG0_OTG_CONTROL, OTG_FIELD_NUMBER_CNTL, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EN, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_LINE_NUM, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_SYNC_OUTPUT_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_STEREO_EYE_FLAG_POLARITY, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_CONTROL, OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP, mask_sh),\ + SF(OTG0_OTG_STEREO_STATUS, OTG_STEREO_CURRENT_EYE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_EN, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_V_UPDATE_MODE, mask_sh),\ + SF(OTG0_OTG_3D_STRUCTURE_CONTROL, OTG_3D_STRUCTURE_STEREO_SEL_OVR, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MAX, OTG_V_TOTAL_MAX, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_MIN, OTG_V_TOTAL_MIN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MIN_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_V_TOTAL_MAX_SEL, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_FORCE_LOCK_ON_EVENT, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK_EN, mask_sh),\ + SF(OTG0_OTG_V_TOTAL_CONTROL, OTG_SET_V_TOTAL_MIN_MASK, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_CLEAR, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_MODE, mask_sh),\ + SF(OTG0_OTG_FORCE_COUNT_NOW_CNTL, OTG_FORCE_COUNT_NOW_OCCURRED, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\ + SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_BLANK, mask_sh),\ + SF(OTG0_OTG_STATUS, OTG_V_ACTIVE_DISP, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_HORZ_COUNT, mask_sh),\ + SF(OTG0_OTG_STATUS_POSITION, OTG_VERT_COUNT, mask_sh),\ + SF(OTG0_OTG_NOM_VERT_POSITION, OTG_VERT_COUNT_NOM, mask_sh),\ + SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_B_CB, mask_sh),\ + SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_G_Y, mask_sh),\ + SF(OTG0_OTG_BLACK_COLOR, OTG_BLACK_COLOR_R_CR, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_BUSY, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_EN, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_ON, mask_sh),\ + SF(OTG0_OTG_CLOCK_CONTROL, OTG_CLOCK_GATE_DIS, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_CONTROL, OTG_VERTICAL_INTERRUPT2_INT_ENABLE, mask_sh),\ + SF(OTG0_OTG_VERTICAL_INTERRUPT2_POSITION, OTG_VERTICAL_INTERRUPT2_LINE_START, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_EN, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_ON, mask_sh),\ + SF(ODM0_OPTC_INPUT_CLOCK_CONTROL, OPTC_INPUT_CLK_GATE_DIS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_OCCURRED_STATUS, mask_sh),\ + SF(ODM0_OPTC_INPUT_GLOBAL_CONTROL, OPTC_UNDERFLOW_CLEAR, mask_sh),\ + SF(VTG0_CONTROL, VTG0_ENABLE, mask_sh),\ + SF(VTG0_CONTROL, VTG0_FP2, mask_sh),\ + SF(VTG0_CONTROL, VTG0_VCOUNT_INIT, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_FORCE_VSYNC_NEXT_LINE_CLEAR, mask_sh),\ + SF(OTG0_OTG_VERT_SYNC_CONTROL, OTG_AUTO_FORCE_VSYNC_MODE, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_MODE, MASTER_UPDATE_INTERLACED_MODE, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL0_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL1_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL2_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_MASTER_EN, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_FORCE_DELAY, mask_sh),\ + SF(OTG0_OTG_GSL_CONTROL, OTG_GSL_CHECK_ALL_FIELDS, mask_sh) + + +#define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\ + TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_INC0, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_INC1, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_VRES, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_HRES, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_PARAMETERS, OTG_TEST_PATTERN_RAMP0_OFFSET, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_EN, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_MODE, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_DYNAMIC_RANGE, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_COLOR_FORMAT, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_MASK, mask_sh),\ + SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_DATA, mask_sh),\ + SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh) + +#define TG_REG_FIELD_LIST(type) \ + type VSTARTUP_START;\ + type VUPDATE_OFFSET;\ + type VUPDATE_WIDTH;\ + type VREADY_OFFSET;\ + type OTG_BLANK_DATA_EN;\ + type OTG_BLANK_DE_MODE;\ + type OTG_CURRENT_BLANK_STATE;\ + type OTG_MASTER_UPDATE_LOCK;\ + type UPDATE_LOCK_STATUS;\ + type OTG_UPDATE_PENDING;\ + type OTG_MASTER_UPDATE_LOCK_SEL;\ + type OTG_BLANK_DATA_DOUBLE_BUFFER_EN;\ + type OTG_H_TOTAL;\ + type OTG_H_BLANK_START;\ + type OTG_H_BLANK_END;\ + type OTG_H_SYNC_A_START;\ + type OTG_H_SYNC_A_END;\ + type OTG_H_SYNC_A_POL;\ + type OTG_H_TIMING_DIV_BY2;\ + type OTG_V_TOTAL;\ + type OTG_V_BLANK_START;\ + type OTG_V_BLANK_END;\ + type OTG_V_SYNC_A_START;\ + type OTG_V_SYNC_A_END;\ + type OTG_V_SYNC_A_POL;\ + type OTG_INTERLACE_ENABLE;\ + type OTG_MASTER_EN;\ + type OTG_START_POINT_CNTL;\ + type OTG_DISABLE_POINT_CNTL;\ + type OTG_FIELD_NUMBER_CNTL;\ + type OTG_STEREO_EN;\ + type OTG_STEREO_SYNC_OUTPUT_LINE_NUM;\ + type OTG_STEREO_SYNC_OUTPUT_POLARITY;\ + type OTG_STEREO_EYE_FLAG_POLARITY;\ + type OTG_STEREO_CURRENT_EYE;\ + type OTG_DISABLE_STEREOSYNC_OUTPUT_FOR_DP;\ + type OTG_3D_STRUCTURE_EN;\ + type OTG_3D_STRUCTURE_V_UPDATE_MODE;\ + type OTG_3D_STRUCTURE_STEREO_SEL_OVR;\ + type OTG_V_TOTAL_MAX;\ + type OTG_V_TOTAL_MIN;\ + type OTG_V_TOTAL_MIN_SEL;\ + type OTG_V_TOTAL_MAX_SEL;\ + type OTG_FORCE_LOCK_ON_EVENT;\ + type OTG_SET_V_TOTAL_MIN_MASK_EN;\ + type OTG_SET_V_TOTAL_MIN_MASK;\ + type OTG_FORCE_COUNT_NOW_CLEAR;\ + type OTG_FORCE_COUNT_NOW_MODE;\ + type OTG_FORCE_COUNT_NOW_OCCURRED;\ + type OTG_TRIGA_SOURCE_SELECT;\ + type OTG_TRIGA_SOURCE_PIPE_SELECT;\ + type OTG_TRIGA_RISING_EDGE_DETECT_CNTL;\ + type OTG_TRIGA_FALLING_EDGE_DETECT_CNTL;\ + type OTG_STATIC_SCREEN_EVENT_MASK;\ + type OTG_STATIC_SCREEN_FRAME_COUNT;\ + type OTG_FRAME_COUNT;\ + type OTG_V_BLANK;\ + type OTG_V_ACTIVE_DISP;\ + type OTG_HORZ_COUNT;\ + type OTG_VERT_COUNT;\ + type OTG_VERT_COUNT_NOM;\ + type OTG_BLACK_COLOR_B_CB;\ + type OTG_BLACK_COLOR_G_Y;\ + type OTG_BLACK_COLOR_R_CR;\ + type OTG_TEST_PATTERN_INC0;\ + type OTG_TEST_PATTERN_INC1;\ + type OTG_TEST_PATTERN_VRES;\ + type OTG_TEST_PATTERN_HRES;\ + type OTG_TEST_PATTERN_RAMP0_OFFSET;\ + type OTG_TEST_PATTERN_EN;\ + type OTG_TEST_PATTERN_MODE;\ + type OTG_TEST_PATTERN_DYNAMIC_RANGE;\ + type OTG_TEST_PATTERN_COLOR_FORMAT;\ + type OTG_TEST_PATTERN_MASK;\ + type OTG_TEST_PATTERN_DATA;\ + type OTG_BUSY;\ + type OTG_CLOCK_EN;\ + type OTG_CLOCK_ON;\ + type OTG_CLOCK_GATE_DIS;\ + type OTG_VERTICAL_INTERRUPT2_INT_ENABLE;\ + type OTG_VERTICAL_INTERRUPT2_LINE_START;\ + type OPTC_INPUT_CLK_EN;\ + type OPTC_INPUT_CLK_ON;\ + type OPTC_INPUT_CLK_GATE_DIS;\ + type OPTC_SRC_SEL;\ + type OPTC_SEG0_SRC_SEL;\ + type OPTC_UNDERFLOW_OCCURRED_STATUS;\ + type OPTC_UNDERFLOW_CLEAR;\ + type VTG0_ENABLE;\ + type VTG0_FP2;\ + type VTG0_VCOUNT_INIT;\ + type OTG_FORCE_VSYNC_NEXT_LINE_OCCURRED;\ + type OTG_FORCE_VSYNC_NEXT_LINE_CLEAR;\ + type OTG_AUTO_FORCE_VSYNC_MODE;\ + type MASTER_UPDATE_INTERLACED_MODE;\ + type OTG_GSL0_EN;\ + type OTG_GSL1_EN;\ + type OTG_GSL2_EN;\ + type OTG_GSL_MASTER_EN;\ + type OTG_GSL_FORCE_DELAY;\ + type OTG_GSL_CHECK_ALL_FIELDS;\ + type OTG_GSL_WINDOW_START_X;\ + type OTG_GSL_WINDOW_END_X;\ + type OTG_GSL_WINDOW_START_Y;\ + type OTG_GSL_WINDOW_END_Y;\ + type OTG_RANGE_TIMING_DBUF_UPDATE_MODE;\ + type OTG_GSL_MASTER_MODE;\ + type OTG_MASTER_UPDATE_LOCK_GSL_EN;\ + type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_START_OFFSET;\ + type MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_END_OFFSET;\ + type OTG_DSC_START_POSITION_X;\ + type OTG_DSC_START_POSITION_LINE_NUM;\ + type OTG_MASTER_UPDATE_LOCK_VUPDATE_KEEPOUT_EN; + + +struct dcn_optc_shift { + TG_REG_FIELD_LIST(uint8_t) +}; + +struct dcn_optc_mask { + TG_REG_FIELD_LIST(uint32_t) +}; + +struct optc { + struct timing_generator base; + + const struct dcn_optc_registers *tg_regs; + const struct dcn_optc_shift *tg_shift; + const struct dcn_optc_mask *tg_mask; + + enum controller_id controller_id; + + uint32_t max_h_total; + uint32_t max_v_total; + + uint32_t min_h_blank; + + uint32_t min_h_sync_width; + uint32_t min_v_sync_width; + uint32_t min_v_blank; + uint32_t min_v_blank_interlace; +}; + +void dcn10_timing_generator_init(struct optc *optc); + +struct dcn_otg_state { + uint32_t v_blank_start; + uint32_t v_blank_end; + uint32_t v_sync_a_pol; + uint32_t v_total; + uint32_t v_total_max; + uint32_t v_total_min; + uint32_t v_sync_a_start; + uint32_t v_sync_a_end; + uint32_t h_blank_start; + uint32_t h_blank_end; + uint32_t h_sync_a_start; + uint32_t h_sync_a_end; + uint32_t h_sync_a_pol; + uint32_t h_total; + uint32_t underflow_occurred_status; + uint32_t otg_enabled; +}; + +void optc1_read_otg_state(struct optc *optc1, + struct dcn_otg_state *s); + +bool optc1_validate_timing( + struct timing_generator *optc, + const struct dc_crtc_timing *timing); + +void optc1_program_timing( + struct timing_generator *optc, + const struct dc_crtc_timing *dc_crtc_timing, + bool use_vbios); + +void optc1_program_global_sync( + struct timing_generator *optc); + +bool optc1_disable_crtc(struct timing_generator *optc); + +bool optc1_is_counter_moving(struct timing_generator *optc); + +void optc1_get_position(struct timing_generator *optc, + struct crtc_position *position); + +uint32_t optc1_get_vblank_counter(struct timing_generator *optc); + +void optc1_get_crtc_scanoutpos( + struct timing_generator *optc, + uint32_t *v_blank_start, + uint32_t *v_blank_end, + uint32_t *h_position, + uint32_t *v_position); + +void optc1_set_early_control( + struct timing_generator *optc, + uint32_t early_cntl); + +void optc1_wait_for_state(struct timing_generator *optc, + enum crtc_state state); + +void optc1_set_blank(struct timing_generator *optc, + bool enable_blanking); + +bool optc1_is_blanked(struct timing_generator *optc); + +void optc1_program_blank_color( + struct timing_generator *optc, + const struct tg_color *black_color); + +bool optc1_did_triggered_reset_occur( + struct timing_generator *optc); + +void optc1_enable_reset_trigger(struct timing_generator *optc, int source_tg_inst); + +void optc1_disable_reset_trigger(struct timing_generator *optc); + +void optc1_lock(struct timing_generator *optc); + +void optc1_unlock(struct timing_generator *optc); + +void optc1_enable_optc_clock(struct timing_generator *optc, bool enable); + +void optc1_set_drr( + struct timing_generator *optc, + const struct drr_params *params); + +void optc1_set_static_screen_control( + struct timing_generator *optc, + uint32_t value); + +void optc1_program_stereo(struct timing_generator *optc, + const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags); + +bool optc1_is_stereo_left_eye(struct timing_generator *optc); + +#endif /* __DC_TIMING_GENERATOR_DCN10_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c new file mode 100644 index 000000000000..44825e2c9ebb --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c @@ -0,0 +1,1503 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#include "dm_services.h" +#include "dc.h" + +#include "resource.h" +#include "include/irq_service_interface.h" +#include "dcn10/dcn10_resource.h" + +#include "dcn10/dcn10_ipp.h" +#include "dcn10/dcn10_mpc.h" +#include "irq/dcn10/irq_service_dcn10.h" +#include "dcn10/dcn10_dpp.h" +#include "dcn10_optc.h" +#include "dcn10/dcn10_hw_sequencer.h" +#include "dce110/dce110_hw_sequencer.h" +#include "dcn10/dcn10_opp.h" +#include "dce/dce_link_encoder.h" +#include "dce/dce_stream_encoder.h" +#include "dce/dce_clocks.h" +#include "dce/dce_clock_source.h" +#include "dce/dce_audio.h" +#include "dce/dce_hwseq.h" +#include "../virtual/virtual_stream_encoder.h" +#include "dce110/dce110_resource.h" +#include "dce112/dce112_resource.h" +#include "dcn10_hubp.h" +#include "dcn10_hubbub.h" + +#include "soc15ip.h" + +#include "dcn/dcn_1_0_offset.h" +#include "dcn/dcn_1_0_sh_mask.h" + +#include "nbio/nbio_7_0_offset.h" + +#include "mmhub/mmhub_9_1_offset.h" +#include "mmhub/mmhub_9_1_sh_mask.h" + +#include "reg_helper.h" +#include "dce/dce_abm.h" +#include "dce/dce_dmcu.h" + +#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL + #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f + #define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x220f + #define mmDP1_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x230f + #define mmDP2_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x240f + #define mmDP3_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x250f + #define mmDP4_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x260f + #define mmDP5_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 + #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x270f + #define mmDP6_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2 +#endif + + +enum dcn10_clk_src_array_id { + DCN10_CLK_SRC_PLL0, + DCN10_CLK_SRC_PLL1, + DCN10_CLK_SRC_PLL2, + DCN10_CLK_SRC_PLL3, + DCN10_CLK_SRC_TOTAL +}; + +/* begin ********************* + * macros to expend register list macro defined in HW object header file */ + +/* DCN */ +#define BASE_INNER(seg) \ + DCE_BASE__INST0_SEG ## seg + +#define BASE(seg) \ + BASE_INNER(seg) + +#define SR(reg_name)\ + .reg_name = BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +#define SRI(reg_name, block, id)\ + .reg_name = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + + +#define SRII(reg_name, block, id)\ + .reg_name[id] = BASE(mm ## block ## id ## _ ## reg_name ## _BASE_IDX) + \ + mm ## block ## id ## _ ## reg_name + +/* NBIO */ +#define NBIO_BASE_INNER(seg) \ + NBIF_BASE__INST0_SEG ## seg + +#define NBIO_BASE(seg) \ + NBIO_BASE_INNER(seg) + +#define NBIO_SR(reg_name)\ + .reg_name = NBIO_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* MMHUB */ +#define MMHUB_BASE_INNER(seg) \ + MMHUB_BASE__INST0_SEG ## seg + +#define MMHUB_BASE(seg) \ + MMHUB_BASE_INNER(seg) + +#define MMHUB_SR(reg_name)\ + .reg_name = MMHUB_BASE(mm ## reg_name ## _BASE_IDX) + \ + mm ## reg_name + +/* macros to expend register list macro defined in HW object header file + * end *********************/ + + +static const struct dce_dmcu_registers dmcu_regs = { + DMCU_DCN10_REG_LIST() +}; + +static const struct dce_dmcu_shift dmcu_shift = { + DMCU_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dce_dmcu_mask dmcu_mask = { + DMCU_MASK_SH_LIST_DCN10(_MASK) +}; + +static const struct dce_abm_registers abm_regs = { + ABM_DCN10_REG_LIST(0) +}; + +static const struct dce_abm_shift abm_shift = { + ABM_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dce_abm_mask abm_mask = { + ABM_MASK_SH_LIST_DCN10(_MASK) +}; + +#define stream_enc_regs(id)\ +[id] = {\ + SE_DCN_REG_LIST(id),\ + .TMDS_CNTL = 0,\ + .AFMT_AVI_INFO0 = 0,\ + .AFMT_AVI_INFO1 = 0,\ + .AFMT_AVI_INFO2 = 0,\ + .AFMT_AVI_INFO3 = 0,\ +} + +static const struct dce110_stream_enc_registers stream_enc_regs[] = { + stream_enc_regs(0), + stream_enc_regs(1), + stream_enc_regs(2), + stream_enc_regs(3), +}; + +static const struct dce_stream_encoder_shift se_shift = { + SE_COMMON_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dce_stream_encoder_mask se_mask = { + SE_COMMON_MASK_SH_LIST_DCN10(_MASK), + .AFMT_GENERIC0_UPDATE = 0, + .AFMT_GENERIC2_UPDATE = 0, + .DP_DYN_RANGE = 0, + .DP_YCBCR_RANGE = 0, + .HDMI_AVI_INFO_SEND = 0, + .HDMI_AVI_INFO_CONT = 0, + .HDMI_AVI_INFO_LINE = 0, + .DP_SEC_AVI_ENABLE = 0, + .AFMT_AVI_INFO_VERSION = 0 +}; + +#define audio_regs(id)\ +[id] = {\ + AUD_COMMON_REG_LIST(id)\ +} + +static const struct dce_audio_registers audio_regs[] = { + audio_regs(0), + audio_regs(1), + audio_regs(2), + audio_regs(3), +}; + +#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\ + SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\ + AUD_COMMON_MASK_SH_LIST_BASE(mask_sh) + +static const struct dce_audio_shift audio_shift = { + DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_aduio_mask audio_mask = { + DCE120_AUD_COMMON_MASK_SH_LIST(_MASK) +}; + +#define aux_regs(id)\ +[id] = {\ + AUX_REG_LIST(id)\ +} + +static const struct dce110_link_enc_aux_registers link_enc_aux_regs[] = { + aux_regs(0), + aux_regs(1), + aux_regs(2), + aux_regs(3), + aux_regs(4), + aux_regs(5) +}; + +#define hpd_regs(id)\ +[id] = {\ + HPD_REG_LIST(id)\ +} + +static const struct dce110_link_enc_hpd_registers link_enc_hpd_regs[] = { + hpd_regs(0), + hpd_regs(1), + hpd_regs(2), + hpd_regs(3), + hpd_regs(4), + hpd_regs(5) +}; + +#define link_regs(id)\ +[id] = {\ + LE_DCN10_REG_LIST(id), \ + SRI(DP_DPHY_INTERNAL_CTRL, DP, id) \ +} + +static const struct dce110_link_enc_registers link_enc_regs[] = { + link_regs(0), + link_regs(1), + link_regs(2), + link_regs(3), + link_regs(4), + link_regs(5), + link_regs(6), +}; + +#define ipp_regs(id)\ +[id] = {\ + IPP_REG_LIST_DCN10(id),\ +} + +static const struct dcn10_ipp_registers ipp_regs[] = { + ipp_regs(0), + ipp_regs(1), + ipp_regs(2), + ipp_regs(3), +}; + +static const struct dcn10_ipp_shift ipp_shift = { + IPP_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn10_ipp_mask ipp_mask = { + IPP_MASK_SH_LIST_DCN10(_MASK), +}; + +#define opp_regs(id)\ +[id] = {\ + OPP_REG_LIST_DCN10(id),\ +} + +static const struct dcn10_opp_registers opp_regs[] = { + opp_regs(0), + opp_regs(1), + opp_regs(2), + opp_regs(3), +}; + +static const struct dcn10_opp_shift opp_shift = { + OPP_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn10_opp_mask opp_mask = { + OPP_MASK_SH_LIST_DCN10(_MASK), +}; + +#define tf_regs(id)\ +[id] = {\ + TF_REG_LIST_DCN10(id),\ +} + +static const struct dcn_dpp_registers tf_regs[] = { + tf_regs(0), + tf_regs(1), + tf_regs(2), + tf_regs(3), +}; + +static const struct dcn_dpp_shift tf_shift = { + TF_REG_LIST_SH_MASK_DCN10(__SHIFT) +}; + +static const struct dcn_dpp_mask tf_mask = { + TF_REG_LIST_SH_MASK_DCN10(_MASK), +}; + +static const struct dcn_mpc_registers mpc_regs = { + MPC_COMMON_REG_LIST_DCN1_0(0), + MPC_COMMON_REG_LIST_DCN1_0(1), + MPC_COMMON_REG_LIST_DCN1_0(2), + MPC_COMMON_REG_LIST_DCN1_0(3), + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(0), + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(1), + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(2), + MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(3) +}; + +static const struct dcn_mpc_shift mpc_shift = { + MPC_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT) +}; + +static const struct dcn_mpc_mask mpc_mask = { + MPC_COMMON_MASK_SH_LIST_DCN1_0(_MASK), +}; + +#define tg_regs(id)\ +[id] = {TG_COMMON_REG_LIST_DCN1_0(id)} + +static const struct dcn_optc_registers tg_regs[] = { + tg_regs(0), + tg_regs(1), + tg_regs(2), + tg_regs(3), +}; + +static const struct dcn_optc_shift tg_shift = { + TG_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT) +}; + +static const struct dcn_optc_mask tg_mask = { + TG_COMMON_MASK_SH_LIST_DCN1_0(_MASK) +}; + + +static const struct bios_registers bios_regs = { + NBIO_SR(BIOS_SCRATCH_6) +}; + +#define hubp_regs(id)\ +[id] = {\ + HUBP_REG_LIST_DCN10(id)\ +} + + +static const struct dcn_mi_registers hubp_regs[] = { + hubp_regs(0), + hubp_regs(1), + hubp_regs(2), + hubp_regs(3), +}; + +static const struct dcn_mi_shift hubp_shift = { + HUBP_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn_mi_mask hubp_mask = { + HUBP_MASK_SH_LIST_DCN10(_MASK) +}; + + +static const struct dcn_hubbub_registers hubbub_reg = { + HUBBUB_REG_LIST_DCN10(0) +}; + +static const struct dcn_hubbub_shift hubbub_shift = { + HUBBUB_MASK_SH_LIST_DCN10(__SHIFT) +}; + +static const struct dcn_hubbub_mask hubbub_mask = { + HUBBUB_MASK_SH_LIST_DCN10(_MASK) +}; + +#define clk_src_regs(index, pllid)\ +[index] = {\ + CS_COMMON_REG_LIST_DCN1_0(index, pllid),\ +} + +static const struct dce110_clk_src_regs clk_src_regs[] = { + clk_src_regs(0, A), + clk_src_regs(1, B), + clk_src_regs(2, C), + clk_src_regs(3, D) +}; + +static const struct dce110_clk_src_shift cs_shift = { + CS_COMMON_MASK_SH_LIST_DCN1_0(__SHIFT) +}; + +static const struct dce110_clk_src_mask cs_mask = { + CS_COMMON_MASK_SH_LIST_DCN1_0(_MASK) +}; + + +static const struct resource_caps res_cap = { + .num_timing_generator = 4, + .num_video_plane = 4, + .num_audio = 4, + .num_stream_encoder = 4, + .num_pll = 4, +}; + +static const struct dc_debug debug_defaults_drv = { + .sanity_checks = true, + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = false, + .clock_trace = true, + + .min_disp_clk_khz = 300000, + + .disable_pplib_clock_request = true, + .disable_pplib_wm_range = false, + .pplib_wm_report_mode = WM_REPORT_DEFAULT, + .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP, + .force_single_disp_pipe_split = true, + .disable_dcc = DCC_ENABLE, + .voltage_align_fclk = true, + .disable_stereo_support = true, + .vsr_support = true, + .performance_trace = false, +}; + +static const struct dc_debug debug_defaults_diags = { + .disable_dmcu = true, + .force_abm_enable = false, + .timing_trace = true, + .clock_trace = true, + .disable_stutter = true, + .disable_pplib_clock_request = true, + .disable_pplib_wm_range = true +}; + +static void dcn10_dpp_destroy(struct dpp **dpp) +{ + kfree(TO_DCN10_DPP(*dpp)); + *dpp = NULL; +} + +static struct dpp *dcn10_dpp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn10_dpp *dpp = + kzalloc(sizeof(struct dcn10_dpp), GFP_KERNEL); + + if (!dpp) + return NULL; + + dpp1_construct(dpp, ctx, inst, + &tf_regs[inst], &tf_shift, &tf_mask); + return &dpp->base; +} + +static struct input_pixel_processor *dcn10_ipp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn10_ipp *ipp = + kzalloc(sizeof(struct dcn10_ipp), GFP_KERNEL); + + if (!ipp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn10_ipp_construct(ipp, ctx, inst, + &ipp_regs[inst], &ipp_shift, &ipp_mask); + return &ipp->base; +} + + +static struct output_pixel_processor *dcn10_opp_create( + struct dc_context *ctx, uint32_t inst) +{ + struct dcn10_opp *opp = + kzalloc(sizeof(struct dcn10_opp), GFP_KERNEL); + + if (!opp) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + dcn10_opp_construct(opp, ctx, inst, + &opp_regs[inst], &opp_shift, &opp_mask); + return &opp->base; +} + +static struct mpc *dcn10_mpc_create(struct dc_context *ctx) +{ + struct dcn10_mpc *mpc10 = kzalloc(sizeof(struct dcn10_mpc), + GFP_KERNEL); + + if (!mpc10) + return NULL; + + dcn10_mpc_construct(mpc10, ctx, + &mpc_regs, + &mpc_shift, + &mpc_mask, + 4); + + return &mpc10->base; +} + +static struct hubbub *dcn10_hubbub_create(struct dc_context *ctx) +{ + struct hubbub *hubbub = kzalloc(sizeof(struct hubbub), + GFP_KERNEL); + + if (!hubbub) + return NULL; + + hubbub1_construct(hubbub, ctx, + &hubbub_reg, + &hubbub_shift, + &hubbub_mask); + + return hubbub; +} + +static struct timing_generator *dcn10_timing_generator_create( + struct dc_context *ctx, + uint32_t instance) +{ + struct optc *tgn10 = + kzalloc(sizeof(struct optc), GFP_KERNEL); + + if (!tgn10) + return NULL; + + tgn10->base.inst = instance; + tgn10->base.ctx = ctx; + + tgn10->tg_regs = &tg_regs[instance]; + tgn10->tg_shift = &tg_shift; + tgn10->tg_mask = &tg_mask; + + dcn10_timing_generator_init(tgn10); + + return &tgn10->base; +} + +static const struct encoder_feature_support link_enc_feature = { + .max_hdmi_deep_color = COLOR_DEPTH_121212, + .max_hdmi_pixel_clock = 600000, + .ycbcr420_supported = true, + .flags.bits.IS_HBR2_CAPABLE = true, + .flags.bits.IS_HBR3_CAPABLE = true, + .flags.bits.IS_TPS3_CAPABLE = true, + .flags.bits.IS_TPS4_CAPABLE = true, + .flags.bits.IS_YCBCR_CAPABLE = true +}; + +struct link_encoder *dcn10_link_encoder_create( + const struct encoder_init_data *enc_init_data) +{ + struct dce110_link_encoder *enc110 = + kzalloc(sizeof(struct dce110_link_encoder), GFP_KERNEL); + + if (!enc110) + return NULL; + + dce110_link_encoder_construct(enc110, + enc_init_data, + &link_enc_feature, + &link_enc_regs[enc_init_data->transmitter], + &link_enc_aux_regs[enc_init_data->channel - 1], + &link_enc_hpd_regs[enc_init_data->hpd_source]); + + return &enc110->base; +} + +struct clock_source *dcn10_clock_source_create( + struct dc_context *ctx, + struct dc_bios *bios, + enum clock_source_id id, + const struct dce110_clk_src_regs *regs, + bool dp_clk_src) +{ + struct dce110_clk_src *clk_src = + kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL); + + if (!clk_src) + return NULL; + + if (dce110_clk_src_construct(clk_src, ctx, bios, id, + regs, &cs_shift, &cs_mask)) { + clk_src->base.dp_clk_src = dp_clk_src; + return &clk_src->base; + } + + BREAK_TO_DEBUGGER(); + return NULL; +} + +static void read_dce_straps( + struct dc_context *ctx, + struct resource_straps *straps) +{ + generic_reg_get(ctx, mmDC_PINSTRAPS + BASE(mmDC_PINSTRAPS_BASE_IDX), + FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio); +} + +static struct audio *create_audio( + struct dc_context *ctx, unsigned int inst) +{ + return dce_audio_create(ctx, inst, + &audio_regs[inst], &audio_shift, &audio_mask); +} + +static struct stream_encoder *dcn10_stream_encoder_create( + enum engine_id eng_id, + struct dc_context *ctx) +{ + struct dce110_stream_encoder *enc110 = + kzalloc(sizeof(struct dce110_stream_encoder), GFP_KERNEL); + + if (!enc110) + return NULL; + + dce110_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id, + &stream_enc_regs[eng_id], + &se_shift, &se_mask); + return &enc110->base; +} + +static const struct dce_hwseq_registers hwseq_reg = { + HWSEQ_DCN1_REG_LIST() +}; + +static const struct dce_hwseq_shift hwseq_shift = { + HWSEQ_DCN1_MASK_SH_LIST(__SHIFT) +}; + +static const struct dce_hwseq_mask hwseq_mask = { + HWSEQ_DCN1_MASK_SH_LIST(_MASK) +}; + +static struct dce_hwseq *dcn10_hwseq_create( + struct dc_context *ctx) +{ + struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL); + + if (hws) { + hws->ctx = ctx; + hws->regs = &hwseq_reg; + hws->shifts = &hwseq_shift; + hws->masks = &hwseq_mask; + hws->wa.DEGVIDCN10_253 = true; + hws->wa.false_optc_underflow = true; + } + return hws; +} + +static const struct resource_create_funcs res_create_funcs = { + .read_dce_straps = read_dce_straps, + .create_audio = create_audio, + .create_stream_encoder = dcn10_stream_encoder_create, + .create_hwseq = dcn10_hwseq_create, +}; + +static const struct resource_create_funcs res_create_maximus_funcs = { + .read_dce_straps = NULL, + .create_audio = NULL, + .create_stream_encoder = NULL, + .create_hwseq = dcn10_hwseq_create, +}; + +void dcn10_clock_source_destroy(struct clock_source **clk_src) +{ + kfree(TO_DCE110_CLK_SRC(*clk_src)); + *clk_src = NULL; +} + +static struct pp_smu_funcs_rv *dcn10_pp_smu_create(struct dc_context *ctx) +{ + struct pp_smu_funcs_rv *pp_smu = kzalloc(sizeof(*pp_smu), GFP_KERNEL); + + if (!pp_smu) + return pp_smu; + + dm_pp_get_funcs_rv(ctx, pp_smu); + return pp_smu; +} + +static void destruct(struct dcn10_resource_pool *pool) +{ + unsigned int i; + + for (i = 0; i < pool->base.stream_enc_count; i++) { + if (pool->base.stream_enc[i] != NULL) { + /* TODO: free dcn version of stream encoder once implemented + * rather than using virtual stream encoder + */ + kfree(pool->base.stream_enc[i]); + pool->base.stream_enc[i] = NULL; + } + } + + if (pool->base.mpc != NULL) { + kfree(TO_DCN10_MPC(pool->base.mpc)); + pool->base.mpc = NULL; + } + + if (pool->base.hubbub != NULL) { + kfree(pool->base.hubbub); + pool->base.hubbub = NULL; + } + + for (i = 0; i < pool->base.pipe_count; i++) { + if (pool->base.opps[i] != NULL) + pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]); + + if (pool->base.dpps[i] != NULL) + dcn10_dpp_destroy(&pool->base.dpps[i]); + + if (pool->base.ipps[i] != NULL) + pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]); + + if (pool->base.hubps[i] != NULL) { + kfree(TO_DCN10_HUBP(pool->base.hubps[i])); + pool->base.hubps[i] = NULL; + } + + if (pool->base.irqs != NULL) { + dal_irq_service_destroy(&pool->base.irqs); + } + + if (pool->base.timing_generators[i] != NULL) { + kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i])); + pool->base.timing_generators[i] = NULL; + } + } + + for (i = 0; i < pool->base.stream_enc_count; i++) + kfree(pool->base.stream_enc[i]); + + for (i = 0; i < pool->base.audio_count; i++) { + if (pool->base.audios[i]) + dce_aud_destroy(&pool->base.audios[i]); + } + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] != NULL) { + dcn10_clock_source_destroy(&pool->base.clock_sources[i]); + pool->base.clock_sources[i] = NULL; + } + } + + if (pool->base.dp_clock_source != NULL) { + dcn10_clock_source_destroy(&pool->base.dp_clock_source); + pool->base.dp_clock_source = NULL; + } + + if (pool->base.abm != NULL) + dce_abm_destroy(&pool->base.abm); + + if (pool->base.dmcu != NULL) + dce_dmcu_destroy(&pool->base.dmcu); + + if (pool->base.display_clock != NULL) + dce_disp_clk_destroy(&pool->base.display_clock); + + kfree(pool->base.pp_smu); +} + +static struct hubp *dcn10_hubp_create( + struct dc_context *ctx, + uint32_t inst) +{ + struct dcn10_hubp *hubp1 = + kzalloc(sizeof(struct dcn10_hubp), GFP_KERNEL); + + if (!hubp1) + return NULL; + + dcn10_hubp_construct(hubp1, ctx, inst, + &hubp_regs[inst], &hubp_shift, &hubp_mask); + return &hubp1->base; +} + +static void get_pixel_clock_parameters( + const struct pipe_ctx *pipe_ctx, + struct pixel_clk_params *pixel_clk_params) +{ + const struct dc_stream_state *stream = pipe_ctx->stream; + pixel_clk_params->requested_pix_clk = stream->timing.pix_clk_khz; + pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id; + pixel_clk_params->signal_type = pipe_ctx->stream->signal; + pixel_clk_params->controller_id = pipe_ctx->pipe_idx + 1; + /* TODO: un-hardcode*/ + pixel_clk_params->requested_sym_clk = LINK_RATE_LOW * + LINK_RATE_REF_FREQ_IN_KHZ; + pixel_clk_params->flags.ENABLE_SS = 0; + pixel_clk_params->color_depth = + stream->timing.display_color_depth; + pixel_clk_params->flags.DISPLAY_BLANKED = 1; + pixel_clk_params->pixel_encoding = stream->timing.pixel_encoding; + + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) + pixel_clk_params->color_depth = COLOR_DEPTH_888; + + if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR420) + pixel_clk_params->requested_pix_clk /= 2; + +} + +static void build_clamping_params(struct dc_stream_state *stream) +{ + stream->clamping.clamping_level = CLAMPING_FULL_RANGE; + stream->clamping.c_depth = stream->timing.display_color_depth; + stream->clamping.pixel_encoding = stream->timing.pixel_encoding; +} + +static void build_pipe_hw_param(struct pipe_ctx *pipe_ctx) +{ + + get_pixel_clock_parameters(pipe_ctx, &pipe_ctx->stream_res.pix_clk_params); + + pipe_ctx->clock_source->funcs->get_pix_clk_dividers( + pipe_ctx->clock_source, + &pipe_ctx->stream_res.pix_clk_params, + &pipe_ctx->pll_settings); + + pipe_ctx->stream->clamping.pixel_encoding = pipe_ctx->stream->timing.pixel_encoding; + + resource_build_bit_depth_reduction_params(pipe_ctx->stream, + &pipe_ctx->stream->bit_depth_params); + build_clamping_params(pipe_ctx->stream); +} + +static enum dc_status build_mapped_resource( + const struct dc *dc, + struct dc_state *context, + struct dc_stream_state *stream) +{ + struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream); + + /*TODO Seems unneeded anymore */ + /* if (old_context && resource_is_stream_unchanged(old_context, stream)) { + if (stream != NULL && old_context->streams[i] != NULL) { + todo: shouldn't have to copy missing parameter here + resource_build_bit_depth_reduction_params(stream, + &stream->bit_depth_params); + stream->clamping.pixel_encoding = + stream->timing.pixel_encoding; + + resource_build_bit_depth_reduction_params(stream, + &stream->bit_depth_params); + build_clamping_params(stream); + + continue; + } + } + */ + + if (!pipe_ctx) + return DC_ERROR_UNEXPECTED; + + build_pipe_hw_param(pipe_ctx); + return DC_OK; +} + +enum dc_status dcn10_add_stream_to_ctx( + struct dc *dc, + struct dc_state *new_ctx, + struct dc_stream_state *dc_stream) +{ + enum dc_status result = DC_ERROR_UNEXPECTED; + + result = resource_map_pool_resources(dc, new_ctx, dc_stream); + + if (result == DC_OK) + result = resource_map_phy_clock_resources(dc, new_ctx, dc_stream); + + + if (result == DC_OK) + result = build_mapped_resource(dc, new_ctx, dc_stream); + + return result; +} + +enum dc_status dcn10_validate_guaranteed( + struct dc *dc, + struct dc_stream_state *dc_stream, + struct dc_state *context) +{ + enum dc_status result = DC_ERROR_UNEXPECTED; + + context->streams[0] = dc_stream; + dc_stream_retain(context->streams[0]); + context->stream_count++; + + result = resource_map_pool_resources(dc, context, dc_stream); + + if (result == DC_OK) + result = resource_map_phy_clock_resources(dc, context, dc_stream); + + if (result == DC_OK) + result = build_mapped_resource(dc, context, dc_stream); + + if (result == DC_OK) { + validate_guaranteed_copy_streams( + context, dc->caps.max_streams); + result = resource_build_scaling_params_for_context(dc, context); + } + if (result == DC_OK && !dcn_validate_bandwidth(dc, context)) + return DC_FAIL_BANDWIDTH_VALIDATE; + + return result; +} + +static struct pipe_ctx *dcn10_acquire_idle_pipe_for_layer( + struct dc_state *context, + const struct resource_pool *pool, + struct dc_stream_state *stream) +{ + struct resource_context *res_ctx = &context->res_ctx; + struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream); + struct pipe_ctx *idle_pipe = find_idle_secondary_pipe(res_ctx, pool); + + if (!head_pipe) { + ASSERT(0); + return NULL; + } + + if (!idle_pipe) + return NULL; + + idle_pipe->stream = head_pipe->stream; + idle_pipe->stream_res.tg = head_pipe->stream_res.tg; + idle_pipe->stream_res.opp = head_pipe->stream_res.opp; + + idle_pipe->plane_res.hubp = pool->hubps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.ipp = pool->ipps[idle_pipe->pipe_idx]; + idle_pipe->plane_res.dpp = pool->dpps[idle_pipe->pipe_idx]; + + return idle_pipe; +} + +enum dcc_control { + dcc_control__256_256_xxx, + dcc_control__128_128_xxx, + dcc_control__256_64_64, +}; + +enum segment_order { + segment_order__na, + segment_order__contiguous, + segment_order__non_contiguous, +}; + +static bool dcc_support_pixel_format( + enum surface_pixel_format format, + unsigned int *bytes_per_element) +{ + /* DML: get_bytes_per_element */ + switch (format) { + case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555: + case SURFACE_PIXEL_FORMAT_GRPH_RGB565: + *bytes_per_element = 2; + return true; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR8888: + case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010: + *bytes_per_element = 4; + return true; + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616: + case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F: + case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F: + *bytes_per_element = 8; + return true; + default: + return false; + } +} + +static bool dcc_support_swizzle( + enum swizzle_mode_values swizzle, + unsigned int bytes_per_element, + enum segment_order *segment_order_horz, + enum segment_order *segment_order_vert) +{ + bool standard_swizzle = false; + bool display_swizzle = false; + + switch (swizzle) { + case DC_SW_4KB_S: + case DC_SW_64KB_S: + case DC_SW_VAR_S: + case DC_SW_4KB_S_X: + case DC_SW_64KB_S_X: + case DC_SW_VAR_S_X: + standard_swizzle = true; + break; + case DC_SW_4KB_D: + case DC_SW_64KB_D: + case DC_SW_VAR_D: + case DC_SW_4KB_D_X: + case DC_SW_64KB_D_X: + case DC_SW_VAR_D_X: + display_swizzle = true; + break; + default: + break; + } + + if (bytes_per_element == 1 && standard_swizzle) { + *segment_order_horz = segment_order__contiguous; + *segment_order_vert = segment_order__na; + return true; + } + if (bytes_per_element == 2 && standard_swizzle) { + *segment_order_horz = segment_order__non_contiguous; + *segment_order_vert = segment_order__contiguous; + return true; + } + if (bytes_per_element == 4 && standard_swizzle) { + *segment_order_horz = segment_order__non_contiguous; + *segment_order_vert = segment_order__contiguous; + return true; + } + if (bytes_per_element == 8 && standard_swizzle) { + *segment_order_horz = segment_order__na; + *segment_order_vert = segment_order__contiguous; + return true; + } + if (bytes_per_element == 8 && display_swizzle) { + *segment_order_horz = segment_order__contiguous; + *segment_order_vert = segment_order__non_contiguous; + return true; + } + + return false; +} + +static void get_blk256_size(unsigned int *blk256_width, unsigned int *blk256_height, + unsigned int bytes_per_element) +{ + /* copied from DML. might want to refactor DML to leverage from DML */ + /* DML : get_blk256_size */ + if (bytes_per_element == 1) { + *blk256_width = 16; + *blk256_height = 16; + } else if (bytes_per_element == 2) { + *blk256_width = 16; + *blk256_height = 8; + } else if (bytes_per_element == 4) { + *blk256_width = 8; + *blk256_height = 8; + } else if (bytes_per_element == 8) { + *blk256_width = 8; + *blk256_height = 4; + } +} + +static void det_request_size( + unsigned int height, + unsigned int width, + unsigned int bpe, + bool *req128_horz_wc, + bool *req128_vert_wc) +{ + unsigned int detile_buf_size = 164 * 1024; /* 164KB for DCN1.0 */ + + unsigned int blk256_height = 0; + unsigned int blk256_width = 0; + unsigned int swath_bytes_horz_wc, swath_bytes_vert_wc; + + get_blk256_size(&blk256_width, &blk256_height, bpe); + + swath_bytes_horz_wc = height * blk256_height * bpe; + swath_bytes_vert_wc = width * blk256_width * bpe; + + *req128_horz_wc = (2 * swath_bytes_horz_wc <= detile_buf_size) ? + false : /* full 256B request */ + true; /* half 128b request */ + + *req128_vert_wc = (2 * swath_bytes_vert_wc <= detile_buf_size) ? + false : /* full 256B request */ + true; /* half 128b request */ +} + +static bool get_dcc_compression_cap(const struct dc *dc, + const struct dc_dcc_surface_param *input, + struct dc_surface_dcc_cap *output) +{ + /* implement section 1.6.2.1 of DCN1_Programming_Guide.docx */ + enum dcc_control dcc_control; + unsigned int bpe; + enum segment_order segment_order_horz, segment_order_vert; + bool req128_horz_wc, req128_vert_wc; + + memset(output, 0, sizeof(*output)); + + if (dc->debug.disable_dcc == DCC_DISABLE) + return false; + + if (!dcc_support_pixel_format(input->format, + &bpe)) + return false; + + if (!dcc_support_swizzle(input->swizzle_mode, bpe, + &segment_order_horz, &segment_order_vert)) + return false; + + det_request_size(input->surface_size.height, input->surface_size.width, + bpe, &req128_horz_wc, &req128_vert_wc); + + if (!req128_horz_wc && !req128_vert_wc) { + dcc_control = dcc_control__256_256_xxx; + } else if (input->scan == SCAN_DIRECTION_HORIZONTAL) { + if (!req128_horz_wc) + dcc_control = dcc_control__256_256_xxx; + else if (segment_order_horz == segment_order__contiguous) + dcc_control = dcc_control__128_128_xxx; + else + dcc_control = dcc_control__256_64_64; + } else if (input->scan == SCAN_DIRECTION_VERTICAL) { + if (!req128_vert_wc) + dcc_control = dcc_control__256_256_xxx; + else if (segment_order_vert == segment_order__contiguous) + dcc_control = dcc_control__128_128_xxx; + else + dcc_control = dcc_control__256_64_64; + } else { + if ((req128_horz_wc && + segment_order_horz == segment_order__non_contiguous) || + (req128_vert_wc && + segment_order_vert == segment_order__non_contiguous)) + /* access_dir not known, must use most constraining */ + dcc_control = dcc_control__256_64_64; + else + /* reg128 is true for either horz and vert + * but segment_order is contiguous + */ + dcc_control = dcc_control__128_128_xxx; + } + + if (dc->debug.disable_dcc == DCC_HALF_REQ_DISALBE && + dcc_control != dcc_control__256_256_xxx) + return false; + + switch (dcc_control) { + case dcc_control__256_256_xxx: + output->grph.rgb.max_uncompressed_blk_size = 256; + output->grph.rgb.max_compressed_blk_size = 256; + output->grph.rgb.independent_64b_blks = false; + break; + case dcc_control__128_128_xxx: + output->grph.rgb.max_uncompressed_blk_size = 128; + output->grph.rgb.max_compressed_blk_size = 128; + output->grph.rgb.independent_64b_blks = false; + break; + case dcc_control__256_64_64: + output->grph.rgb.max_uncompressed_blk_size = 256; + output->grph.rgb.max_compressed_blk_size = 64; + output->grph.rgb.independent_64b_blks = true; + break; + } + + output->capable = true; + output->const_color_support = false; + + return true; +} + + +static void dcn10_destroy_resource_pool(struct resource_pool **pool) +{ + struct dcn10_resource_pool *dcn10_pool = TO_DCN10_RES_POOL(*pool); + + destruct(dcn10_pool); + kfree(dcn10_pool); + *pool = NULL; +} + +static enum dc_status dcn10_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps) +{ + if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN + && caps->max_video_width != 0 + && plane_state->src_rect.width > caps->max_video_width) + return DC_FAIL_SURFACE_VALIDATE; + + return DC_OK; +} + +static struct dc_cap_funcs cap_funcs = { + .get_dcc_compression_cap = get_dcc_compression_cap +}; + +static struct resource_funcs dcn10_res_pool_funcs = { + .destroy = dcn10_destroy_resource_pool, + .link_enc_create = dcn10_link_encoder_create, + .validate_guaranteed = dcn10_validate_guaranteed, + .validate_bandwidth = dcn_validate_bandwidth, + .acquire_idle_pipe_for_layer = dcn10_acquire_idle_pipe_for_layer, + .validate_plane = dcn10_validate_plane, + .add_stream_to_ctx = dcn10_add_stream_to_ctx +}; + +static uint32_t read_pipe_fuses(struct dc_context *ctx) +{ + uint32_t value = dm_read_reg_soc15(ctx, mmCC_DC_PIPE_DIS, 0); + /* RV1 support max 4 pipes */ + value = value & 0xf; + return value; +} + +static bool construct( + uint8_t num_virtual_links, + struct dc *dc, + struct dcn10_resource_pool *pool) +{ + int i; + int j; + struct dc_context *ctx = dc->ctx; + uint32_t pipe_fuses = read_pipe_fuses(ctx); + + ctx->dc_bios->regs = &bios_regs; + + pool->base.res_cap = &res_cap; + pool->base.funcs = &dcn10_res_pool_funcs; + + /* + * TODO fill in from actual raven resource when we create + * more than virtual encoder + */ + + /************************************************* + * Resource + asic cap harcoding * + *************************************************/ + pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE; + + /* max pipe num for ASIC before check pipe fuses */ + pool->base.pipe_count = pool->base.res_cap->num_timing_generator; + + dc->caps.max_video_width = 3840; + dc->caps.max_downscale_ratio = 200; + dc->caps.i2c_speed_in_khz = 100; + dc->caps.max_cursor_size = 256; + dc->caps.max_slave_planes = 1; + dc->caps.is_apu = true; + + if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV) + dc->debug = debug_defaults_drv; + else + dc->debug = debug_defaults_diags; + + /************************************************* + * Create resources * + *************************************************/ + + pool->base.clock_sources[DCN10_CLK_SRC_PLL0] = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL0, + &clk_src_regs[0], false); + pool->base.clock_sources[DCN10_CLK_SRC_PLL1] = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL1, + &clk_src_regs[1], false); + pool->base.clock_sources[DCN10_CLK_SRC_PLL2] = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL2, + &clk_src_regs[2], false); + pool->base.clock_sources[DCN10_CLK_SRC_PLL3] = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_COMBO_PHY_PLL3, + &clk_src_regs[3], false); + + pool->base.clk_src_count = DCN10_CLK_SRC_TOTAL; + + pool->base.dp_clock_source = + dcn10_clock_source_create(ctx, ctx->dc_bios, + CLOCK_SOURCE_ID_DP_DTO, + /* todo: not reuse phy_pll registers */ + &clk_src_regs[0], true); + + for (i = 0; i < pool->base.clk_src_count; i++) { + if (pool->base.clock_sources[i] == NULL) { + dm_error("DC: failed to create clock sources!\n"); + BREAK_TO_DEBUGGER(); + goto fail; + } + } + + if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) { + pool->base.display_clock = dce120_disp_clk_create(ctx); + if (pool->base.display_clock == NULL) { + dm_error("DC: failed to create display clock!\n"); + BREAK_TO_DEBUGGER(); + goto fail; + } + } + + pool->base.dmcu = dcn10_dmcu_create(ctx, + &dmcu_regs, + &dmcu_shift, + &dmcu_mask); + if (pool->base.dmcu == NULL) { + dm_error("DC: failed to create dmcu!\n"); + BREAK_TO_DEBUGGER(); + goto fail; + } + + pool->base.abm = dce_abm_create(ctx, + &abm_regs, + &abm_shift, + &abm_mask); + if (pool->base.abm == NULL) { + dm_error("DC: failed to create abm!\n"); + BREAK_TO_DEBUGGER(); + goto fail; + } + + dml_init_instance(&dc->dml, DML_PROJECT_RAVEN1); + memcpy(dc->dcn_ip, &dcn10_ip_defaults, sizeof(dcn10_ip_defaults)); + memcpy(dc->dcn_soc, &dcn10_soc_defaults, sizeof(dcn10_soc_defaults)); + + if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { + dc->dcn_soc->urgent_latency = 3; + dc->debug.disable_dmcu = true; + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 41.60f; + } + + + dc->dcn_soc->number_of_channels = dc->ctx->asic_id.vram_width / ddr4_dram_width; + ASSERT(dc->dcn_soc->number_of_channels < 3); + if (dc->dcn_soc->number_of_channels == 0)/*old sbios bug*/ + dc->dcn_soc->number_of_channels = 2; + + if (dc->dcn_soc->number_of_channels == 1) { + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 19.2f; + dc->dcn_soc->fabric_and_dram_bandwidth_vnom0p8 = 17.066f; + dc->dcn_soc->fabric_and_dram_bandwidth_vmid0p72 = 14.933f; + dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 = 12.8f; + if (ASICREV_IS_RV1_F0(dc->ctx->asic_id.hw_internal_rev)) { + dc->dcn_soc->fabric_and_dram_bandwidth_vmax0p9 = 20.80f; + } + } + + pool->base.pp_smu = dcn10_pp_smu_create(ctx); + + if (!dc->debug.disable_pplib_clock_request) + dcn_bw_update_from_pplib(dc); + dcn_bw_sync_calcs_and_dml(dc); + if (!dc->debug.disable_pplib_wm_range) { + dc->res_pool = &pool->base; + dcn_bw_notify_pplib_of_wm_ranges(dc); + } + + { + struct irq_service_init_data init_data; + init_data.ctx = dc->ctx; + pool->base.irqs = dal_irq_service_dcn10_create(&init_data); + if (!pool->base.irqs) + goto fail; + } + + /* index to valid pipe resource */ + j = 0; + /* mem input -> ipp -> dpp -> opp -> TG */ + for (i = 0; i < pool->base.pipe_count; i++) { + /* if pipe is disabled, skip instance of HW pipe, + * i.e, skip ASIC register instance + */ + if ((pipe_fuses & (1 << i)) != 0) + continue; + + pool->base.hubps[j] = dcn10_hubp_create(ctx, i); + if (pool->base.hubps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create memory input!\n"); + goto fail; + } + + pool->base.ipps[j] = dcn10_ipp_create(ctx, i); + if (pool->base.ipps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create input pixel processor!\n"); + goto fail; + } + + pool->base.dpps[j] = dcn10_dpp_create(ctx, i); + if (pool->base.dpps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create dpp!\n"); + goto fail; + } + + pool->base.opps[j] = dcn10_opp_create(ctx, i); + if (pool->base.opps[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error( + "DC: failed to create output pixel processor!\n"); + goto fail; + } + + pool->base.timing_generators[j] = dcn10_timing_generator_create( + ctx, i); + if (pool->base.timing_generators[j] == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create tg!\n"); + goto fail; + } + + /* check next valid pipe */ + j++; + } + + /* valid pipe num */ + pool->base.pipe_count = j; + + /* within dml lib, it is hard code to 4. If ASIC pipe is fused, + * the value may be changed + */ + dc->dml.ip.max_num_dpp = pool->base.pipe_count; + dc->dcn_ip->max_num_dpp = pool->base.pipe_count; + + pool->base.mpc = dcn10_mpc_create(ctx); + if (pool->base.mpc == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create mpc!\n"); + goto fail; + } + + pool->base.hubbub = dcn10_hubbub_create(ctx); + if (pool->base.hubbub == NULL) { + BREAK_TO_DEBUGGER(); + dm_error("DC: failed to create hubbub!\n"); + goto fail; + } + + if (!resource_construct(num_virtual_links, dc, &pool->base, + (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) ? + &res_create_funcs : &res_create_maximus_funcs))) + goto fail; + + dcn10_hw_sequencer_construct(dc); + dc->caps.max_planes = pool->base.pipe_count; + + dc->cap_funcs = cap_funcs; + + return true; + +fail: + + destruct(pool); + + return false; +} + +struct resource_pool *dcn10_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc) +{ + struct dcn10_resource_pool *pool = + kzalloc(sizeof(struct dcn10_resource_pool), GFP_KERNEL); + + if (!pool) + return NULL; + + if (construct(num_virtual_links, dc, pool)) + return &pool->base; + + BREAK_TO_DEBUGGER(); + return NULL; +} diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h new file mode 100644 index 000000000000..8f71225bc61b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h @@ -0,0 +1,47 @@ +/* +* Copyright 2016 Advanced Micro Devices, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * Authors: AMD + * + */ + +#ifndef __DC_RESOURCE_DCN10_H__ +#define __DC_RESOURCE_DCN10_H__ + +#include "core_types.h" + +#define TO_DCN10_RES_POOL(pool)\ + container_of(pool, struct dcn10_resource_pool, base) + +struct dc; +struct resource_pool; +struct _vcs_dpi_display_pipe_params_st; + +struct dcn10_resource_pool { + struct resource_pool base; +}; +struct resource_pool *dcn10_create_resource_pool( + uint8_t num_virtual_links, + struct dc *dc); + + +#endif /* __DC_RESOURCE_DCN10_H__ */ + |