Laying the groundwork for the AMD DAL display driver. This patch includes the basic services and defines basic types required by the display driver, such as: - ASIC register access - VBIOS access - Vector and flat_set data structures - Display signal types - ASIC versions and IDs - HW IDs - Logging functionality This patch adds Kconfig options to enable the DAL display driver. - DRM_AMD_DAL - DRM_AMD_DAL_VBIOS_PRESENT - DRM_AMD_DAL_DCE11_0 - DRM_AMD_DAL_DCE10_0 - DEBUG_KERNEL_DAL Signed-off-by: Harry Wentland <harry.wentland@xxxxxxx> Reviewed-by: Alex Deucher <alexander.deucher@xxxxxxx> --- drivers/gpu/drm/amd/dal/Kconfig | 48 ++ drivers/gpu/drm/amd/dal/Makefile | 21 + drivers/gpu/drm/amd/dal/dc/basics/Makefile | 10 + drivers/gpu/drm/amd/dal/dc/basics/conversion.c | 224 +++++ drivers/gpu/drm/amd/dal/dc/basics/conversion.h | 49 ++ drivers/gpu/drm/amd/dal/dc/basics/grph_object_id.c | 134 +++ drivers/gpu/drm/amd/dal/dc/basics/logger.c | 954 +++++++++++++++++++++ drivers/gpu/drm/amd/dal/dc/basics/logger.h | 64 ++ .../gpu/drm/amd/dal/dc/basics/register_logger.c | 197 +++++ drivers/gpu/drm/amd/dal/dc/basics/signal_types.c | 116 +++ drivers/gpu/drm/amd/dal/dc/basics/vector.c | 309 +++++++ 11 files changed, 2126 insertions(+) create mode 100644 drivers/gpu/drm/amd/dal/Kconfig create mode 100644 drivers/gpu/drm/amd/dal/Makefile create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/Makefile create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/conversion.c create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/conversion.h create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/grph_object_id.c create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/logger.c create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/logger.h create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/register_logger.c create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/signal_types.c create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/vector.c diff --git a/drivers/gpu/drm/amd/dal/Kconfig b/drivers/gpu/drm/amd/dal/Kconfig new file mode 100644 index 000000000000..2289c0b10dae --- /dev/null +++ b/drivers/gpu/drm/amd/dal/Kconfig @@ -0,0 +1,48 @@ +menu "Display Engine Configuration" + depends on DRM && (DRM_AMDSOC || DRM_AMDGPU) + +config DRM_AMD_DAL + bool "AMD DAL - Enable new display engine + help + Choose this option if you want to use the new display engine + support for AMD SOC. + + Will be deprecated when the DAL component becomes stable and + AMDSOC will fully switch to it. + +config DRM_AMD_DAL_VBIOS_PRESENT + bool "Video Bios available on board" + depends on DRM_AMD_DAL + help + This option is needed to allow a full range of feature + support when working on + x86 platforms and there is a VBIOS + present in the system + +config DRM_AMD_DAL_DCE11_0 + bool "Carrizo family" + depends on DRM_AMD_DAL + help + Choose this option + if you want to have + CZ family + for display engine + +config DRM_AMD_DAL_DCE10_0 + bool "VI family" + depends on DRM_AMD_DAL + help + Choose this option + if you want to have + VI family for display + engine. + +config DEBUG_KERNEL_DAL + bool "Enable kgdb break in DAL" + depends on DRM_AMD_DAL + help + Choose this option + if you want to hit + kdgb_break in assert. + +endmenu diff --git a/drivers/gpu/drm/amd/dal/Makefile b/drivers/gpu/drm/amd/dal/Makefile new file mode 100644 index 000000000000..25ae4646c4d3 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/Makefile @@ -0,0 +1,21 @@ +# +# Makefile for the DAL (Display Abstract Layer), which is a sub-component +# of the AMDGPU drm driver. +# It provides the HW control for display related functionalities. + +AMDDALPATH = $(RELATIVE_AMD_DAL_PATH) + +subdir-ccflags-y += -Werror + +subdir-ccflags-y += -I$(AMDDALPATH)/ -I$(AMDDALPATH)/include + +subdir-ccflags-y += -I$(FULL_AMD_DAL_PATH)/dc/inc/ + +#TODO: remove when Timing Sync feature is complete +subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0 + +DAL_LIBS = amdgpu_dm dc + +AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DAL_PATH)/,$(DAL_LIBS))) + +include $(AMD_DAL) diff --git a/drivers/gpu/drm/amd/dal/dc/basics/Makefile b/drivers/gpu/drm/amd/dal/dc/basics/Makefile new file mode 100644 index 000000000000..6f382812fae3 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/basics/Makefile @@ -0,0 +1,10 @@ +# +# Makefile for the 'utils' sub-component of DAL. +# It provides the general basic services required by other DAL +# subcomponents. + +BASICS = conversion.o grph_object_id.o logger.o register_logger.o signal_types.o vector.o + +AMD_DAL_BASICS = $(addprefix $(AMDDALPATH)/dc/basics/,$(BASICS)) + +AMD_DAL_FILES += $(AMD_DAL_BASICS) diff --git a/drivers/gpu/drm/amd/dal/dc/basics/conversion.c b/drivers/gpu/drm/amd/dal/dc/basics/conversion.c new file mode 100644 index 000000000000..2f1f3d4ff96b --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/basics/conversion.c @@ -0,0 +1,224 @@ +/* + * 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/dal/dc/basics/conversion.h b/drivers/gpu/drm/amd/dal/dc/basics/conversion.h new file mode 100644 index 000000000000..24ff47352688 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/basics/conversion.h @@ -0,0 +1,49 @@ +/* + * 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__ + +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/dal/dc/basics/grph_object_id.c b/drivers/gpu/drm/amd/dal/dc/basics/grph_object_id.c new file mode 100644 index 000000000000..9c80847d03a9 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/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/dal/dc/basics/logger.c b/drivers/gpu/drm/amd/dal/dc/basics/logger.c new file mode 100644 index 000000000000..e7938ec9bb7c --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/basics/logger.c @@ -0,0 +1,954 @@ +/* + * 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 <stdarg.h> +#include "dm_services.h" +#include "include/dal_types.h" +#include "include/logger_interface.h" +#include "logger.h" + +/* TODO: for now - empty, use DRM defines from dal services. + Need to define appropriate levels of prints, and implement + this component +void dal_log(const char *format, ...) +{ +} +*/ + +/* ----------- Logging Major/Minor names ------------ */ + +#define NUM_ELEMENTS(a) (sizeof(a) / sizeof((a)[0])) + +static const struct log_minor_info component_minor_info_tbl[] = { + {LOG_MINOR_COMPONENT_LINK_SERVICE, "LS"}, + {LOG_MINOR_COMPONENT_DAL_INTERFACE, "DalIf"}, + {LOG_MINOR_COMPONENT_HWSS, "HWSS"}, + {LOG_MINOR_COMPONENT_ADAPTER_SERVICE, "AS"}, + {LOG_MINOR_COMPONENT_DISPLAY_SERVICE, "DS"}, + {LOG_MINOR_COMPONENT_TOPOLOGY_MANAGER, "TM"}, + {LOG_MINOR_COMPONENT_ENCODER, "Encoder"}, + {LOG_MINOR_COMPONENT_I2C_AUX, "I2cAux"}, + {LOG_MINOR_COMPONENT_AUDIO, "Audio"}, + {LOG_MINOR_COMPONENT_DISPLAY_CAPABILITY_SERVICE, "Dcs"}, + {LOG_MINOR_COMPONENT_DMCU, "Dmcu"}, + {LOG_MINOR_COMPONENT_GPU, "GPU"}, + {LOG_MINOR_COMPONENT_CONTROLLER, "Cntrlr"}, + {LOG_MINOR_COMPONENT_ISR, "ISR"}, + {LOG_MINOR_COMPONENT_BIOS, "BIOS"}, + {LOG_MINOR_COMPONENT_DC, "DC"}, + {LOG_MINOR_COMPONENT_IRQ_SERVICE, "IRQ SERVICE"}, + +}; + +static const struct log_minor_info hw_trace_minor_info_tbl[] = { + {LOG_MINOR_HW_TRACE_MST, "Mst" }, + {LOG_MINOR_HW_TRACE_TRAVIS, "Travis" }, + {LOG_MINOR_HW_TRACE_HOTPLUG, "Hotplug" }, + {LOG_MINOR_HW_TRACE_LINK_TRAINING, "LinkTraining" }, + {LOG_MINOR_HW_TRACE_SET_MODE, "SetMode" }, + {LOG_MINOR_HW_TRACE_RESUME_S3, "ResumeS3" }, + {LOG_MINOR_HW_TRACE_RESUME_S4, "ResumeS4" }, + {LOG_MINOR_HW_TRACE_BOOTUP, "BootUp" }, + {LOG_MINOR_HW_TRACE_AUDIO, "Audio"}, + {LOG_MINOR_HW_TRACE_HPD_IRQ, "HpdIrq" }, + {LOG_MINOR_HW_TRACE_INTERRUPT, "Interrupt" }, + {LOG_MINOR_HW_TRACE_MPO, "Planes" }, +}; + +static const struct log_minor_info mst_minor_info_tbl[] = { + {LOG_MINOR_MST_IRQ_HPD_RX, "IrqHpdRx"}, + {LOG_MINOR_MST_IRQ_TIMER, "IrqTimer"}, + {LOG_MINOR_MST_NATIVE_AUX, "NativeAux"}, + {LOG_MINOR_MST_SIDEBAND_MSG, "SB"}, + {LOG_MINOR_MST_MSG_TRANSACTION, "MT"}, + {LOG_MINOR_MST_SIDEBAND_MSG_PARSED, "SB Parsed"}, + {LOG_MINOR_MST_MSG_TRANSACTION_PARSED, "MT Parsed"}, + {LOG_MINOR_MST_AUX_MSG_DPCD_ACCESS, "AuxMsgDpcdAccess"}, + {LOG_MINOR_MST_PROGRAMMING, "Programming"}, + {LOG_MINOR_MST_TOPOLOGY_DISCOVERY, "TopologyDiscovery"}, + {LOG_MINOR_MST_CONVERTER_CAPS, "ConverterCaps"}, +}; + +static const struct log_minor_info dcs_minor_info_tbl[] = { + {LOG_MINOR_DCS_EDID_EMULATOR, "EdidEmul"}, + {LOG_MINOR_DCS_DONGLE_DETECTION, "DongleDetect"}, +}; + +static const struct log_minor_info dcp_minor_info_tbl[] = { + { LOG_MINOR_DCP_GAMMA_GRPH, "GammaGrph"}, + { LOG_MINOR_DCP_GAMMA_OVL, "GammaOvl"}, + { LOG_MINOR_DCP_CSC_GRPH, "CscGrph"}, + { LOG_MINOR_DCP_CSC_OVL, "CscOvl"}, + { LOG_MINOR_DCP_SCALER, "Scaler"}, + { LOG_MINOR_DCP_SCALER_TABLES, "ScalerTables"}, +}; + +static const struct log_minor_info bios_minor_info_tbl[] = { + {LOG_MINOR_BIOS_CMD_TABLE, "CmdTbl"}, +}; + +static const struct log_minor_info reg_minor_info_tbl[] = { + {LOG_MINOR_REGISTER_INDEX, "Index"}, +}; + +static const struct log_minor_info info_packet_minor_info_tbl[] = { + {LOG_MINOR_INFO_PACKETS_HDMI, "Hdmi"}, +}; + + +static const struct log_minor_info dsat_minor_info_tbl[] = { + {LOG_MINOR_DSAT_LOGGER, "Logger"}, + {LOG_MINOR_DSAT_EDID_OVERRIDE, "EDID_Override"}, +}; + +static const struct log_minor_info ec_minor_info_tbl[] = { + {LOG_MINOR_EC_PPLIB_NOTIFY, "PPLib_Notify" }, /* PPLib notifies DAL */ + {LOG_MINOR_EC_PPLIB_QUERY, "PPLib_Query" } /* DAL requested info from + PPLib */ +}; + +static const struct log_minor_info bwm_minor_info_tbl[] = { + {LOG_MINOR_BWM_MODE_VALIDATION, "ModeValidation"}, + {LOG_MINOR_BWM_REQUIRED_BANDWIDTH_CALCS, "Req_Bandw_Calcs"} +}; + +static const struct log_minor_info mode_enum_minor_info_tbl[] = { + {LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES, "BestviewCandidates"}, + {LOG_MINOR_MODE_ENUM_VIEW_SOLUTION, "ViewSolution"}, + {LOG_MINOR_MODE_ENUM_TS_LIST_BUILD, "TsListBuild"}, + {LOG_MINOR_MODE_ENUM_TS_LIST, "TsList"}, + {LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST, "MasterViewList"}, + {LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST_UPDATE, "MasterViewListUpdate"}, +}; + +static const struct log_minor_info i2caux_minor_info_tbl[] = { + {LOG_MINOR_I2C_AUX_LOG, "Log"}, + {LOG_MINOR_I2C_AUX_AUX_TIMESTAMP, "Timestamp"}, + {LOG_MINOR_I2C_AUX_CFG, "Config"} +}; + +static const struct log_minor_info line_buffer_minor_info_tbl[] = { + {LOG_MINOR_LINE_BUFFER_POWERGATING, "PowerGating"} +}; + +static const struct log_minor_info hwss_minor_info_tbl[] = { + {LOG_MINOR_HWSS_TAPS_VALIDATION, "HWSS Taps"} +}; + +static const struct log_minor_info optimization_minor_info_tbl[] = { + {LOG_MINOR_OPTMZ_GENERAL, "General Optimizations"}, + {LOG_MINOR_OPTMZ_DO_NOT_TURN_OFF_VCC_DURING_SET_MODE, + "Skip Vcc Off During Set Mode"} +}; + +static const struct log_minor_info perf_measure_minor_info_tbl[] = { + {LOG_MINOR_PERF_MEASURE_GENERAL, "General Performance Measurement"}, + {LOG_MINOR_PERF_MEASURE_HEAP_MEMORY, "Heap Memory Management"} +}; + +static const struct log_minor_info sync_minor_info_tbl[] = { + {LOG_MINOR_SYNC_HW_CLOCK_ADJUST, "Pixel Rate Tune-up"}, + {LOG_MINOR_SYNC_TIMING, "Timing"} +}; + +static const struct log_minor_info backlight_minor_info_tbl[] = { + {LOG_MINOR_BACKLIGHT_BRIGHTESS_CAPS, "Caps"}, + {LOG_MINOR_BACKLIGHT_DMCU_DELTALUT, "DMCU Delta LUT"}, + {LOG_MINOR_BACKLIGHT_DMCU_BUILD_DELTALUT, "Build DMCU Delta LUT"}, + {LOG_MINOR_BACKLIGHT_INTERFACE, "Interface"}, + {LOG_MINOR_BACKLIGHT_LID, "Lid Status"} +}; + + +static const struct log_minor_info override_feature_minor_info_tbl[] = { + {LOG_MINOR_FEATURE_OVERRIDE, "overriden feature"}, +}; + +static const struct log_minor_info detection_minor_info_tbl[] = { + {LOG_MINOR_DETECTION_EDID_PARSER, "EDID Parser"}, + {LOG_MINOR_DETECTION_DP_CAPS, "DP caps"}, +}; + +static const struct log_minor_info tm_minor_info_tbl[] = { + {LOG_MINOR_TM_INFO, "INFO"}, + {LOG_MINOR_TM_IFACE_TRACE, "IFACE_TRACE"}, + {LOG_MINOR_TM_RESOURCES, "RESOURCES"}, + {LOG_MINOR_TM_ENCODER_CTL, "ENCODER_CTL"}, + {LOG_MINOR_TM_ENG_ASN, "ENG_ASN"}, + {LOG_MINOR_TM_CONTROLLER_ASN, "CONTROLLER_ASN"}, + {LOG_MINOR_TM_PWR_GATING, "PWR_GATING"}, + {LOG_MINOR_TM_BUILD_DSP_PATH, "BUILD_PATH"}, + {LOG_MINOR_TM_DISPLAY_DETECT, "DISPLAY_DETECT"}, + {LOG_MINOR_TM_LINK_SRV, "LINK_SRV"}, + {LOG_MINOR_TM_NOT_IMPLEMENTED, "NOT_IMPL"}, + {LOG_MINOR_TM_COFUNC_PATH, "COFUNC_PATH"} +}; + +static const struct log_minor_info ds_minor_info_tbl[] = { + {LOG_MINOR_DS_MODE_SETTING, "Mode_Setting"}, +}; + + +struct log_major_mask_info { + struct log_major_info major_info; + uint32_t default_mask; + const struct log_minor_info *minor_tbl; + uint32_t tbl_element_cnt; +}; + +/* A mask for each Major. + * Use a mask or zero. */ +#define LG_ERR_MSK 0xffffffff +#define LG_WRN_MSK 0xffffffff +#define LG_TM_MSK (1 << LOG_MINOR_TM_INFO) +#define LG_FO_MSK (1 << LOG_MINOR_FEATURE_OVERRIDE) +#define LG_EC_MSK ((1 << LOG_MINOR_EC_PPLIB_NOTIFY) | \ + (1 << LOG_MINOR_EC_PPLIB_QUERY)) +#define LG_DSAT_MSK (1 << LOG_MINOR_DSAT_EDID_OVERRIDE) +#define LG_DT_MSK (1 << LOG_MINOR_DETECTION_EDID_PARSER) + +/* IFT - InterFaceTrace */ +#define LG_IFT_MSK (1 << LOG_MINOR_COMPONENT_DC) + + +#define LG_HW_TR_AUD_MSK (1 << LOG_MINOR_HW_TRACE_AUDIO) +#define LG_HW_TR_INTERRUPT_MSK (1 << LOG_MINOR_HW_TRACE_INTERRUPT) | \ + (1 << LOG_MINOR_HW_TRACE_HPD_IRQ) +#define LG_HW_TR_PLANES_MSK (1 << LOG_MINOR_HW_TRACE_MPO) +#define LG_ALL_MSK 0xffffffff +#define LG_DCP_MSK ~(1 << LOG_MINOR_DCP_SCALER) + +#define LG_SYNC_MSK (1 << LOG_MINOR_SYNC_TIMING) + +#define LG_BWM_MSK (1 << LOG_MINOR_BWM_MODE_VALIDATION) + +static const struct log_major_mask_info log_major_mask_info_tbl[] = { + /* LogMajor major name default MinorTble tblElementCnt */ + {{LOG_MAJOR_ERROR, "Error" }, LG_ALL_MSK, component_minor_info_tbl, NUM_ELEMENTS(component_minor_info_tbl)}, + {{LOG_MAJOR_WARNING, "Warning" }, LG_ALL_MSK, component_minor_info_tbl, NUM_ELEMENTS(component_minor_info_tbl)}, + {{LOG_MAJOR_INTERFACE_TRACE, "IfTrace" }, LG_ALL_MSK, component_minor_info_tbl, NUM_ELEMENTS(component_minor_info_tbl)}, + {{LOG_MAJOR_HW_TRACE, "HwTrace" }, (LG_ALL_MSK & + ~((1 << LOG_MINOR_HW_TRACE_LINK_TRAINING) | + (1 << LOG_MINOR_HW_TRACE_AUDIO))), + hw_trace_minor_info_tbl, NUM_ELEMENTS(hw_trace_minor_info_tbl)}, + {{LOG_MAJOR_MST, "MST" }, LG_ALL_MSK, mst_minor_info_tbl, NUM_ELEMENTS(mst_minor_info_tbl)}, + {{LOG_MAJOR_DCS, "DCS" }, LG_ALL_MSK, dcs_minor_info_tbl, NUM_ELEMENTS(dcs_minor_info_tbl)}, + {{LOG_MAJOR_DCP, "DCP" }, LG_DCP_MSK, dcp_minor_info_tbl, NUM_ELEMENTS(dcp_minor_info_tbl)}, + {{LOG_MAJOR_BIOS, "Bios" }, LG_ALL_MSK, bios_minor_info_tbl, NUM_ELEMENTS(bios_minor_info_tbl)}, + {{LOG_MAJOR_REGISTER, "Register" }, LG_ALL_MSK, reg_minor_info_tbl, NUM_ELEMENTS(reg_minor_info_tbl)}, + {{LOG_MAJOR_INFO_PACKETS, "InfoPacket" }, LG_ALL_MSK, info_packet_minor_info_tbl, NUM_ELEMENTS(info_packet_minor_info_tbl)}, + {{LOG_MAJOR_DSAT, "DSAT" }, LG_ALL_MSK, dsat_minor_info_tbl, NUM_ELEMENTS(dsat_minor_info_tbl)}, + {{LOG_MAJOR_EC, "EC" }, LG_ALL_MSK, ec_minor_info_tbl, NUM_ELEMENTS(ec_minor_info_tbl)}, + {{LOG_MAJOR_BWM, "BWM" }, LG_BWM_MSK, bwm_minor_info_tbl, NUM_ELEMENTS(bwm_minor_info_tbl)}, + {{LOG_MAJOR_MODE_ENUM, "ModeEnum" }, LG_ALL_MSK, mode_enum_minor_info_tbl, NUM_ELEMENTS(mode_enum_minor_info_tbl)}, + {{LOG_MAJOR_I2C_AUX, "I2cAux" }, LG_ALL_MSK, i2caux_minor_info_tbl, NUM_ELEMENTS(i2caux_minor_info_tbl)}, + {{LOG_MAJOR_LINE_BUFFER, "LineBuffer" }, LG_ALL_MSK, line_buffer_minor_info_tbl, NUM_ELEMENTS(line_buffer_minor_info_tbl)}, + {{LOG_MAJOR_HWSS, "HWSS" }, LG_ALL_MSK, hwss_minor_info_tbl, NUM_ELEMENTS(hwss_minor_info_tbl)}, + {{LOG_MAJOR_OPTIMIZATION, "Optimization"}, LG_ALL_MSK, optimization_minor_info_tbl, NUM_ELEMENTS(optimization_minor_info_tbl)}, + {{LOG_MAJOR_PERF_MEASURE, "PerfMeasure" }, LG_ALL_MSK, perf_measure_minor_info_tbl, NUM_ELEMENTS(perf_measure_minor_info_tbl)}, + {{LOG_MAJOR_SYNC, "Sync" }, LG_SYNC_MSK,sync_minor_info_tbl, NUM_ELEMENTS(sync_minor_info_tbl)}, + {{LOG_MAJOR_BACKLIGHT, "Backlight" }, LG_ALL_MSK, backlight_minor_info_tbl, NUM_ELEMENTS(backlight_minor_info_tbl)}, + {{LOG_MAJOR_INTERRUPTS, "Interrupts" }, LG_ALL_MSK, component_minor_info_tbl, NUM_ELEMENTS(component_minor_info_tbl)}, + {{LOG_MAJOR_TM, "TM" }, 0, tm_minor_info_tbl, NUM_ELEMENTS(tm_minor_info_tbl)}, + {{LOG_MAJOR_DISPLAY_SERVICE, "DS" }, LG_ALL_MSK, ds_minor_info_tbl, NUM_ELEMENTS(ds_minor_info_tbl)}, + {{LOG_MAJOR_FEATURE_OVERRIDE, "FeatureOverride" }, LG_ALL_MSK, override_feature_minor_info_tbl, NUM_ELEMENTS(override_feature_minor_info_tbl)}, + {{LOG_MAJOR_DETECTION, "Detection" }, LG_ALL_MSK, detection_minor_info_tbl, NUM_ELEMENTS(detection_minor_info_tbl)}, +}; + +/* ----------- Object init and destruction ----------- */ +static bool construct(struct dc_context *ctx, struct dal_logger *logger) +{ + uint32_t i; + /* malloc buffer and init offsets */ + + logger->log_buffer_size = DAL_LOGGER_BUFFER_MAX_SIZE; + logger->log_buffer = (char *)dm_alloc(ctx, + logger->log_buffer_size * + sizeof(char)); + + if (!logger->log_buffer) + return false; + + /* todo: Fill buffer with \0 if not done by dal_alloc */ + + /* 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; + + /* malloc and init minor mask array */ + logger->log_enable_mask_minors = + (uint32_t *)dm_alloc( + ctx, + NUM_ELEMENTS(log_major_mask_info_tbl) + * sizeof(uint32_t)); + if (!logger->log_enable_mask_minors) + return false; + + + /* Set default values for mask */ + for (i = 0; i < NUM_ELEMENTS(log_major_mask_info_tbl); i++) { + + uint32_t dflt_mask = log_major_mask_info_tbl[i].default_mask; + + logger->log_enable_mask_minors[i] = dflt_mask; + } + + return true; +} + +static void destruct(struct dal_logger *logger) +{ + if (logger->log_buffer) { + dm_free(logger->ctx, logger->log_buffer); + logger->log_buffer = NULL; + } + + if (logger->log_enable_mask_minors) { + dm_free(logger->ctx, logger->log_enable_mask_minors); + logger->log_enable_mask_minors = NULL; + } +} + +struct dal_logger *dal_logger_create(struct dc_context *ctx) +{ + /* malloc struct */ + struct dal_logger *logger = dm_alloc(ctx, sizeof(struct dal_logger)); + + if (!logger) + return NULL; + if (!construct(ctx, logger)) { + dm_free(ctx, 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)->ctx, *logger); + *logger = NULL; + + return 0; +} + +/* ------------------------------------------------------------------------ */ + +static void lock(struct dal_logger *logger) +{ + /* Todo: lock mutex? */ +} + +static void unlock(struct dal_logger *logger) +{ + /* Todo: unlock mutex */ +} + +bool dal_logger_should_log( + struct dal_logger *logger, + enum log_major major, + enum log_minor minor) +{ + if (major < LOG_MAJOR_COUNT) { + + uint32_t minor_mask = logger->log_enable_mask_minors[major]; + + if ((minor_mask & (1 << minor)) != 0) + 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->major) { + case LOG_MAJOR_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' + */ + dm_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; + + dm_memmove(logger->log_buffer + + logger->buffer_write_offset, + entry->buf, space_before_wrap); + dm_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 */ + dm_memmove(logger->log_buffer, entry->buf, size); + logger->buffer_write_offset = size; + logger->buffer_read_offset = 0; + } + + } + + unlock(logger); +} + + +static void log_timestamp(struct log_entry *entry) +{ + dal_logger_append(entry, "00:00:00 "); +} + +static void log_major_minor(struct log_entry *entry) +{ + uint32_t i; + enum log_major major = entry->major; + enum log_minor minor = entry->minor; + + for (i = 0; i < NUM_ELEMENTS(log_major_mask_info_tbl); i++) { + + const struct log_major_mask_info *maj_mask_info = + &log_major_mask_info_tbl[i]; + + if (maj_mask_info->major_info.major == major) { + + dal_logger_append(entry, "[%s_", + maj_mask_info->major_info.major_name); + + if (maj_mask_info->minor_tbl != NULL) { + uint32_t j; + + for (j = 0; j < maj_mask_info->tbl_element_cnt; j++) { + + const struct log_minor_info *min_info = &maj_mask_info->minor_tbl[j]; + + if (min_info->minor == minor) + dal_logger_append(entry, "%s]\t", min_info->minor_name); + } + } + + break; + } + } +} + +static void log_heading(struct log_entry *entry, + enum log_major major, + enum log_minor minor) +{ + log_timestamp(entry); + log_major_minor(entry); +} + + +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 */ + dm_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 dal_logger_write( + struct dal_logger *logger, + enum log_major major, + enum log_minor minor, + const char *msg, + ...) +{ + + if (logger && dal_logger_should_log(logger, major, minor)) { + + uint32_t size; + va_list args; + char buffer[DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE]; + struct log_entry entry; + + va_start(args, msg); + dal_logger_open(logger, &entry, major, minor); + + + size = dm_log_to_buffer( + buffer, DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE, msg, args); + + if (size > 0 && size < + DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE - 1) { + + if (buffer[size] == '\0') + size++; /* Add one for null terminator */ + + /* Concatenate onto end of entry buffer */ + append_entry(&entry, buffer, size); + } else { + append_entry(&entry, + "LOG_ERROR, line too long or null\n", 35); + } + + dal_logger_close(&entry); + va_end(args); + + } +} + + +/* Same as dal_logger_write, except without open() and close(), which must + * be done separately. + */ +void dal_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->major, entry->minor)) { + + uint32_t size; + va_list args; + char buffer[DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE]; + + va_start(args, msg); + + size = dm_log_to_buffer( + buffer, DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE, msg, args); + + if (size < DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE - 1) { + append_entry(entry, buffer, size); + } else { + append_entry(entry, "LOG_ERROR, line too long\n", 27); + } + + va_end(args); + } +} + + +uint32_t dal_logger_read( + struct dal_logger *logger, /* <[in] */ + uint32_t output_buffer_size, /* <[in] */ + char *output_buffer, /* >[out] */ + uint32_t *bytes_read, /* >[out] */ + bool single_line) +{ + uint32_t bytes_remaining = 0; + uint32_t bytes_read_count = 0; + bool keep_reading = true; + + if (!logger || output_buffer == NULL || output_buffer_size == 0) { + BREAK_TO_DEBUGGER(); + *bytes_read = 0; + return 0; + } + + lock(logger); + + /* Read until null terminator (if single_line==true, + * max buffer size, or until we've read everything new + */ + + do { + char cur; + + /* Stop when we've read everything */ + if (logger->buffer_read_offset == + logger->buffer_write_offset) { + + break; + } + + cur = logger->log_buffer[logger->buffer_read_offset]; + logger->buffer_read_offset++; + + /* Wrap read pointer if at end */ + if (logger->buffer_read_offset == logger->log_buffer_size) { + + logger->buffer_read_offset = 0; + logger->read_wrap_count++; + } + + /* Don't send null terminators to buffer */ + if (cur != '\0') { + output_buffer[bytes_read_count] = cur; + bytes_read_count++; + } else if (single_line) { + keep_reading = false; + } + + } while (bytes_read_count <= output_buffer_size && keep_reading); + + /* We assume that reading can never be ahead of writing */ + if (logger->write_wrap_count > logger->read_wrap_count) { + bytes_remaining = logger->log_buffer_size - + logger->buffer_read_offset + + logger->buffer_write_offset; + } else { + bytes_remaining = logger->buffer_write_offset - + logger->buffer_read_offset; + } + + /* reset write/read wrap count to 0 if we've read everything */ + if (bytes_remaining == 0) { + + logger->write_wrap_count = 0; + logger->read_wrap_count = 0; + } + + *bytes_read = bytes_read_count; + unlock(logger); + + return bytes_remaining; +} + +void dal_logger_open( + struct dal_logger *logger, + struct log_entry *entry, /* out */ + enum log_major major, + enum log_minor minor) +{ + if (!entry) { + BREAK_TO_DEBUGGER(); + return; + } + + entry->major = LOG_MAJOR_COUNT; + entry->minor = 0; + entry->logger = logger; + + entry->buf = dm_alloc( + logger->ctx, + 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++; + entry->major = major; + entry->minor = minor; + + log_heading(entry, major, minor); +} + +void dal_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->logger->ctx, entry->buf); + entry->buf = NULL; + entry->buf_offset = 0; + entry->max_buf_bytes = 0; + } +} + +uint32_t dal_logger_get_mask( + struct dal_logger *logger, + enum log_major lvl_major, enum log_minor lvl_minor) +{ + uint32_t log_mask = 0; + + if (logger && lvl_major < LOG_MAJOR_COUNT) + log_mask = logger->log_enable_mask_minors[lvl_major]; + + log_mask &= 1 << lvl_minor; + return log_mask; +} + +uint32_t dal_logger_set_mask( + struct dal_logger *logger, + enum log_major lvl_major, enum log_minor lvl_minor) +{ + + if (logger && lvl_major < LOG_MAJOR_COUNT) { + if (lvl_minor == LOG_MINOR_MASK_ALL) { + logger->log_enable_mask_minors[lvl_major] = 0xFFFFFFFF; + } else { + logger->log_enable_mask_minors[lvl_major] |= + (1 << lvl_minor); + } + return 0; + } + return 1; +} + +uint32_t dal_logger_get_masks( + struct dal_logger *logger, + enum log_major lvl_major) +{ + uint32_t log_mask = 0; + + if (logger && lvl_major < LOG_MAJOR_COUNT) + log_mask = logger->log_enable_mask_minors[lvl_major]; + + return log_mask; +} + +void dal_logger_set_masks( + struct dal_logger *logger, + enum log_major lvl_major, uint32_t log_mask) +{ + if (logger && lvl_major < LOG_MAJOR_COUNT) + logger->log_enable_mask_minors[lvl_major] = log_mask; +} + +uint32_t dal_logger_unset_mask( + struct dal_logger *logger, + enum log_major lvl_major, enum log_minor lvl_minor) +{ + + if (lvl_major < LOG_MAJOR_COUNT) { + if (lvl_minor == LOG_MINOR_MASK_ALL) { + logger->log_enable_mask_minors[lvl_major] = 0; + } else { + logger->log_enable_mask_minors[lvl_major] &= + ~(1 << lvl_minor); + } + return 0; + } + return 1; +} + +uint32_t dal_logger_get_flags( + struct dal_logger *logger) +{ + + return logger->flags.value; +} + +void dal_logger_set_flags( + struct dal_logger *logger, + union logger_flags flags) +{ + + logger->flags = flags; +} + + +uint32_t dal_logger_get_buffer_size(struct dal_logger *logger) +{ + return DAL_LOGGER_BUFFER_MAX_SIZE; +} + +uint32_t dal_logger_set_buffer_size( + struct dal_logger *logger, + uint32_t new_size) +{ + /* ToDo: implement dynamic size */ + + /* return new size */ + return DAL_LOGGER_BUFFER_MAX_SIZE; +} + + +const struct log_major_info *dal_logger_enum_log_major_info( + struct dal_logger *logger, + unsigned int enum_index) +{ + const struct log_major_info *major_info; + + if (enum_index >= NUM_ELEMENTS(log_major_mask_info_tbl)) + return NULL; + + major_info = &log_major_mask_info_tbl[enum_index].major_info; + return major_info; +} + +const struct log_minor_info *dal_logger_enum_log_minor_info( + struct dal_logger *logger, + enum log_major major, + unsigned int enum_index) +{ + const struct log_minor_info *minor_info = NULL; + uint32_t i; + + for (i = 0; i < NUM_ELEMENTS(log_major_mask_info_tbl); i++) { + + const struct log_major_mask_info *maj_mask_info = + &log_major_mask_info_tbl[i]; + + if (maj_mask_info->major_info.major == major) { + + if (maj_mask_info->minor_tbl != NULL) { + uint32_t j; + + for (j = 0; j < maj_mask_info->tbl_element_cnt; j++) { + + minor_info = &maj_mask_info->minor_tbl[j]; + + if (minor_info->minor == enum_index) + return minor_info; + } + } + + break; + } + } + return NULL; + +} + diff --git a/drivers/gpu/drm/amd/dal/dc/basics/logger.h b/drivers/gpu/drm/amd/dal/dc/basics/logger.h new file mode 100644 index 000000000000..fba5ec3264b6 --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/basics/logger.h @@ -0,0 +1,64 @@ +/* + * 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 +#define DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE 256 + + +#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 *log_enable_mask_minors; /*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/dal/dc/basics/register_logger.c b/drivers/gpu/drm/amd/dal/dc/basics/register_logger.c new file mode 100644 index 000000000000..6d32b1bdf35c --- /dev/null +++ b/drivers/gpu/drm/amd/dal/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; + + dm_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()); + + dm_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/dal/dc/basics/signal_types.c b/drivers/gpu/drm/amd/dal/dc/basics/signal_types.c new file mode 100644 index 000000000000..44447e07803a --- /dev/null +++ b/drivers/gpu/drm/amd/dal/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/dal/dc/basics/vector.c b/drivers/gpu/drm/amd/dal/dc/basics/vector.c new file mode 100644 index 000000000000..32ca6b13a3bd --- /dev/null +++ b/drivers/gpu/drm/amd/dal/dc/basics/vector.c @@ -0,0 +1,309 @@ +/* + * 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(ctx, 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(ctx, 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) + dm_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(ctx, 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(ctx, vector); + return NULL; +} + +struct vector *dal_vector_create( + struct dc_context *ctx, + uint32_t capacity, + uint32_t struct_size) +{ + struct vector *vector = dm_alloc(ctx, sizeof(struct vector)); + + if (vector == NULL) + return NULL; + + if (dal_vector_construct(vector, ctx, capacity, struct_size)) + return vector; + + + BREAK_TO_DEBUGGER(); + dm_free(ctx, vector); + return NULL; +} + +void dal_vector_destruct( + struct vector *vector) +{ + if (vector->container != NULL) + dm_free(vector->ctx, 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)->ctx, *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) + dm_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; + } + dm_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) + dm_memmove( + insert_address + vector->struct_size, + insert_address, + vector->struct_size * (vector->count - position)); + + dm_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 */ + dm_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->ctx, 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; +} -- 2.1.4 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel