mirror of
https://github.com/torvalds/linux.git
synced 2026-04-27 11:02:31 -04:00
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>
This commit is contained in:
committed by
Alex Deucher
parent
9c5b2b0d40
commit
4562236b3b
11
drivers/gpu/drm/amd/display/dc/basics/Makefile
Normal file
11
drivers/gpu/drm/amd/display/dc/basics/Makefile
Normal file
@@ -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)
|
||||
223
drivers/gpu/drm/amd/display/dc/basics/conversion.c
Normal file
223
drivers/gpu/drm/amd/display/dc/basics/conversion.c
Normal file
@@ -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);
|
||||
}
|
||||
|
||||
51
drivers/gpu/drm/amd/display/dc/basics/conversion.h
Normal file
51
drivers/gpu/drm/amd/display/dc/basics/conversion.h
Normal file
@@ -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
|
||||
691
drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c
Normal file
691
drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c
Normal file
@@ -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);
|
||||
}
|
||||
221
drivers/gpu/drm/amd/display/dc/basics/fixpt32_32.c
Normal file
221
drivers/gpu/drm/amd/display/dc/basics/fixpt32_32.c
Normal file
@@ -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;
|
||||
}
|
||||
134
drivers/gpu/drm/amd/display/dc/basics/grph_object_id.c
Normal file
134
drivers/gpu/drm/amd/display/dc/basics/grph_object_id.c
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
100
drivers/gpu/drm/amd/display/dc/basics/log_helpers.c
Normal file
100
drivers/gpu/drm/amd/display/dc/basics/log_helpers.c
Normal file
@@ -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);
|
||||
}
|
||||
457
drivers/gpu/drm/amd/display/dc/basics/logger.c
Normal file
457
drivers/gpu/drm/amd/display/dc/basics/logger.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
67
drivers/gpu/drm/amd/display/dc/basics/logger.h
Normal file
67
drivers/gpu/drm/amd/display/dc/basics/logger.h
Normal file
@@ -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__ */
|
||||
197
drivers/gpu/drm/amd/display/dc/basics/register_logger.c
Normal file
197
drivers/gpu/drm/amd/display/dc/basics/register_logger.c
Normal file
@@ -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.
|
||||
*****************************************************************************/
|
||||
116
drivers/gpu/drm/amd/display/dc/basics/signal_types.c
Normal file
116
drivers/gpu/drm/amd/display/dc/basics/signal_types.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
307
drivers/gpu/drm/amd/display/dc/basics/vector.c
Normal file
307
drivers/gpu/drm/amd/display/dc/basics/vector.c
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user