diff options
author | Harry Wentland <harry.wentland@amd.com> | 2017-09-12 15:58:20 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2017-09-26 17:01:32 -0400 |
commit | 4562236b3bc0a28aeb6ee93b2d8a849a4c4e1c7c (patch) | |
tree | 84301c04dcaaa05c3318a8fe62cf62ab52ecc162 /drivers/gpu/drm/amd/display/dc/basics | |
parent | drm/amdgpu: Pulling old prepare and submit for flip back (diff) | |
download | linux-dev-4562236b3bc0a28aeb6ee93b2d8a849a4c4e1c7c.tar.xz linux-dev-4562236b3bc0a28aeb6ee93b2d8a849a4c4e1c7c.zip |
drm/amd/dc: Add dc display driver (v2)
Supported DCE versions: 8.0, 10.0, 11.0, 11.2
v2: rebase against 4.11
Signed-off-by: Harry Wentland <harry.wentland@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/basics')
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/Makefile | 11 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/conversion.c | 223 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/conversion.h | 51 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c | 691 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/fixpt32_32.c | 221 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/grph_object_id.c | 134 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/log_helpers.c | 100 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/logger.c | 457 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/logger.h | 67 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/register_logger.c | 197 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/signal_types.c | 116 | ||||
-rw-r--r-- | drivers/gpu/drm/amd/display/dc/basics/vector.c | 307 |
12 files changed, 2575 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/basics/Makefile b/drivers/gpu/drm/amd/display/dc/basics/Makefile new file mode 100644 index 000000000000..a263cadcc0df --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/Makefile @@ -0,0 +1,11 @@ +# +# Makefile for the 'utils' sub-component of DAL. +# It provides the general basic services required by other DAL +# subcomponents. + +BASICS = conversion.o fixpt31_32.o fixpt32_32.o grph_object_id.o \ + logger.o log_helpers.o register_logger.o signal_types.o vector.o + +AMD_DAL_BASICS = $(addprefix $(AMDDALPATH)/dc/basics/,$(BASICS)) + +AMD_DISPLAY_FILES += $(AMD_DAL_BASICS) diff --git a/drivers/gpu/drm/amd/display/dc/basics/conversion.c b/drivers/gpu/drm/amd/display/dc/basics/conversion.c new file mode 100644 index 000000000000..ebe14e17cc2e --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/conversion.c @@ -0,0 +1,223 @@ +/* + * 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" + +#define DIVIDER 10000 + +/* S2D13 value in [-3.00...0.9999] */ +#define S2D13_MIN (-3 * DIVIDER) +#define S2D13_MAX (3 * DIVIDER) + +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; +} +/** +* convert_float_matrix +* This converts a double into HW register spec defined format S2D13. +* @param : +* @return None +*/ +void convert_float_matrix( + uint16_t *matrix, + struct fixed31_32 *flt, + uint32_t buffer_size) +{ + const struct fixed31_32 min_2_13 = + dal_fixed31_32_from_fraction(S2D13_MIN, DIVIDER); + const struct fixed31_32 max_2_13 = + dal_fixed31_32_from_fraction(S2D13_MAX, DIVIDER); + uint32_t i; + + for (i = 0; i < buffer_size; ++i) { + uint32_t reg_value = + fixed_point_to_int_frac( + dal_fixed31_32_clamp( + flt[i], + min_2_13, + max_2_13), + 2, + 13); + + matrix[i] = (uint16_t)reg_value; + } +} + +static void calculate_adjustments_common( + const struct fixed31_32 *ideal_matrix, + const struct dc_csc_adjustments *adjustments, + struct fixed31_32 *matrix) +{ + const struct fixed31_32 sin_hue = + dal_fixed31_32_sin(adjustments->hue); + const struct fixed31_32 cos_hue = + dal_fixed31_32_cos(adjustments->hue); + + const struct fixed31_32 multiplier = + dal_fixed31_32_mul( + adjustments->contrast, + adjustments->saturation); + + matrix[0] = dal_fixed31_32_mul( + ideal_matrix[0], + adjustments->contrast); + + matrix[1] = dal_fixed31_32_mul( + ideal_matrix[1], + adjustments->contrast); + + matrix[2] = dal_fixed31_32_mul( + ideal_matrix[2], + adjustments->contrast); + + matrix[4] = dal_fixed31_32_mul( + multiplier, + dal_fixed31_32_add( + dal_fixed31_32_mul( + ideal_matrix[8], + sin_hue), + dal_fixed31_32_mul( + ideal_matrix[4], + cos_hue))); + + matrix[5] = dal_fixed31_32_mul( + multiplier, + dal_fixed31_32_add( + dal_fixed31_32_mul( + ideal_matrix[9], + sin_hue), + dal_fixed31_32_mul( + ideal_matrix[5], + cos_hue))); + + matrix[6] = dal_fixed31_32_mul( + multiplier, + dal_fixed31_32_add( + dal_fixed31_32_mul( + ideal_matrix[10], + sin_hue), + dal_fixed31_32_mul( + ideal_matrix[6], + cos_hue))); + + matrix[7] = ideal_matrix[7]; + + matrix[8] = dal_fixed31_32_mul( + multiplier, + dal_fixed31_32_sub( + dal_fixed31_32_mul( + ideal_matrix[8], + cos_hue), + dal_fixed31_32_mul( + ideal_matrix[4], + sin_hue))); + + matrix[9] = dal_fixed31_32_mul( + multiplier, + dal_fixed31_32_sub( + dal_fixed31_32_mul( + ideal_matrix[9], + cos_hue), + dal_fixed31_32_mul( + ideal_matrix[5], + sin_hue))); + + matrix[10] = dal_fixed31_32_mul( + multiplier, + dal_fixed31_32_sub( + dal_fixed31_32_mul( + ideal_matrix[10], + cos_hue), + dal_fixed31_32_mul( + ideal_matrix[6], + sin_hue))); + + matrix[11] = ideal_matrix[11]; +} + +void calculate_adjustments( + const struct fixed31_32 *ideal_matrix, + const struct dc_csc_adjustments *adjustments, + struct fixed31_32 *matrix) +{ + calculate_adjustments_common(ideal_matrix, adjustments, matrix); + + matrix[3] = dal_fixed31_32_add( + ideal_matrix[3], + dal_fixed31_32_mul( + adjustments->brightness, + dal_fixed31_32_from_fraction(86, 100))); +} + +void calculate_adjustments_y_only( + const struct fixed31_32 *ideal_matrix, + const struct dc_csc_adjustments *adjustments, + struct fixed31_32 *matrix) +{ + calculate_adjustments_common(ideal_matrix, adjustments, matrix); + + matrix[3] = dal_fixed31_32_add( + ideal_matrix[3], + adjustments->brightness); +} + diff --git a/drivers/gpu/drm/amd/display/dc/basics/conversion.h b/drivers/gpu/drm/amd/display/dc/basics/conversion.h new file mode 100644 index 000000000000..18cbe41e80ff --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/conversion.h @@ -0,0 +1,51 @@ +/* + * 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 __DAL_CONVERSION_H__ +#define __DAL_CONVERSION_H__ + +#include "include/fixed31_32.h" + +uint16_t fixed_point_to_int_frac( + struct fixed31_32 arg, + uint8_t integer_bits, + uint8_t fractional_bits); + +void convert_float_matrix( + uint16_t *matrix, + struct fixed31_32 *flt, + uint32_t buffer_size); + +void calculate_adjustments( + const struct fixed31_32 *ideal_matrix, + const struct dc_csc_adjustments *adjustments, + struct fixed31_32 *matrix); + +void calculate_adjustments_y_only( + const struct fixed31_32 *ideal_matrix, + const struct dc_csc_adjustments *adjustments, + struct fixed31_32 *matrix); + +#endif diff --git a/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c new file mode 100644 index 000000000000..5a6e46843502 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c @@ -0,0 +1,691 @@ +/* + * 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 "include/fixed31_32.h" + +static inline uint64_t abs_i64( + int64_t arg) +{ + if (arg > 0) + return (uint64_t)arg; + else + return (uint64_t)(-arg); +} + +/* + * @brief + * result = dividend / divisor + * *remainder = dividend % divisor + */ +static inline uint64_t complete_integer_division_u64( + uint64_t dividend, + uint64_t divisor, + uint64_t *remainder) +{ + uint64_t result; + + ASSERT(divisor); + + result = div64_u64_rem(dividend, divisor, remainder); + + return result; +} + +#define BITS_PER_FRACTIONAL_PART \ + 32 + +#define FRACTIONAL_PART_MASK \ + ((1ULL << BITS_PER_FRACTIONAL_PART) - 1) + +#define GET_INTEGER_PART(x) \ + ((x) >> BITS_PER_FRACTIONAL_PART) + +#define GET_FRACTIONAL_PART(x) \ + (FRACTIONAL_PART_MASK & (x)) + +struct fixed31_32 dal_fixed31_32_from_fraction( + int64_t numerator, + int64_t denominator) +{ + struct fixed31_32 res; + + bool arg1_negative = numerator < 0; + bool arg2_negative = denominator < 0; + + uint64_t arg1_value = arg1_negative ? -numerator : numerator; + uint64_t arg2_value = arg2_negative ? -denominator : denominator; + + uint64_t remainder; + + /* determine integer part */ + + uint64_t res_value = complete_integer_division_u64( + arg1_value, arg2_value, &remainder); + + ASSERT(res_value <= LONG_MAX); + + /* determine fractional part */ + { + uint32_t i = BITS_PER_FRACTIONAL_PART; + + do { + remainder <<= 1; + + res_value <<= 1; + + if (remainder >= arg2_value) { + res_value |= 1; + remainder -= arg2_value; + } + } while (--i != 0); + } + + /* round up LSB */ + { + uint64_t summand = (remainder << 1) >= arg2_value; + + ASSERT(res_value <= LLONG_MAX - summand); + + res_value += summand; + } + + res.value = (int64_t)res_value; + + if (arg1_negative ^ arg2_negative) + res.value = -res.value; + + return res; +} + +struct fixed31_32 dal_fixed31_32_from_int( + int64_t arg) +{ + struct fixed31_32 res; + + ASSERT((LONG_MIN <= arg) && (arg <= LONG_MAX)); + + res.value = arg << BITS_PER_FRACTIONAL_PART; + + return res; +} + +struct fixed31_32 dal_fixed31_32_neg( + struct fixed31_32 arg) +{ + struct fixed31_32 res; + + res.value = -arg.value; + + return res; +} + +struct fixed31_32 dal_fixed31_32_abs( + struct fixed31_32 arg) +{ + if (arg.value < 0) + return dal_fixed31_32_neg(arg); + else + return arg; +} + +bool dal_fixed31_32_lt( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + return arg1.value < arg2.value; +} + +bool dal_fixed31_32_le( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + return arg1.value <= arg2.value; +} + +bool dal_fixed31_32_eq( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + return arg1.value == arg2.value; +} + +struct fixed31_32 dal_fixed31_32_min( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + if (arg1.value <= arg2.value) + return arg1; + else + return arg2; +} + +struct fixed31_32 dal_fixed31_32_max( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + if (arg1.value <= arg2.value) + return arg2; + else + return arg1; +} + +struct fixed31_32 dal_fixed31_32_clamp( + struct fixed31_32 arg, + struct fixed31_32 min_value, + struct fixed31_32 max_value) +{ + if (dal_fixed31_32_le(arg, min_value)) + return min_value; + else if (dal_fixed31_32_le(max_value, arg)) + return max_value; + else + return arg; +} + +struct fixed31_32 dal_fixed31_32_shl( + struct fixed31_32 arg, + uint8_t shift) +{ + struct fixed31_32 res; + + ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) || + ((arg.value < 0) && (arg.value >= LLONG_MIN >> shift))); + + res.value = arg.value << shift; + + return res; +} + +struct fixed31_32 dal_fixed31_32_shr( + struct fixed31_32 arg, + uint8_t shift) +{ + struct fixed31_32 res; + + ASSERT(shift < 64); + + res.value = arg.value >> shift; + + return res; +} + +struct fixed31_32 dal_fixed31_32_add( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + struct fixed31_32 res; + + ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) || + ((arg1.value < 0) && (LLONG_MIN - arg1.value <= arg2.value))); + + res.value = arg1.value + arg2.value; + + return res; +} + +struct fixed31_32 dal_fixed31_32_sub_int( + struct fixed31_32 arg1, + int32_t arg2) +{ + return dal_fixed31_32_sub( + arg1, + dal_fixed31_32_from_int(arg2)); +} + +struct fixed31_32 dal_fixed31_32_sub( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + struct fixed31_32 res; + + ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) || + ((arg2.value < 0) && (LLONG_MAX + arg2.value >= arg1.value))); + + res.value = arg1.value - arg2.value; + + return res; +} + +struct fixed31_32 dal_fixed31_32_mul_int( + struct fixed31_32 arg1, + int32_t arg2) +{ + return dal_fixed31_32_mul( + arg1, + dal_fixed31_32_from_int(arg2)); +} + +struct fixed31_32 dal_fixed31_32_mul( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + struct fixed31_32 res; + + bool arg1_negative = arg1.value < 0; + bool arg2_negative = arg2.value < 0; + + uint64_t arg1_value = arg1_negative ? -arg1.value : arg1.value; + uint64_t arg2_value = arg2_negative ? -arg2.value : arg2.value; + + uint64_t arg1_int = GET_INTEGER_PART(arg1_value); + uint64_t arg2_int = GET_INTEGER_PART(arg2_value); + + uint64_t arg1_fra = GET_FRACTIONAL_PART(arg1_value); + uint64_t arg2_fra = GET_FRACTIONAL_PART(arg2_value); + + uint64_t tmp; + + res.value = arg1_int * arg2_int; + + ASSERT(res.value <= LONG_MAX); + + res.value <<= BITS_PER_FRACTIONAL_PART; + + tmp = arg1_int * arg2_fra; + + ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value)); + + res.value += tmp; + + tmp = arg2_int * arg1_fra; + + ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value)); + + res.value += tmp; + + tmp = arg1_fra * arg2_fra; + + tmp = (tmp >> BITS_PER_FRACTIONAL_PART) + + (tmp >= (uint64_t)dal_fixed31_32_half.value); + + ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value)); + + res.value += tmp; + + if (arg1_negative ^ arg2_negative) + res.value = -res.value; + + return res; +} + +struct fixed31_32 dal_fixed31_32_sqr( + struct fixed31_32 arg) +{ + struct fixed31_32 res; + + uint64_t arg_value = abs_i64(arg.value); + + uint64_t arg_int = GET_INTEGER_PART(arg_value); + + uint64_t arg_fra = GET_FRACTIONAL_PART(arg_value); + + uint64_t tmp; + + res.value = arg_int * arg_int; + + ASSERT(res.value <= LONG_MAX); + + res.value <<= BITS_PER_FRACTIONAL_PART; + + tmp = arg_int * arg_fra; + + ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value)); + + res.value += tmp; + + ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value)); + + res.value += tmp; + + tmp = arg_fra * arg_fra; + + tmp = (tmp >> BITS_PER_FRACTIONAL_PART) + + (tmp >= (uint64_t)dal_fixed31_32_half.value); + + ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value)); + + res.value += tmp; + + return res; +} + +struct fixed31_32 dal_fixed31_32_div_int( + struct fixed31_32 arg1, + int64_t arg2) +{ + return dal_fixed31_32_from_fraction( + arg1.value, + dal_fixed31_32_from_int(arg2).value); +} + +struct fixed31_32 dal_fixed31_32_div( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + return dal_fixed31_32_from_fraction( + arg1.value, + arg2.value); +} + +struct fixed31_32 dal_fixed31_32_recip( + struct fixed31_32 arg) +{ + /* + * @note + * Good idea to use Newton's method + */ + + ASSERT(arg.value); + + return dal_fixed31_32_from_fraction( + dal_fixed31_32_one.value, + arg.value); +} + +struct fixed31_32 dal_fixed31_32_sinc( + struct fixed31_32 arg) +{ + struct fixed31_32 square; + + struct fixed31_32 res = dal_fixed31_32_one; + + int32_t n = 27; + + struct fixed31_32 arg_norm = arg; + + if (dal_fixed31_32_le( + dal_fixed31_32_two_pi, + dal_fixed31_32_abs(arg))) { + arg_norm = dal_fixed31_32_sub( + arg_norm, + dal_fixed31_32_mul_int( + dal_fixed31_32_two_pi, + (int32_t)div64_s64( + arg_norm.value, + dal_fixed31_32_two_pi.value))); + } + + square = dal_fixed31_32_sqr(arg_norm); + + do { + res = dal_fixed31_32_sub( + dal_fixed31_32_one, + dal_fixed31_32_div_int( + dal_fixed31_32_mul( + square, + res), + n * (n - 1))); + + n -= 2; + } while (n > 2); + + if (arg.value != arg_norm.value) + res = dal_fixed31_32_div( + dal_fixed31_32_mul(res, arg_norm), + arg); + + return res; +} + +struct fixed31_32 dal_fixed31_32_sin( + struct fixed31_32 arg) +{ + return dal_fixed31_32_mul( + arg, + dal_fixed31_32_sinc(arg)); +} + +struct fixed31_32 dal_fixed31_32_cos( + struct fixed31_32 arg) +{ + /* TODO implement argument normalization */ + + const struct fixed31_32 square = dal_fixed31_32_sqr(arg); + + struct fixed31_32 res = dal_fixed31_32_one; + + int32_t n = 26; + + do { + res = dal_fixed31_32_sub( + dal_fixed31_32_one, + dal_fixed31_32_div_int( + dal_fixed31_32_mul( + square, + res), + n * (n - 1))); + + n -= 2; + } while (n != 0); + + return res; +} + +/* + * @brief + * result = exp(arg), + * where abs(arg) < 1 + * + * Calculated as Taylor series. + */ +static struct fixed31_32 fixed31_32_exp_from_taylor_series( + struct fixed31_32 arg) +{ + uint32_t n = 9; + + struct fixed31_32 res = dal_fixed31_32_from_fraction( + n + 2, + n + 1); + /* TODO find correct res */ + + ASSERT(dal_fixed31_32_lt(arg, dal_fixed31_32_one)); + + do + res = dal_fixed31_32_add( + dal_fixed31_32_one, + dal_fixed31_32_div_int( + dal_fixed31_32_mul( + arg, + res), + n)); + while (--n != 1); + + return dal_fixed31_32_add( + dal_fixed31_32_one, + dal_fixed31_32_mul( + arg, + res)); +} + +struct fixed31_32 dal_fixed31_32_exp( + struct fixed31_32 arg) +{ + /* + * @brief + * Main equation is: + * exp(x) = exp(r + m * ln(2)) = (1 << m) * exp(r), + * where m = round(x / ln(2)), r = x - m * ln(2) + */ + + if (dal_fixed31_32_le( + dal_fixed31_32_ln2_div_2, + dal_fixed31_32_abs(arg))) { + int32_t m = dal_fixed31_32_round( + dal_fixed31_32_div( + arg, + dal_fixed31_32_ln2)); + + struct fixed31_32 r = dal_fixed31_32_sub( + arg, + dal_fixed31_32_mul_int( + dal_fixed31_32_ln2, + m)); + + ASSERT(m != 0); + + ASSERT(dal_fixed31_32_lt( + dal_fixed31_32_abs(r), + dal_fixed31_32_one)); + + if (m > 0) + return dal_fixed31_32_shl( + fixed31_32_exp_from_taylor_series(r), + (uint8_t)m); + else + return dal_fixed31_32_div_int( + fixed31_32_exp_from_taylor_series(r), + 1LL << -m); + } else if (arg.value != 0) + return fixed31_32_exp_from_taylor_series(arg); + else + return dal_fixed31_32_one; +} + +struct fixed31_32 dal_fixed31_32_log( + struct fixed31_32 arg) +{ + struct fixed31_32 res = dal_fixed31_32_neg(dal_fixed31_32_one); + /* TODO improve 1st estimation */ + + struct fixed31_32 error; + + ASSERT(arg.value > 0); + /* TODO if arg is negative, return NaN */ + /* TODO if arg is zero, return -INF */ + + do { + struct fixed31_32 res1 = dal_fixed31_32_add( + dal_fixed31_32_sub( + res, + dal_fixed31_32_one), + dal_fixed31_32_div( + arg, + dal_fixed31_32_exp(res))); + + error = dal_fixed31_32_sub( + res, + res1); + + res = res1; + /* TODO determine max_allowed_error based on quality of exp() */ + } while (abs_i64(error.value) > 100ULL); + + return res; +} + +struct fixed31_32 dal_fixed31_32_pow( + struct fixed31_32 arg1, + struct fixed31_32 arg2) +{ + return dal_fixed31_32_exp( + dal_fixed31_32_mul( + dal_fixed31_32_log(arg1), + arg2)); +} + +int32_t dal_fixed31_32_floor( + struct fixed31_32 arg) +{ + uint64_t arg_value = abs_i64(arg.value); + + if (arg.value >= 0) + return (int32_t)GET_INTEGER_PART(arg_value); + else + return -(int32_t)GET_INTEGER_PART(arg_value); +} + +int32_t dal_fixed31_32_round( + struct fixed31_32 arg) +{ + uint64_t arg_value = abs_i64(arg.value); + + const int64_t summand = dal_fixed31_32_half.value; + + ASSERT(LLONG_MAX - (int64_t)arg_value >= summand); + + arg_value += summand; + + if (arg.value >= 0) + return (int32_t)GET_INTEGER_PART(arg_value); + else + return -(int32_t)GET_INTEGER_PART(arg_value); +} + +int32_t dal_fixed31_32_ceil( + struct fixed31_32 arg) +{ + uint64_t arg_value = abs_i64(arg.value); + + const int64_t summand = dal_fixed31_32_one.value - + dal_fixed31_32_epsilon.value; + + ASSERT(LLONG_MAX - (int64_t)arg_value >= summand); + + arg_value += summand; + + if (arg.value >= 0) + return (int32_t)GET_INTEGER_PART(arg_value); + else + return -(int32_t)GET_INTEGER_PART(arg_value); +} + +/* this function is a generic helper to translate fixed point value to + * specified integer format that will consist of integer_bits integer part and + * fractional_bits fractional part. For example it is used in + * dal_fixed31_32_u2d19 to receive 2 bits integer part and 19 bits fractional + * part in 32 bits. It is used in hw programming (scaler) + */ + +static inline uint32_t ux_dy( + int64_t value, + uint32_t integer_bits, + uint32_t fractional_bits) +{ + /* 1. create mask of integer part */ + uint32_t result = (1 << integer_bits) - 1; + /* 2. mask out fractional part */ + uint32_t fractional_part = FRACTIONAL_PART_MASK & value; + /* 3. shrink fixed point integer part to be of integer_bits width*/ + result &= GET_INTEGER_PART(value); + /* 4. make space for fractional part to be filled in after integer */ + result <<= fractional_bits; + /* 5. shrink fixed point fractional part to of fractional_bits width*/ + fractional_part >>= BITS_PER_FRACTIONAL_PART - fractional_bits; + /* 6. merge the result */ + return result | fractional_part; +} + +uint32_t dal_fixed31_32_u2d19( + struct fixed31_32 arg) +{ + return ux_dy(arg.value, 2, 19); +} + +uint32_t dal_fixed31_32_u0d19( + struct fixed31_32 arg) +{ + return ux_dy(arg.value, 0, 19); +} diff --git a/drivers/gpu/drm/amd/display/dc/basics/fixpt32_32.c b/drivers/gpu/drm/amd/display/dc/basics/fixpt32_32.c new file mode 100644 index 000000000000..911e90bb1b5c --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/fixpt32_32.c @@ -0,0 +1,221 @@ +/* + * 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 "include/fixed32_32.h" + +static uint64_t u64_div(uint64_t n, uint64_t d) +{ + uint32_t i = 0; + uint64_t r; + uint64_t q = div64_u64_rem(n, d, &r); + + for (i = 0; i < 32; ++i) { + uint64_t sbit = q & (1ULL<<63); + + r <<= 1; + r |= sbit ? 1 : 0; + q <<= 1; + if (r >= d) { + r -= d; + q |= 1; + } + } + + if (2*r >= d) + q += 1; + return q; +} + +struct fixed32_32 dal_fixed32_32_from_fraction(uint32_t n, uint32_t d) +{ + struct fixed32_32 fx; + + fx.value = u64_div((uint64_t)n << 32, (uint64_t)d << 32); + return fx; +} + +struct fixed32_32 dal_fixed32_32_from_int(uint32_t value) +{ + struct fixed32_32 fx; + + fx.value = (uint64_t)value<<32; + return fx; +} + +struct fixed32_32 dal_fixed32_32_add( + struct fixed32_32 lhs, + struct fixed32_32 rhs) +{ + struct fixed32_32 fx = {lhs.value + rhs.value}; + + ASSERT(fx.value >= rhs.value); + return fx; +} + +struct fixed32_32 dal_fixed32_32_add_int(struct fixed32_32 lhs, uint32_t rhs) +{ + struct fixed32_32 fx = {lhs.value + ((uint64_t)rhs << 32)}; + + ASSERT(fx.value >= (uint64_t)rhs << 32); + return fx; + +} +struct fixed32_32 dal_fixed32_32_sub( + struct fixed32_32 lhs, + struct fixed32_32 rhs) +{ + struct fixed32_32 fx; + + ASSERT(lhs.value >= rhs.value); + fx.value = lhs.value - rhs.value; + return fx; +} + +struct fixed32_32 dal_fixed32_32_sub_int(struct fixed32_32 lhs, uint32_t rhs) +{ + struct fixed32_32 fx; + + ASSERT(lhs.value >= ((uint64_t)rhs<<32)); + fx.value = lhs.value - ((uint64_t)rhs<<32); + return fx; +} + +struct fixed32_32 dal_fixed32_32_mul( + struct fixed32_32 lhs, + struct fixed32_32 rhs) +{ + struct fixed32_32 fx; + uint64_t lhs_int = lhs.value>>32; + uint64_t lhs_frac = (uint32_t)lhs.value; + uint64_t rhs_int = rhs.value>>32; + uint64_t rhs_frac = (uint32_t)rhs.value; + uint64_t ahbh = lhs_int * rhs_int; + uint64_t ahbl = lhs_int * rhs_frac; + uint64_t albh = lhs_frac * rhs_int; + uint64_t albl = lhs_frac * rhs_frac; + + ASSERT((ahbh>>32) == 0); + + fx.value = (ahbh<<32) + ahbl + albh + (albl>>32); + return fx; + +} + +struct fixed32_32 dal_fixed32_32_mul_int(struct fixed32_32 lhs, uint32_t rhs) +{ + struct fixed32_32 fx; + uint64_t lhsi = (lhs.value>>32) * (uint64_t)rhs; + uint64_t lhsf; + + ASSERT((lhsi>>32) == 0); + lhsf = ((uint32_t)lhs.value) * (uint64_t)rhs; + ASSERT((lhsi<<32) + lhsf >= lhsf); + fx.value = (lhsi<<32) + lhsf; + return fx; +} + +struct fixed32_32 dal_fixed32_32_div( + struct fixed32_32 lhs, + struct fixed32_32 rhs) +{ + struct fixed32_32 fx; + + fx.value = u64_div(lhs.value, rhs.value); + return fx; +} + +struct fixed32_32 dal_fixed32_32_div_int(struct fixed32_32 lhs, uint32_t rhs) +{ + struct fixed32_32 fx; + + fx.value = u64_div(lhs.value, (uint64_t)rhs << 32); + return fx; +} + +struct fixed32_32 dal_fixed32_32_min( + struct fixed32_32 lhs, + struct fixed32_32 rhs) +{ + return (lhs.value < rhs.value) ? lhs : rhs; +} + +struct fixed32_32 dal_fixed32_32_max( + struct fixed32_32 lhs, + struct fixed32_32 rhs) +{ + return (lhs.value > rhs.value) ? lhs : rhs; +} + +bool dal_fixed32_32_gt(struct fixed32_32 lhs, struct fixed32_32 rhs) +{ + return lhs.value > rhs.value; +} +bool dal_fixed32_32_gt_int(struct fixed32_32 lhs, uint32_t rhs) +{ + return lhs.value > ((uint64_t)rhs<<32); +} + +bool dal_fixed32_32_lt(struct fixed32_32 lhs, struct fixed32_32 rhs) +{ + return lhs.value < rhs.value; +} + +bool dal_fixed32_32_le(struct fixed32_32 lhs, struct fixed32_32 rhs) +{ + return lhs.value <= rhs.value; +} + +bool dal_fixed32_32_lt_int(struct fixed32_32 lhs, uint32_t rhs) +{ + return lhs.value < ((uint64_t)rhs<<32); +} + +bool dal_fixed32_32_le_int(struct fixed32_32 lhs, uint32_t rhs) +{ + return lhs.value <= ((uint64_t)rhs<<32); +} + +uint32_t dal_fixed32_32_ceil(struct fixed32_32 v) +{ + ASSERT((uint32_t)v.value ? (v.value >> 32) + 1 >= 1 : true); + return (v.value>>32) + ((uint32_t)v.value ? 1 : 0); +} + +uint32_t dal_fixed32_32_floor(struct fixed32_32 v) +{ + return v.value>>32; +} + +uint32_t dal_fixed32_32_round(struct fixed32_32 v) +{ + ASSERT(v.value + (1ULL<<31) >= (1ULL<<31)); + return (v.value + (1ULL<<31))>>32; +} + +bool dal_fixed32_32_eq(struct fixed32_32 lhs, struct fixed32_32 rhs) +{ + return lhs.value == rhs.value; +} diff --git a/drivers/gpu/drm/amd/display/dc/basics/grph_object_id.c b/drivers/gpu/drm/amd/display/dc/basics/grph_object_id.c new file mode 100644 index 000000000000..9c80847d03a9 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/grph_object_id.c @@ -0,0 +1,134 @@ +/* + * 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 "include/grph_object_id.h" + +bool dal_graphics_object_id_is_valid(struct graphics_object_id id) +{ + bool rc = true; + + switch (id.type) { + case OBJECT_TYPE_UNKNOWN: + rc = false; + break; + case OBJECT_TYPE_GPU: + case OBJECT_TYPE_ENGINE: + /* do NOT check for id.id == 0 */ + if (id.enum_id == ENUM_ID_UNKNOWN) + rc = false; + break; + default: + if (id.id == 0 || id.enum_id == ENUM_ID_UNKNOWN) + rc = false; + break; + } + + return rc; +} + +bool dal_graphics_object_id_is_equal( + struct graphics_object_id id1, + struct graphics_object_id id2) +{ + if (false == dal_graphics_object_id_is_valid(id1)) { + dm_output_to_console( + "%s: Warning: comparing invalid object 'id1'!\n", __func__); + return false; + } + + if (false == dal_graphics_object_id_is_valid(id2)) { + dm_output_to_console( + "%s: Warning: comparing invalid object 'id2'!\n", __func__); + return false; + } + + if (id1.id == id2.id && id1.enum_id == id2.enum_id + && id1.type == id2.type) + return true; + + return false; +} + +/* Based on internal data members memory layout */ +uint32_t dal_graphics_object_id_to_uint(struct graphics_object_id id) +{ + uint32_t object_id = 0; + + object_id = id.id + (id.enum_id << 0x8) + (id.type << 0xc); + return object_id; +} + +/* + * ******* get specific ID - internal safe cast into specific type ******* + */ + +enum controller_id dal_graphics_object_id_get_controller_id( + struct graphics_object_id id) +{ + if (id.type == OBJECT_TYPE_CONTROLLER) + return id.id; + return CONTROLLER_ID_UNDEFINED; +} + +enum clock_source_id dal_graphics_object_id_get_clock_source_id( + struct graphics_object_id id) +{ + if (id.type == OBJECT_TYPE_CLOCK_SOURCE) + return id.id; + return CLOCK_SOURCE_ID_UNDEFINED; +} + +enum encoder_id dal_graphics_object_id_get_encoder_id( + struct graphics_object_id id) +{ + if (id.type == OBJECT_TYPE_ENCODER) + return id.id; + return ENCODER_ID_UNKNOWN; +} + +enum connector_id dal_graphics_object_id_get_connector_id( + struct graphics_object_id id) +{ + if (id.type == OBJECT_TYPE_CONNECTOR) + return id.id; + return CONNECTOR_ID_UNKNOWN; +} + +enum audio_id dal_graphics_object_id_get_audio_id(struct graphics_object_id id) +{ + if (id.type == OBJECT_TYPE_AUDIO) + return id.id; + return AUDIO_ID_UNKNOWN; +} + +enum engine_id dal_graphics_object_id_get_engine_id( + struct graphics_object_id id) +{ + if (id.type == OBJECT_TYPE_ENGINE) + return id.id; + return ENGINE_ID_UNKNOWN; +} + diff --git a/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c b/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c new file mode 100644 index 000000000000..61f36a7f322b --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/log_helpers.c @@ -0,0 +1,100 @@ +/* + * Copyright 2012-16 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 "core_types.h" +#include "logger.h" +#include "include/logger_interface.h" + +#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) + +struct dc_signal_type_info { + enum signal_type type; + char name[MAX_NAME_LEN]; +}; + +static const struct dc_signal_type_info signal_type_info_tbl[] = { + {SIGNAL_TYPE_NONE, "NC"}, + {SIGNAL_TYPE_DVI_SINGLE_LINK, "DVI"}, + {SIGNAL_TYPE_DVI_DUAL_LINK, "DDVI"}, + {SIGNAL_TYPE_HDMI_TYPE_A, "HDMIA"}, + {SIGNAL_TYPE_LVDS, "LVDS"}, + {SIGNAL_TYPE_RGB, "VGA"}, + {SIGNAL_TYPE_DISPLAY_PORT, "DP"}, + {SIGNAL_TYPE_DISPLAY_PORT_MST, "MST"}, + {SIGNAL_TYPE_EDP, "eDP"}, + {SIGNAL_TYPE_WIRELESS, "Wireless"}, + {SIGNAL_TYPE_VIRTUAL, "Virtual"} +}; + +void dc_conn_log(struct dc_context *ctx, + const struct dc_link *link, + uint8_t *hex_data, + int hex_data_count, + enum dc_log_type event, + const char *msg, + ...) +{ + int i; + va_list args; + struct log_entry entry = { 0 }; + enum signal_type signal; + + if (link->local_sink) + signal = link->local_sink->sink_signal; + else + signal = link->connector_signal; + + if (link->type == dc_connection_mst_branch) + signal = SIGNAL_TYPE_DISPLAY_PORT_MST; + + dm_logger_open(ctx->logger, &entry, event); + + for (i = 0; i < NUM_ELEMENTS(signal_type_info_tbl); i++) + if (signal == signal_type_info_tbl[i].type) + break; + + dm_logger_append(&entry, "[%s][ConnIdx:%d] ", + signal_type_info_tbl[i].name, + link->link_index); + + va_start(args, msg); + entry.buf_offset += dm_log_to_buffer( + &entry.buf[entry.buf_offset], + LOG_MAX_LINE_SIZE - entry.buf_offset, + msg, args); + + if (entry.buf[strlen(entry.buf) - 1] == '\n') { + entry.buf[strlen(entry.buf) - 1] = '\0'; + entry.buf_offset--; + } + + if (hex_data) + for (i = 0; i < hex_data_count; i++) + dm_logger_append(&entry, "%2.2X ", hex_data[i]); + + dm_logger_append(&entry, "^\n"); + dm_logger_close(&entry); + va_end(args); +} diff --git a/drivers/gpu/drm/amd/display/dc/basics/logger.c b/drivers/gpu/drm/amd/display/dc/basics/logger.c new file mode 100644 index 000000000000..a5625a3badab --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/logger.c @@ -0,0 +1,457 @@ +/* + * 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 "include/logger_interface.h" +#include "logger.h" + + +#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) + +static const struct dc_log_type_info log_type_info_tbl[] = { + {LOG_ERROR, "Error"}, + {LOG_WARNING, "Warning"}, + {LOG_DC, "DC_Interface"}, + {LOG_SURFACE, "Surface"}, + {LOG_HW_HOTPLUG, "HW_Hotplug"}, + {LOG_HW_LINK_TRAINING, "HW_LKTN"}, + {LOG_HW_SET_MODE, "HW_Mode"}, + {LOG_HW_RESUME_S3, "HW_Resume"}, + {LOG_HW_AUDIO, "HW_Audio"}, + {LOG_HW_HPD_IRQ, "HW_HPDIRQ"}, + {LOG_MST, "MST"}, + {LOG_SCALER, "Scaler"}, + {LOG_BIOS, "BIOS"}, + {LOG_BANDWIDTH_CALCS, "BWCalcs"}, + {LOG_BANDWIDTH_VALIDATION, "BWValidation"}, + {LOG_I2C_AUX, "I2C_AUX"}, + {LOG_SYNC, "Sync"}, + {LOG_BACKLIGHT, "Backlight"}, + {LOG_FEATURE_OVERRIDE, "Override"}, + {LOG_DETECTION_EDID_PARSER, "Edid"}, + {LOG_DETECTION_DP_CAPS, "DP_Caps"}, + {LOG_RESOURCE, "Resource"}, + {LOG_DML, "DML"}, + {LOG_EVENT_MODE_SET, "Mode"}, + {LOG_EVENT_DETECTION, "Detect"}, + {LOG_EVENT_LINK_TRAINING, "LKTN"}, + {LOG_EVENT_LINK_LOSS, "LinkLoss"}, + {LOG_EVENT_UNDERFLOW, "Underflow"}, + {LOG_IF_TRACE, "InterfaceTrace"} +}; + + +#define DC_DEFAULT_LOG_MASK ((1 << LOG_ERROR) | \ + (1 << LOG_WARNING) | \ + (1 << LOG_EVENT_MODE_SET) | \ + (1 << LOG_EVENT_DETECTION) | \ + (1 << LOG_EVENT_LINK_TRAINING) | \ + (1 << LOG_EVENT_LINK_LOSS) | \ + (1 << LOG_EVENT_UNDERFLOW) | \ + (1 << LOG_RESOURCE) | \ + (1 << LOG_FEATURE_OVERRIDE) | \ + (1 << LOG_DETECTION_EDID_PARSER) | \ + (1 << LOG_DC) | \ + (1 << LOG_HW_HOTPLUG) | \ + (1 << LOG_HW_SET_MODE) | \ + (1 << LOG_HW_RESUME_S3) | \ + (1 << LOG_HW_HPD_IRQ) | \ + (1 << LOG_SYNC) | \ + (1 << LOG_BANDWIDTH_VALIDATION) | \ + (1 << LOG_MST) | \ + (1 << LOG_BIOS) | \ + (1 << LOG_DETECTION_EDID_PARSER) | \ + (1 << LOG_DETECTION_DP_CAPS) | \ + (1 << LOG_BACKLIGHT)) | \ + (1 << LOG_I2C_AUX) | \ + (1 << LOG_IF_TRACE) /* | \ + (1 << LOG_SURFACE) | \ + (1 << LOG_SCALER) | \ + (1 << LOG_DML) | \ + (1 << LOG_HW_LINK_TRAINING) | \ + (1 << LOG_HW_AUDIO)| \ + (1 << LOG_BANDWIDTH_CALCS)*/ + +/* ----------- Object init and destruction ----------- */ +static bool construct(struct dc_context *ctx, struct dal_logger *logger) +{ + /* malloc buffer and init offsets */ + logger->log_buffer_size = DAL_LOGGER_BUFFER_MAX_SIZE; + logger->log_buffer = (char *)dm_alloc(logger->log_buffer_size * + sizeof(char)); + + if (!logger->log_buffer) + return false; + + /* Initialize both offsets to start of buffer (empty) */ + logger->buffer_read_offset = 0; + logger->buffer_write_offset = 0; + + logger->write_wrap_count = 0; + logger->read_wrap_count = 0; + logger->open_count = 0; + + logger->flags.bits.ENABLE_CONSOLE = 1; + logger->flags.bits.ENABLE_BUFFER = 0; + + logger->ctx = ctx; + + logger->mask = DC_DEFAULT_LOG_MASK; + + return true; +} + +static void destruct(struct dal_logger *logger) +{ + if (logger->log_buffer) { + dm_free(logger->log_buffer); + logger->log_buffer = NULL; + } +} + +struct dal_logger *dal_logger_create(struct dc_context *ctx) +{ + /* malloc struct */ + struct dal_logger *logger = dm_alloc(sizeof(struct dal_logger)); + + if (!logger) + return NULL; + if (!construct(ctx, logger)) { + dm_free(logger); + return NULL; + } + + return logger; +} + +uint32_t dal_logger_destroy(struct dal_logger **logger) +{ + if (logger == NULL || *logger == NULL) + return 1; + destruct(*logger); + dm_free(*logger); + *logger = NULL; + + return 0; +} + +/* ------------------------------------------------------------------------ */ + + +static bool dal_logger_should_log( + struct dal_logger *logger, + enum dc_log_type log_type) +{ + if (logger->mask & (1 << log_type)) + return true; + + return false; +} + +static void log_to_debug_console(struct log_entry *entry) +{ + struct dal_logger *logger = entry->logger; + + if (logger->flags.bits.ENABLE_CONSOLE == 0) + return; + + if (entry->buf_offset) { + switch (entry->type) { + case LOG_ERROR: + dm_error("%s", entry->buf); + break; + default: + dm_output_to_console("%s", entry->buf); + break; + } + } +} + +/* Print everything unread existing in log_buffer to debug console*/ +static void flush_to_debug_console(struct dal_logger *logger) +{ + int i = logger->buffer_read_offset; + char *string_start = &logger->log_buffer[i]; + + dm_output_to_console( + "---------------- FLUSHING LOG BUFFER ----------------\n"); + while (i < logger->buffer_write_offset) { + + if (logger->log_buffer[i] == '\0') { + dm_output_to_console("%s", string_start); + string_start = (char *)logger->log_buffer + i + 1; + } + i++; + } + dm_output_to_console( + "-------------- END FLUSHING LOG BUFFER --------------\n\n"); +} + +static void log_to_internal_buffer(struct log_entry *entry) +{ + + uint32_t size = entry->buf_offset; + struct dal_logger *logger = entry->logger; + + if (logger->flags.bits.ENABLE_BUFFER == 0) + return; + + if (logger->log_buffer == NULL) + return; + + if (size > 0 && size < logger->log_buffer_size) { + + int total_free_space = 0; + int space_before_wrap = 0; + + if (logger->buffer_write_offset > logger->buffer_read_offset) { + total_free_space = logger->log_buffer_size - + logger->buffer_write_offset + + logger->buffer_read_offset; + space_before_wrap = logger->log_buffer_size - + logger->buffer_write_offset; + } else if (logger->buffer_write_offset < + logger->buffer_read_offset) { + total_free_space = logger->log_buffer_size - + logger->buffer_read_offset + + logger->buffer_write_offset; + space_before_wrap = total_free_space; + } else if (logger->write_wrap_count != + logger->read_wrap_count) { + /* Buffer is completely full already */ + total_free_space = 0; + space_before_wrap = 0; + } else { + /* Buffer is empty, start writing at beginning */ + total_free_space = logger->log_buffer_size; + space_before_wrap = logger->log_buffer_size; + logger->buffer_write_offset = 0; + logger->buffer_read_offset = 0; + } + + if (space_before_wrap > size) { + /* No wrap around, copy 'size' bytes + * from 'entry->buf' to 'log_buffer' + */ + memmove(logger->log_buffer + + logger->buffer_write_offset, + entry->buf, size); + logger->buffer_write_offset += size; + + } else if (total_free_space > size) { + /* We have enough room without flushing, + * but need to wrap around */ + + int space_after_wrap = total_free_space - + space_before_wrap; + + memmove(logger->log_buffer + + logger->buffer_write_offset, + entry->buf, space_before_wrap); + memmove(logger->log_buffer, entry->buf + + space_before_wrap, space_after_wrap); + + logger->buffer_write_offset = space_after_wrap; + logger->write_wrap_count++; + + } else { + /* Not enough room remaining, we should flush + * existing logs */ + + /* Flush existing unread logs to console */ + flush_to_debug_console(logger); + + /* Start writing to beginning of buffer */ + memmove(logger->log_buffer, entry->buf, size); + logger->buffer_write_offset = size; + logger->buffer_read_offset = 0; + } + + } +} + +static void log_heading(struct log_entry *entry) +{ + int j; + + for (j = 0; j < NUM_ELEMENTS(log_type_info_tbl); j++) { + + const struct dc_log_type_info *info = &log_type_info_tbl[j]; + + if (info->type == entry->type) + dm_logger_append(entry, "[%s]\t", info->name); + } +} + +static void append_entry( + struct log_entry *entry, + char *buffer, + uint32_t buf_size) +{ + if (!entry->buf || + entry->buf_offset + buf_size > entry->max_buf_bytes + ) { + BREAK_TO_DEBUGGER(); + return; + } + + /* Todo: check if off by 1 byte due to \0 anywhere */ + memmove(entry->buf + entry->buf_offset, buffer, buf_size); + entry->buf_offset += buf_size; +} + +/* ------------------------------------------------------------------------ */ + +/* Warning: Be careful that 'msg' is null terminated and the total size is + * less than DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE (256) including '\0' + */ +void dm_logger_write( + struct dal_logger *logger, + enum dc_log_type log_type, + const char *msg, + ...) +{ + if (logger && dal_logger_should_log(logger, log_type)) { + uint32_t size; + va_list args; + char buffer[LOG_MAX_LINE_SIZE]; + struct log_entry entry; + + va_start(args, msg); + + entry.logger = logger; + + entry.buf = buffer; + + entry.buf_offset = 0; + entry.max_buf_bytes = DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char); + + entry.type = log_type; + + log_heading(&entry); + + size = dm_log_to_buffer( + buffer, LOG_MAX_LINE_SIZE, msg, args); + + entry.buf_offset += size; + + /* --Flush log_entry buffer-- */ + /* print to kernel console */ + log_to_debug_console(&entry); + /* log internally for dsat */ + log_to_internal_buffer(&entry); + + va_end(args); + } +} + +/* Same as dm_logger_write, except without open() and close(), which must + * be done separately. + */ +void dm_logger_append( + struct log_entry *entry, + const char *msg, + ...) +{ + struct dal_logger *logger; + + if (!entry) { + BREAK_TO_DEBUGGER(); + return; + } + + logger = entry->logger; + + if (logger && logger->open_count > 0 && + dal_logger_should_log(logger, entry->type)) { + + uint32_t size; + va_list args; + char buffer[LOG_MAX_LINE_SIZE]; + + va_start(args, msg); + + size = dm_log_to_buffer( + buffer, LOG_MAX_LINE_SIZE, msg, args); + + if (size < LOG_MAX_LINE_SIZE - 1) { + append_entry(entry, buffer, size); + } else { + append_entry(entry, "LOG_ERROR, line too long\n", 27); + } + + va_end(args); + } +} + +void dm_logger_open( + struct dal_logger *logger, + struct log_entry *entry, /* out */ + enum dc_log_type log_type) +{ + if (!entry) { + BREAK_TO_DEBUGGER(); + return; + } + + entry->type = log_type; + entry->logger = logger; + + entry->buf = dm_alloc(DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char)); + + entry->buf_offset = 0; + entry->max_buf_bytes = DAL_LOGGER_BUFFER_MAX_SIZE * sizeof(char); + + logger->open_count++; + + log_heading(entry); +} + +void dm_logger_close(struct log_entry *entry) +{ + struct dal_logger *logger = entry->logger; + + if (logger && logger->open_count > 0) { + logger->open_count--; + } else { + BREAK_TO_DEBUGGER(); + goto cleanup; + } + + /* --Flush log_entry buffer-- */ + /* print to kernel console */ + log_to_debug_console(entry); + /* log internally for dsat */ + log_to_internal_buffer(entry); + + /* TODO: Write end heading */ + +cleanup: + if (entry->buf) { + dm_free(entry->buf); + entry->buf = NULL; + entry->buf_offset = 0; + entry->max_buf_bytes = 0; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/basics/logger.h b/drivers/gpu/drm/amd/display/dc/basics/logger.h new file mode 100644 index 000000000000..2f7a5df4c811 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/logger.h @@ -0,0 +1,67 @@ +/* + * 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 __DAL_LOGGER_H__ +#define __DAL_LOGGER_H__ + +/* Structure for keeping track of offsets, buffer, etc */ + +#define DAL_LOGGER_BUFFER_MAX_SIZE 2048 + +/*Connectivity log needs to output EDID, which needs at lease 256x3 bytes, + * change log line size to 896 to meet the request. + */ +#define LOG_MAX_LINE_SIZE 896 + +#include "include/logger_types.h" + +struct dal_logger { + + /* How far into the circular buffer has been read by dsat + * Read offset should never cross write offset. Write \0's to + * read data just to be sure? + */ + uint32_t buffer_read_offset; + + /* How far into the circular buffer we have written + * Write offset should never cross read offset + */ + uint32_t buffer_write_offset; + + uint32_t write_wrap_count; + uint32_t read_wrap_count; + + uint32_t open_count; + + char *log_buffer; /* Pointer to malloc'ed buffer */ + uint32_t log_buffer_size; /* Size of circular buffer */ + + uint32_t mask; /*array of masks for major elements*/ + + union logger_flags flags; + struct dc_context *ctx; +}; + +#endif /* __DAL_LOGGER_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/basics/register_logger.c b/drivers/gpu/drm/amd/display/dc/basics/register_logger.c new file mode 100644 index 000000000000..b8d57d919fe4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/register_logger.c @@ -0,0 +1,197 @@ +/* + * 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 "include/dal_types.h" +#include "include/logger_interface.h" +#include "logger.h" + +/****************************************************************************** + * Register Logger. + * A facility to create register R/W logs. + * Currently used for DAL Test. + *****************************************************************************/ + +/****************************************************************************** + * Private structures + *****************************************************************************/ +struct dal_reg_dump_stack_location { + const char *current_caller_func; + long current_pid; + long current_tgid; + uint32_t rw_count;/* register access counter for current function. */ +}; + +/* This the maximum number of nested calls to the 'reg_dump' facility. */ +#define DAL_REG_DUMP_STACK_MAX_SIZE 32 + +struct dal_reg_dump_stack { + int32_t stack_pointer; + struct dal_reg_dump_stack_location + stack_locations[DAL_REG_DUMP_STACK_MAX_SIZE]; + uint32_t total_rw_count; /* Total count for *all* functions. */ +}; + +static struct dal_reg_dump_stack reg_dump_stack = {0}; + +/****************************************************************************** + * Private functions + *****************************************************************************/ + +/* Check if current process is the one which requested register dump. + * The reason for the check: + * mmCRTC_STATUS_FRAME_COUNT is accessed by dal_controller_get_vblank_counter(). + * Which runs all the time when at least one display is connected. + * (Triggered by drm_mode_page_flip_ioctl()). */ +static bool is_reg_dump_process(void) +{ + uint32_t i; + + /* walk the list of our processes */ + for (i = 0; i < reg_dump_stack.stack_pointer; i++) { + struct dal_reg_dump_stack_location *stack_location + = ®_dump_stack.stack_locations[i]; + + if (stack_location->current_pid == dm_get_pid() + && stack_location->current_tgid == dm_get_tgid()) + return true; + } + + return false; +} + +static bool dal_reg_dump_stack_is_empty(void) +{ + if (reg_dump_stack.stack_pointer <= 0) + return true; + else + return false; +} + +static struct dal_reg_dump_stack_location *dal_reg_dump_stack_push(void) +{ + struct dal_reg_dump_stack_location *current_location = NULL; + + if (reg_dump_stack.stack_pointer >= DAL_REG_DUMP_STACK_MAX_SIZE) { + /* stack is full */ + dm_output_to_console("[REG_DUMP]: %s: stack is full!\n", + __func__); + } else { + current_location = + ®_dump_stack.stack_locations[reg_dump_stack.stack_pointer]; + ++reg_dump_stack.stack_pointer; + } + + return current_location; +} + +static struct dal_reg_dump_stack_location *dal_reg_dump_stack_pop(void) +{ + struct dal_reg_dump_stack_location *current_location = NULL; + + if (dal_reg_dump_stack_is_empty()) { + /* stack is empty */ + dm_output_to_console("[REG_DUMP]: %s: stack is empty!\n", + __func__); + } else { + --reg_dump_stack.stack_pointer; + current_location = + ®_dump_stack.stack_locations[reg_dump_stack.stack_pointer]; + } + + return current_location; +} + +/****************************************************************************** + * Public functions + *****************************************************************************/ + +void dal_reg_logger_push(const char *caller_func) +{ + struct dal_reg_dump_stack_location *free_stack_location; + + free_stack_location = dal_reg_dump_stack_push(); + + if (NULL == free_stack_location) + return; + + memset(free_stack_location, 0, sizeof(*free_stack_location)); + + free_stack_location->current_caller_func = caller_func; + free_stack_location->current_pid = dm_get_pid(); + free_stack_location->current_tgid = dm_get_tgid(); + + dm_output_to_console("[REG_DUMP]:%s - start (pid:%ld, tgid:%ld)\n", + caller_func, + free_stack_location->current_pid, + free_stack_location->current_tgid); +} + +void dal_reg_logger_pop(void) +{ + struct dal_reg_dump_stack_location *top_stack_location; + + top_stack_location = dal_reg_dump_stack_pop(); + + if (NULL == top_stack_location) { + dm_output_to_console("[REG_DUMP]:%s - Stack is Empty!\n", + __func__); + return; + } + + dm_output_to_console( + "[REG_DUMP]:%s - end."\ + " Reg R/W Count: Total=%d Function=%d. (pid:%ld, tgid:%ld)\n", + top_stack_location->current_caller_func, + reg_dump_stack.total_rw_count, + top_stack_location->rw_count, + dm_get_pid(), + dm_get_tgid()); + + memset(top_stack_location, 0, sizeof(*top_stack_location)); +} + +void dal_reg_logger_rw_count_increment(void) +{ + ++reg_dump_stack.total_rw_count; + + ++reg_dump_stack.stack_locations + [reg_dump_stack.stack_pointer - 1].rw_count; +} + +bool dal_reg_logger_should_dump_register(void) +{ + if (true == dal_reg_dump_stack_is_empty()) + return false; + + if (false == is_reg_dump_process()) + return false; + + return true; +} + +/****************************************************************************** + * End of File. + *****************************************************************************/ diff --git a/drivers/gpu/drm/amd/display/dc/basics/signal_types.c b/drivers/gpu/drm/amd/display/dc/basics/signal_types.c new file mode 100644 index 000000000000..44447e07803a --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/signal_types.c @@ -0,0 +1,116 @@ +/* + * 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 "include/signal_types.h" + +bool dc_is_hdmi_signal(enum signal_type signal) +{ + return (signal == SIGNAL_TYPE_HDMI_TYPE_A); +} + +bool dc_is_dp_sst_signal(enum signal_type signal) +{ + return (signal == SIGNAL_TYPE_DISPLAY_PORT || + signal == SIGNAL_TYPE_EDP); +} + +bool dc_is_dp_signal(enum signal_type signal) +{ + return (signal == SIGNAL_TYPE_DISPLAY_PORT || + signal == SIGNAL_TYPE_EDP || + signal == SIGNAL_TYPE_DISPLAY_PORT_MST); +} + +bool dc_is_dp_external_signal(enum signal_type signal) +{ + return (signal == SIGNAL_TYPE_DISPLAY_PORT || + signal == SIGNAL_TYPE_DISPLAY_PORT_MST); +} + +bool dc_is_analog_signal(enum signal_type signal) +{ + switch (signal) { + case SIGNAL_TYPE_RGB: + return true; + break; + default: + return false; + } +} + +bool dc_is_embedded_signal(enum signal_type signal) +{ + return (signal == SIGNAL_TYPE_EDP || signal == SIGNAL_TYPE_LVDS); +} + +bool dc_is_dvi_signal(enum signal_type signal) +{ + switch (signal) { + case SIGNAL_TYPE_DVI_SINGLE_LINK: + case SIGNAL_TYPE_DVI_DUAL_LINK: + return true; + break; + default: + return false; + } +} + +bool dc_is_dvi_single_link_signal(enum signal_type signal) +{ + return (signal == SIGNAL_TYPE_DVI_SINGLE_LINK); +} + +bool dc_is_dual_link_signal(enum signal_type signal) +{ + return (signal == SIGNAL_TYPE_DVI_DUAL_LINK); +} + +bool dc_is_audio_capable_signal(enum signal_type signal) +{ + return (signal == SIGNAL_TYPE_DISPLAY_PORT || + signal == SIGNAL_TYPE_DISPLAY_PORT_MST || + dc_is_hdmi_signal(signal) || + signal == SIGNAL_TYPE_WIRELESS); +} + +/* + * @brief + * Returns whether the signal is compatible + * with other digital encoder signal types. + * This is true for DVI, LVDS, and HDMI signal types. + */ +bool dc_is_digital_encoder_compatible_signal(enum signal_type signal) +{ + switch (signal) { + case SIGNAL_TYPE_DVI_SINGLE_LINK: + case SIGNAL_TYPE_DVI_DUAL_LINK: + case SIGNAL_TYPE_HDMI_TYPE_A: + case SIGNAL_TYPE_LVDS: + return true; + default: + return false; + } +} diff --git a/drivers/gpu/drm/amd/display/dc/basics/vector.c b/drivers/gpu/drm/amd/display/dc/basics/vector.c new file mode 100644 index 000000000000..bb72a1857160 --- /dev/null +++ b/drivers/gpu/drm/amd/display/dc/basics/vector.c @@ -0,0 +1,307 @@ +/* + * 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 "include/vector.h" + +bool dal_vector_construct( + struct vector *vector, + struct dc_context *ctx, + uint32_t capacity, + uint32_t struct_size) +{ + vector->container = NULL; + + if (!struct_size || !capacity) { + /* Container must be non-zero size*/ + BREAK_TO_DEBUGGER(); + return false; + } + + vector->container = dm_alloc(struct_size * capacity); + if (vector->container == NULL) + return false; + vector->capacity = capacity; + vector->struct_size = struct_size; + vector->count = 0; + vector->ctx = ctx; + return true; +} + +bool dal_vector_presized_costruct( + struct vector *vector, + struct dc_context *ctx, + uint32_t count, + void *initial_value, + uint32_t struct_size) +{ + uint32_t i; + + vector->container = NULL; + + if (!struct_size || !count) { + /* Container must be non-zero size*/ + BREAK_TO_DEBUGGER(); + return false; + } + + vector->container = dm_alloc(struct_size * count); + + if (vector->container == NULL) + return false; + + /* If caller didn't supply initial value then the default + * of all zeros is expected, which is exactly what dal_alloc() + * initialises the memory to. */ + if (NULL != initial_value) { + for (i = 0; i < count; ++i) + memmove( + vector->container + i * struct_size, + initial_value, + struct_size); + } + + vector->capacity = count; + vector->struct_size = struct_size; + vector->count = count; + return true; +} + +struct vector *dal_vector_presized_create( + struct dc_context *ctx, + uint32_t size, + void *initial_value, + uint32_t struct_size) +{ + struct vector *vector = dm_alloc(sizeof(struct vector)); + + if (vector == NULL) + return NULL; + + if (dal_vector_presized_costruct( + vector, ctx, size, initial_value, struct_size)) + return vector; + + BREAK_TO_DEBUGGER(); + dm_free(vector); + return NULL; +} + +struct vector *dal_vector_create( + struct dc_context *ctx, + uint32_t capacity, + uint32_t struct_size) +{ + struct vector *vector = dm_alloc(sizeof(struct vector)); + + if (vector == NULL) + return NULL; + + if (dal_vector_construct(vector, ctx, capacity, struct_size)) + return vector; + + BREAK_TO_DEBUGGER(); + dm_free(vector); + return NULL; +} + +void dal_vector_destruct( + struct vector *vector) +{ + if (vector->container != NULL) + dm_free(vector->container); + vector->count = 0; + vector->capacity = 0; +} + +void dal_vector_destroy( + struct vector **vector) +{ + if (vector == NULL || *vector == NULL) + return; + dal_vector_destruct(*vector); + dm_free(*vector); + *vector = NULL; +} + +uint32_t dal_vector_get_count( + const struct vector *vector) +{ + return vector->count; +} + +void *dal_vector_at_index( + const struct vector *vector, + uint32_t index) +{ + if (vector->container == NULL || index >= vector->count) + return NULL; + return vector->container + (index * vector->struct_size); +} + +bool dal_vector_remove_at_index( + struct vector *vector, + uint32_t index) +{ + if (index >= vector->count) + return false; + + if (index != vector->count - 1) + memmove( + vector->container + (index * vector->struct_size), + vector->container + ((index + 1) * vector->struct_size), + (vector->count - index - 1) * vector->struct_size); + vector->count -= 1; + + return true; +} + +void dal_vector_set_at_index( + const struct vector *vector, + const void *what, + uint32_t index) +{ + void *where = dal_vector_at_index(vector, index); + + if (!where) { + BREAK_TO_DEBUGGER(); + return; + } + memmove( + where, + what, + vector->struct_size); +} + +static inline uint32_t calc_increased_capacity( + uint32_t old_capacity) +{ + return old_capacity * 2; +} + +bool dal_vector_insert_at( + struct vector *vector, + const void *what, + uint32_t position) +{ + uint8_t *insert_address; + + if (vector->count == vector->capacity) { + if (!dal_vector_reserve( + vector, + calc_increased_capacity(vector->capacity))) + return false; + } + + insert_address = vector->container + (vector->struct_size * position); + + if (vector->count && position < vector->count) + memmove( + insert_address + vector->struct_size, + insert_address, + vector->struct_size * (vector->count - position)); + + memmove( + insert_address, + what, + vector->struct_size); + + vector->count++; + + return true; +} + +bool dal_vector_append( + struct vector *vector, + const void *item) +{ + return dal_vector_insert_at(vector, item, vector->count); +} + +struct vector *dal_vector_clone( + const struct vector *vector) +{ + struct vector *vec_cloned; + uint32_t count; + + /* create new vector */ + count = dal_vector_get_count(vector); + + if (count == 0) + /* when count is 0 we still want to create clone of the vector + */ + vec_cloned = dal_vector_create( + vector->ctx, + vector->capacity, + vector->struct_size); + else + /* Call "presized create" version, independently of how the + * original vector was created. + * The owner of original vector must know how to treat the new + * vector - as "presized" or as "regular". + * But from vector point of view it doesn't matter. */ + vec_cloned = dal_vector_presized_create(vector->ctx, count, + NULL,/* no initial value */ + vector->struct_size); + + if (NULL == vec_cloned) { + BREAK_TO_DEBUGGER(); + return NULL; + } + + /* copy vector's data */ + memmove(vec_cloned->container, vector->container, + vec_cloned->struct_size * vec_cloned->capacity); + + return vec_cloned; +} + +uint32_t dal_vector_capacity(const struct vector *vector) +{ + return vector->capacity; +} + +bool dal_vector_reserve(struct vector *vector, uint32_t capacity) +{ + void *new_container; + + if (capacity <= vector->capacity) + return true; + + new_container = dm_realloc(vector->container, capacity * vector->struct_size); + + if (new_container) { + vector->container = new_container; + vector->capacity = capacity; + return true; + } + + return false; +} + +void dal_vector_clear(struct vector *vector) +{ + vector->count = 0; +} |