aboutsummaryrefslogtreecommitdiffstats
path: root/common/recipes-kernel/linux/files/0510-drm-amd-dal-Add-dal-display-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'common/recipes-kernel/linux/files/0510-drm-amd-dal-Add-dal-display-driver.patch')
-rw-r--r--common/recipes-kernel/linux/files/0510-drm-amd-dal-Add-dal-display-driver.patch90113
1 files changed, 90113 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0510-drm-amd-dal-Add-dal-display-driver.patch b/common/recipes-kernel/linux/files/0510-drm-amd-dal-Add-dal-display-driver.patch
new file mode 100644
index 00000000..1606a1aa
--- /dev/null
+++ b/common/recipes-kernel/linux/files/0510-drm-amd-dal-Add-dal-display-driver.patch
@@ -0,0 +1,90113 @@
+From 35eea4f1b20ded08fc0d65891163d03238e3adf6 Mon Sep 17 00:00:00 2001
+From: Harry Wentland <harry.wentland@amd.com>
+Date: Wed, 25 Nov 2015 14:45:50 -0500
+Subject: [PATCH 0510/1110] drm/amd/dal: Add dal display driver
+
+Signed-off-by: Harry Wentland <harry.wentland@amd.com>
+Acked-by: Alex Deucher <alexander.deucher@amd.com>
+---
+ drivers/gpu/drm/amd/dal/Kconfig | 39 +
+ drivers/gpu/drm/amd/dal/Makefile | 19 +
+ .../gpu/drm/amd/dal/dal_power_interface_types.h | 76 +
+ drivers/gpu/drm/amd/dal/dal_services.h | 266 ++
+ drivers/gpu/drm/amd/dal/dal_services_types.h | 62 +
+ drivers/gpu/drm/amd/dal/dc/Makefile | 24 +
+ drivers/gpu/drm/amd/dal/dc/adapter/Makefile | 18 +
+ .../gpu/drm/amd/dal/dc/adapter/adapter_service.c | 2037 +++++++++
+ .../gpu/drm/amd/dal/dc/adapter/adapter_service.h | 67 +
+ .../adapter/dce110/hw_ctx_adapter_service_dce110.c | 303 ++
+ .../adapter/dce110/hw_ctx_adapter_service_dce110.h | 40 +
+ .../amd/dal/dc/adapter/hw_ctx_adapter_service.c | 164 +
+ .../amd/dal/dc/adapter/hw_ctx_adapter_service.h | 86 +
+ .../drm/amd/dal/dc/adapter/wireless_data_source.c | 209 +
+ .../drm/amd/dal/dc/adapter/wireless_data_source.h | 80 +
+ .../gpu/drm/amd/dal/dc/asic_capability/Makefile | 23 +
+ .../amd/dal/dc/asic_capability/asic_capability.c | 178 +
+ .../dc/asic_capability/carrizo_asic_capability.c | 146 +
+ .../dc/asic_capability/carrizo_asic_capability.h | 36 +
+ drivers/gpu/drm/amd/dal/dc/audio/Makefile | 22 +
+ drivers/gpu/drm/amd/dal/dc/audio/audio.h | 195 +
+ drivers/gpu/drm/amd/dal/dc/audio/audio_base.c | 463 ++
+ .../gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c | 452 ++
+ .../gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h | 42 +
+ .../amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c | 1929 ++++++++
+ .../amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h | 47 +
+ drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c | 771 ++++
+ drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h | 285 ++
+ drivers/gpu/drm/amd/dal/dc/basics/Makefile | 10 +
+ drivers/gpu/drm/amd/dal/dc/basics/conversion.c | 223 +
+ drivers/gpu/drm/amd/dal/dc/basics/conversion.h | 49 +
+ drivers/gpu/drm/amd/dal/dc/basics/fixpt31_32.c | 692 +++
+ drivers/gpu/drm/amd/dal/dc/basics/fixpt32_32.c | 223 +
+ drivers/gpu/drm/amd/dal/dc/basics/grph_object_id.c | 135 +
+ drivers/gpu/drm/amd/dal/dc/basics/logger.c | 947 ++++
+ 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 ++
+ drivers/gpu/drm/amd/dal/dc/bios/Makefile | 27 +
+ drivers/gpu/drm/amd/dal/dc/bios/bios_parser.c | 4758 ++++++++++++++++++++
+ drivers/gpu/drm/amd/dal/dc/bios/bios_parser.h | 78 +
+ .../gpu/drm/amd/dal/dc/bios/bios_parser_helper.c | 193 +
+ .../gpu/drm/amd/dal/dc/bios/bios_parser_helper.h | 108 +
+ drivers/gpu/drm/amd/dal/dc/bios/command_table.c | 2616 +++++++++++
+ drivers/gpu/drm/amd/dal/dc/bios/command_table.h | 117 +
+ .../gpu/drm/amd/dal/dc/bios/command_table_helper.c | 315 ++
+ .../gpu/drm/amd/dal/dc/bios/command_table_helper.h | 87 +
+ .../dal/dc/bios/dce110/bios_parser_helper_dce110.c | 484 ++
+ .../dal/dc/bios/dce110/bios_parser_helper_dce110.h | 34 +
+ .../dc/bios/dce110/command_table_helper_dce110.c | 369 ++
+ .../dc/bios/dce110/command_table_helper_dce110.h | 34 +
+ drivers/gpu/drm/amd/dal/dc/calcs/Makefile | 10 +
+ drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c | 3478 ++++++++++++++
+ drivers/gpu/drm/amd/dal/dc/calcs/bw_fixed.c | 278 ++
+ drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.c | 1992 ++++++++
+ drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.h | 74 +
+ drivers/gpu/drm/amd/dal/dc/connector/Makefile | 10 +
+ drivers/gpu/drm/amd/dal/dc/connector/connector.h | 39 +
+ .../gpu/drm/amd/dal/dc/connector/connector_base.c | 421 ++
+ .../drm/amd/dal/dc/connector/connector_signals.c | 204 +
+ drivers/gpu/drm/amd/dal/dc/core/dc.c | 849 ++++
+ drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c | 49 +
+ drivers/gpu/drm/amd/dal/dc/core/dc_link.c | 1081 +++++
+ drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c | 1689 +++++++
+ drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c | 188 +
+ drivers/gpu/drm/amd/dal/dc/core/dc_resource.c | 378 ++
+ drivers/gpu/drm/amd/dal/dc/core/dc_sink.c | 118 +
+ drivers/gpu/drm/amd/dal/dc/core/dc_stream.c | 172 +
+ drivers/gpu/drm/amd/dal/dc/core/dc_surface.c | 124 +
+ drivers/gpu/drm/amd/dal/dc/core/dc_target.c | 473 ++
+ drivers/gpu/drm/amd/dal/dc/dc.h | 440 ++
+ drivers/gpu/drm/amd/dal/dc/dc_helpers.h | 75 +
+ drivers/gpu/drm/amd/dal/dc/dc_services.h | 174 +
+ drivers/gpu/drm/amd/dal/dc/dc_temp.h | 508 +++
+ drivers/gpu/drm/amd/dal/dc/dc_types.h | 677 +++
+ drivers/gpu/drm/amd/dal/dc/dce110/Makefile | 33 +
+ .../gpu/drm/amd/dal/dc/dce110/dce110_compressor.c | 886 ++++
+ .../gpu/drm/amd/dal/dc/dce110/dce110_compressor.h | 84 +
+ .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.c | 1825 ++++++++
+ .../drm/amd/dal/dc/dce110/dce110_hw_sequencer.h | 36 +
+ drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c | 85 +
+ drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h | 90 +
+ .../gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c | 256 ++
+ .../gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c | 877 ++++
+ .../drm/amd/dal/dc/dce110/dce110_link_encoder.c | 2049 +++++++++
+ .../drm/amd/dal/dc/dce110/dce110_link_encoder.h | 91 +
+ .../gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c | 969 ++++
+ .../gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h | 88 +
+ drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c | 296 ++
+ drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h | 140 +
+ drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c | 904 ++++
+ .../drm/amd/dal/dc/dce110/dce110_opp_formatter.c | 610 +++
+ .../gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c | 2473 ++++++++++
+ .../gpu/drm/amd/dal/dc/dce110/dce110_resource.c | 1276 ++++++
+ .../gpu/drm/amd/dal/dc/dce110/dce110_resource.h | 55 +
+ .../drm/amd/dal/dc/dce110/dce110_stream_encoder.c | 1168 +++++
+ .../drm/amd/dal/dc/dce110/dce110_stream_encoder.h | 64 +
+ .../amd/dal/dc/dce110/dce110_timing_generator.c | 1878 ++++++++
+ .../amd/dal/dc/dce110/dce110_timing_generator.h | 178 +
+ .../gpu/drm/amd/dal/dc/dce110/dce110_transform.c | 116 +
+ .../gpu/drm/amd/dal/dc/dce110/dce110_transform.h | 91 +
+ .../amd/dal/dc/dce110/dce110_transform_bit_depth.c | 840 ++++
+ .../amd/dal/dc/dce110/dce110_transform_bit_depth.h | 51 +
+ .../drm/amd/dal/dc/dce110/dce110_transform_gamut.c | 297 ++
+ .../drm/amd/dal/dc/dce110/dce110_transform_scl.c | 818 ++++
+ .../drm/amd/dal/dc/dce110/dce110_transform_sclv.c | 531 +++
+ drivers/gpu/drm/amd/dal/dc/dcs/Makefile | 10 +
+ drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c | 159 +
+ drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h | 60 +
+ drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c | 1034 +++++
+ drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h | 38 +
+ drivers/gpu/drm/amd/dal/dc/gpio/Makefile | 24 +
+ .../gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.c | 883 ++++
+ .../gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.h | 46 +
+ .../drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.c | 84 +
+ .../drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.h | 32 +
+ .../gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.c | 367 ++
+ .../gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.h | 47 +
+ .../amd/dal/dc/gpio/dce110/hw_translate_dce110.c | 440 ++
+ .../amd/dal/dc/gpio/dce110/hw_translate_dce110.h | 34 +
+ drivers/gpu/drm/amd/dal/dc/gpio/ddc.c | 290 ++
+ drivers/gpu/drm/amd/dal/dc/gpio/ddc.h | 45 +
+ drivers/gpu/drm/amd/dal/dc/gpio/dvo.c | 138 +
+ drivers/gpu/drm/amd/dal/dc/gpio/dvo.h | 42 +
+ drivers/gpu/drm/amd/dal/dc/gpio/gpio.h | 48 +
+ drivers/gpu/drm/amd/dal/dc/gpio/gpio_base.c | 279 ++
+ drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.c | 470 ++
+ drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.h | 57 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.c | 105 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.h | 60 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.c | 318 ++
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.h | 89 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c | 80 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.h | 74 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.c | 408 ++
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.h | 129 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.c | 93 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.h | 47 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.c | 86 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.h | 79 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.c | 88 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.h | 45 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c | 67 +
+ drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.h | 49 +
+ drivers/gpu/drm/amd/dal/dc/gpio/irq.c | 181 +
+ drivers/gpu/drm/amd/dal/dc/gpio/irq.h | 42 +
+ drivers/gpu/drm/amd/dal/dc/gpu/Makefile | 26 +
+ .../gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.c | 407 ++
+ .../gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.h | 79 +
+ drivers/gpu/drm/amd/dal/dc/gpu/clock_source.c | 649 +++
+ drivers/gpu/drm/amd/dal/dc/gpu/clock_source.h | 136 +
+ .../gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c | 92 +
+ .../gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h | 63 +
+ .../amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c | 90 +
+ .../amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h | 33 +
+ .../amd/dal/dc/gpu/dce110/display_clock_dce110.c | 958 ++++
+ .../amd/dal/dc/gpu/dce110/display_clock_dce110.h | 53 +
+ .../dal/dc/gpu/dce110/ext_clock_source_dce110.c | 383 ++
+ .../dal/dc/gpu/dce110/ext_clock_source_dce110.h | 38 +
+ .../dal/dc/gpu/dce110/pll_clock_source_dce110.c | 718 +++
+ .../dal/dc/gpu/dce110/pll_clock_source_dce110.h | 55 +
+ .../dal/dc/gpu/dce110/vce_clock_source_dce110.c | 193 +
+ .../dal/dc/gpu/dce110/vce_clock_source_dce110.h | 32 +
+ drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c | 204 +
+ drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h | 82 +
+ drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c | 127 +
+ drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h | 63 +
+ drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.c | 119 +
+ drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.h | 47 +
+ drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.c | 141 +
+ drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.h | 52 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/Makefile | 23 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.c | 568 +++
+ drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.h | 119 +
+ .../amd/dal/dc/i2caux/dce110/aux_engine_dce110.c | 789 ++++
+ .../amd/dal/dc/i2caux/dce110/aux_engine_dce110.h | 56 +
+ .../i2caux/dce110/i2c_generic_hw_engine_dce110.h | 25 +
+ .../dal/dc/i2caux/dce110/i2c_hw_engine_dce110.c | 954 ++++
+ .../dal/dc/i2caux/dce110/i2c_hw_engine_dce110.h | 58 +
+ .../dal/dc/i2caux/dce110/i2c_sw_engine_dce110.c | 172 +
+ .../dal/dc/i2caux/dce110/i2c_sw_engine_dce110.h | 43 +
+ .../drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.c | 260 ++
+ .../drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.h | 39 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/engine.h | 129 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/engine_base.c | 68 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.c | 122 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.h | 113 +
+ .../drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.c | 287 ++
+ .../drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.h | 77 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.c | 247 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.h | 80 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.c | 615 +++
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.h | 81 +
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c | 519 +++
+ drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.h | 123 +
+ drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h | 463 ++
+ drivers/gpu/drm/amd/dal/dc/inc/bw_fixed.h | 60 +
+ drivers/gpu/drm/amd/dal/dc/inc/compressor.h | 140 +
+ drivers/gpu/drm/amd/dal/dc/inc/core_dc.h | 39 +
+ drivers/gpu/drm/amd/dal/dc/inc/core_status.h | 46 +
+ drivers/gpu/drm/amd/dal/dc/inc/core_types.h | 308 ++
+ drivers/gpu/drm/amd/dal/dc/inc/dc_link_dp.h | 51 +
+ drivers/gpu/drm/amd/dal/dc/inc/hw_sequencer.h | 170 +
+ drivers/gpu/drm/amd/dal/dc/inc/ipp.h | 66 +
+ drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h | 67 +
+ drivers/gpu/drm/amd/dal/dc/inc/mem_input.h | 55 +
+ drivers/gpu/drm/amd/dal/dc/inc/opp.h | 206 +
+ drivers/gpu/drm/amd/dal/dc/inc/resource.h | 61 +
+ drivers/gpu/drm/amd/dal/dc/inc/transform.h | 81 +
+ drivers/gpu/drm/amd/dal/dc/irq/Makefile | 21 +
+ .../drm/amd/dal/dc/irq/dce110/irq_service_dce110.c | 389 ++
+ .../drm/amd/dal/dc/irq/dce110/irq_service_dce110.h | 34 +
+ drivers/gpu/drm/amd/dal/dc/irq/irq_service.c | 173 +
+ drivers/gpu/drm/amd/dal/dc/irq/irq_service.h | 85 +
+ drivers/gpu/drm/amd/dal/dc/irq_types.h | 199 +
+ .../amd/dal/include/adapter_service_interface.h | 628 +++
+ .../drm/amd/dal/include/adapter_service_types.h | 70 +
+ .../gpu/drm/amd/dal/include/adjustment_interface.h | 230 +
+ drivers/gpu/drm/amd/dal/include/adjustment_types.h | 420 ++
+ .../amd/dal/include/asic_capability_interface.h | 58 +
+ .../drm/amd/dal/include/asic_capability_types.h | 134 +
+ drivers/gpu/drm/amd/dal/include/audio_interface.h | 184 +
+ drivers/gpu/drm/amd/dal/include/audio_types.h | 275 ++
+ .../drm/amd/dal/include/bios_parser_interface.h | 294 ++
+ .../gpu/drm/amd/dal/include/bios_parser_types.h | 305 ++
+ drivers/gpu/drm/amd/dal/include/bit_set.h | 61 +
+ .../drm/amd/dal/include/clock_source_interface.h | 89 +
+ .../gpu/drm/amd/dal/include/clock_source_types.h | 118 +
+ .../gpu/drm/amd/dal/include/connector_interface.h | 82 +
+ drivers/gpu/drm/amd/dal/include/dal_asic_id.h | 106 +
+ .../gpu/drm/amd/dal/include/dal_register_logger.h | 43 +
+ drivers/gpu/drm/amd/dal/include/dal_types.h | 292 ++
+ .../amd/dal/include/dc_clock_generator_interface.h | 77 +
+ drivers/gpu/drm/amd/dal/include/dcs_interface.h | 351 ++
+ drivers/gpu/drm/amd/dal/include/dcs_types.h | 742 +++
+ drivers/gpu/drm/amd/dal/include/ddc_interface.h | 74 +
+ .../drm/amd/dal/include/ddc_service_interface.h | 100 +
+ .../gpu/drm/amd/dal/include/ddc_service_types.h | 220 +
+ .../amd/dal/include/default_mode_list_interface.h | 37 +
+ .../drm/amd/dal/include/display_clock_interface.h | 189 +
+ .../drm/amd/dal/include/display_path_interface.h | 436 ++
+ .../gpu/drm/amd/dal/include/display_path_types.h | 132 +
+ .../amd/dal/include/display_service_interface.h | 165 +
+ .../drm/amd/dal/include/display_service_types.h | 167 +
+ drivers/gpu/drm/amd/dal/include/dmcu_interface.h | 87 +
+ drivers/gpu/drm/amd/dal/include/dmcu_types.h | 199 +
+ .../dal/include/dpcd_access_service_interface.h | 65 +
+ drivers/gpu/drm/amd/dal/include/dpcd_defs.h | 869 ++++
+ drivers/gpu/drm/amd/dal/include/dvo_interface.h | 48 +
+ .../gpu/drm/amd/dal/include/encoder_interface.h | 278 ++
+ drivers/gpu/drm/amd/dal/include/encoder_types.h | 216 +
+ drivers/gpu/drm/amd/dal/include/fixed31_32.h | 389 ++
+ drivers/gpu/drm/amd/dal/include/fixed32_32.h | 80 +
+ drivers/gpu/drm/amd/dal/include/gpio_interface.h | 93 +
+ .../drm/amd/dal/include/gpio_service_interface.h | 94 +
+ drivers/gpu/drm/amd/dal/include/gpio_types.h | 393 ++
+ drivers/gpu/drm/amd/dal/include/gpu_clock_info.h | 43 +
+ drivers/gpu/drm/amd/dal/include/gpu_interface.h | 91 +
+ drivers/gpu/drm/amd/dal/include/grph_csc_types.h | 98 +
+ .../drm/amd/dal/include/grph_object_ctrl_defs.h | 598 +++
+ drivers/gpu/drm/amd/dal/include/grph_object_defs.h | 328 ++
+ drivers/gpu/drm/amd/dal/include/grph_object_id.h | 285 ++
+ .../gpu/drm/amd/dal/include/hw_adjustment_set.h | 50 +
+ .../gpu/drm/amd/dal/include/hw_adjustment_types.h | 205 +
+ .../amd/dal/include/hw_path_mode_set_interface.h | 48 +
+ .../drm/amd/dal/include/hw_sequencer_interface.h | 388 ++
+ .../gpu/drm/amd/dal/include/hw_sequencer_types.h | 305 ++
+ drivers/gpu/drm/amd/dal/include/i2caux_interface.h | 127 +
+ drivers/gpu/drm/amd/dal/include/irq_interface.h | 53 +
+ .../drm/amd/dal/include/irq_service_interface.h | 55 +
+ drivers/gpu/drm/amd/dal/include/isr_config_types.h | 157 +
+ .../gpu/drm/amd/dal/include/link_encoder_types.h | 32 +
+ .../drm/amd/dal/include/link_service_interface.h | 202 +
+ .../gpu/drm/amd/dal/include/link_service_types.h | 428 ++
+ drivers/gpu/drm/amd/dal/include/logger_interface.h | 153 +
+ drivers/gpu/drm/amd/dal/include/logger_types.h | 356 ++
+ .../gpu/drm/amd/dal/include/mode_manager_types.h | 71 +
+ .../gpu/drm/amd/dal/include/mode_query_interface.h | 93 +
+ .../amd/dal/include/mode_timing_list_interface.h | 51 +
+ .../gpu/drm/amd/dal/include/overlay_interface.h | 137 +
+ drivers/gpu/drm/amd/dal/include/overlay_types.h | 164 +
+ .../drm/amd/dal/include/path_mode_set_interface.h | 107 +
+ drivers/gpu/drm/amd/dal/include/plane_types.h | 309 ++
+ drivers/gpu/drm/amd/dal/include/scaler_types.h | 196 +
+ .../amd/dal/include/set_mode_params_interface.h | 101 +
+ drivers/gpu/drm/amd/dal/include/set_mode_types.h | 285 ++
+ drivers/gpu/drm/amd/dal/include/signal_types.h | 58 +
+ .../gpu/drm/amd/dal/include/stream_encoder_types.h | 16 +
+ .../drm/amd/dal/include/timing_generator_types.h | 150 +
+ .../amd/dal/include/timing_list_query_interface.h | 69 +
+ drivers/gpu/drm/amd/dal/include/vector.h | 150 +
+ drivers/gpu/drm/amd/dal/include/video_csc_types.h | 135 +
+ .../gpu/drm/amd/dal/include/video_gamma_types.h | 56 +
+ 294 files changed, 87748 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/dal_power_interface_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dal_services.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dal_services_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/dce110/hw_ctx_adapter_service_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/dce110/hw_ctx_adapter_service_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/hw_ctx_adapter_service.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/hw_ctx_adapter_service.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/wireless_data_source.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/adapter/wireless_data_source.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/carrizo_asic_capability.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/asic_capability/carrizo_asic_capability.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/audio.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h
+ 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/fixpt31_32.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/basics/fixpt32_32.c
+ 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
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/bios_parser.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/bios_parser.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/command_table.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/command_table.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce110/bios_parser_helper_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce110/bios_parser_helper_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce110/command_table_helper_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/bios/dce110/command_table_helper_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/calcs/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/calcs/bw_fixed.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/connector/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/connector/connector.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/connector/connector_base.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/connector/connector_signals.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_link.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_sink.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_stream.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_surface.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/core/dc_target.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dc.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dc_helpers.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dc_services.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dc_temp.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dc_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_compressor.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_compressor.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_formatter.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_bit_depth.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_bit_depth.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_gamut.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_scl.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_sclv.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_translate_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_translate_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/ddc.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/ddc.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dvo.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/dvo.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/gpio.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/gpio_base.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/irq.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpio/irq.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/clock_source.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/clock_source.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/ext_clock_source_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/ext_clock_source_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/pll_clock_source_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/pll_clock_source_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/vce_clock_source_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/dce110/vce_clock_source_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/aux_engine_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/aux_engine_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_generic_hw_engine_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_hw_engine_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_hw_engine_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_sw_engine_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_sw_engine_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/engine.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/engine_base.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/bw_fixed.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/compressor.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/core_dc.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/core_status.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/core_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/dc_link_dp.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/hw_sequencer.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/ipp.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/mem_input.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/opp.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/resource.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/inc/transform.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/irq/Makefile
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/irq/dce110/irq_service_dce110.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/irq/dce110/irq_service_dce110.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/irq/irq_service.h
+ create mode 100644 drivers/gpu/drm/amd/dal/dc/irq_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/adapter_service_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/adapter_service_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/adjustment_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/adjustment_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/asic_capability_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/asic_capability_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/audio_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/audio_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/bios_parser_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/bios_parser_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/bit_set.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/clock_source_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/clock_source_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/connector_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dal_asic_id.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dal_register_logger.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dal_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dc_clock_generator_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dcs_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dcs_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/ddc_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/ddc_service_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/ddc_service_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/default_mode_list_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/display_clock_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/display_path_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/display_path_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/display_service_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/display_service_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dmcu_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dmcu_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dpcd_access_service_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dpcd_defs.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/dvo_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/encoder_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/encoder_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/fixed31_32.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/fixed32_32.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/gpio_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/gpio_service_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/gpio_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/gpu_clock_info.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/gpu_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/grph_csc_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/grph_object_ctrl_defs.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/grph_object_defs.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/grph_object_id.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/hw_adjustment_set.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/hw_adjustment_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/hw_path_mode_set_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/hw_sequencer_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/hw_sequencer_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/i2caux_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/irq_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/irq_service_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/isr_config_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/link_encoder_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/link_service_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/link_service_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/logger_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/logger_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/mode_manager_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/mode_query_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/mode_timing_list_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/overlay_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/overlay_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/path_mode_set_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/plane_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/scaler_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/set_mode_params_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/set_mode_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/signal_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/stream_encoder_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/timing_generator_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/timing_list_query_interface.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/vector.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/video_csc_types.h
+ create mode 100644 drivers/gpu/drm/amd/dal/include/video_gamma_types.h
+
+diff --git a/drivers/gpu/drm/amd/dal/Kconfig b/drivers/gpu/drm/amd/dal/Kconfig
+new file mode 100644
+index 0000000..14df02e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/Kconfig
+@@ -0,0 +1,39 @@
++menu "Display Engine Configuration"
++ depends on DRM && (DRM_AMDSOC || DRM_AMDGPU)
++
++config DRM_AMD_DAL
++ bool "AMD DAL - Enable new display engine (will be deprecated when the development is done)"
++ 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 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 0000000..bdf5d18
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/Makefile
+@@ -0,0 +1,19 @@
++#
++# 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 += -I$(AMDDALPATH)/ -I$(AMDDALPATH)/include -DDAL_CZ_BRINGUP
++
++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/dal_power_interface_types.h b/drivers/gpu/drm/amd/dal/dal_power_interface_types.h
+new file mode 100644
+index 0000000..82e8ca2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dal_power_interface_types.h
+@@ -0,0 +1,76 @@
++/*
++ * Copyright 2015 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_POWER_INTERFACE_TYPES_H__
++#define __DAL_POWER_INTERFACE_TYPES_H__
++
++enum dal_to_power_clocks_state {
++ PP_CLOCKS_STATE_INVALID,
++ PP_CLOCKS_STATE_ULTRA_LOW,
++ PP_CLOCKS_STATE_LOW,
++ PP_CLOCKS_STATE_NOMINAL,
++ PP_CLOCKS_STATE_PERFORMANCE
++};
++
++/* clocks in khz */
++struct dal_to_power_info {
++ enum dal_to_power_clocks_state required_clock;
++ uint32_t min_sclk;
++ uint32_t min_mclk;
++ uint32_t min_deep_sleep_sclk;
++};
++
++/* clocks in khz */
++struct power_to_dal_info {
++ uint32_t min_sclk;
++ uint32_t max_sclk;
++ uint32_t min_mclk;
++ uint32_t max_mclk;
++};
++
++/* clocks in khz */
++struct dal_system_clock_range {
++ uint32_t min_sclk;
++ uint32_t max_sclk;
++
++ uint32_t min_mclk;
++ uint32_t max_mclk;
++
++ uint32_t min_dclk;
++ uint32_t max_dclk;
++
++ /* Wireless Display */
++ uint32_t min_eclk;
++ uint32_t max_eclk;
++};
++
++/* clocks in khz */
++struct dal_to_power_dclk {
++ uint32_t optimal; /* input: best optimizes for stutter efficiency */
++ uint32_t minimal; /* input: the lowest clk that DAL can support */
++ uint32_t established; /* output: the actually set one */
++};
++
++#endif /* __DAL_POWER_INTERFACE_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dal_services.h b/drivers/gpu/drm/amd/dal/dal_services.h
+new file mode 100644
+index 0000000..398e4e5
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dal_services.h
+@@ -0,0 +1,266 @@
++/*
++ * 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_SERVICES_H__
++#define __DAL_SERVICES_H__
++
++/* DC headers*/
++#include "dc/dc_services.h"
++
++#include "dal_power_interface_types.h"
++
++#include "irq_types.h"
++#include "include/dal_types.h"
++
++/* TODO: investigate if it can be removed. */
++/* Undefine DEPRECATED because it conflicts with printk.h */
++#undef DEPRECATED
++
++/*
++ *
++ * interrupt services to register and unregister handlers
++ *
++ */
++
++/* the timer "interrupt" current implementation supports only
++'one-shot' type, and LOW level (asynchronous) context */
++void dal_register_timer_interrupt(
++ struct dc_context *ctx,
++ struct dc_timer_interrupt_params *int_params,
++ interrupt_handler ih,
++ void *handler_args);
++
++/*
++ *
++ * kernel memory manipulation
++ *
++ */
++
++/* Reallocate memory. The contents will remain unchanged.*/
++void *dc_service_realloc(struct dc_context *ctx, const void *ptr, uint32_t size);
++
++void dc_service_memmove(void *dst, const void *src, uint32_t size);
++
++void dc_service_memset(void *p, int32_t c, uint32_t count);
++
++int32_t dal_memcmp(const void *p1, const void *p2, uint32_t count);
++
++int32_t dal_strncmp(const int8_t *p1, const int8_t *p2, uint32_t count);
++
++/*
++ *
++ * GPU registers access
++ *
++ */
++static inline uint32_t dal_read_reg(
++ const struct dc_context *ctx,
++ uint32_t address)
++{
++ uint32_t value = cgs_read_register(ctx->cgs_device, address);
++
++#if defined(__DAL_REGISTER_LOGGER__)
++ if (true == dal_reg_logger_should_dump_register()) {
++ dal_reg_logger_rw_count_increment();
++ DRM_INFO("%s 0x%x 0x%x\n", __func__, address, value);
++ }
++#endif
++ return value;
++}
++
++static inline uint32_t get_reg_field_value_ex(
++ uint32_t reg_value,
++ uint32_t mask,
++ uint8_t shift)
++{
++ return (mask & reg_value) >> shift;
++}
++
++#define get_reg_field_value(reg_value, reg_name, reg_field)\
++ get_reg_field_value_ex(\
++ (reg_value),\
++ reg_name ## __ ## reg_field ## _MASK,\
++ reg_name ## __ ## reg_field ## __SHIFT)
++
++static inline uint32_t set_reg_field_value_ex(
++ uint32_t reg_value,
++ uint32_t value,
++ uint32_t mask,
++ uint8_t shift)
++{
++ return (reg_value & ~mask) | (mask & (value << shift));
++}
++
++#define set_reg_field_value(reg_value, value, reg_name, reg_field)\
++ (reg_value) = set_reg_field_value_ex(\
++ (reg_value),\
++ (value),\
++ reg_name ## __ ## reg_field ## _MASK,\
++ reg_name ## __ ## reg_field ## __SHIFT)
++
++static inline void dal_write_reg(
++ const struct dc_context *ctx,
++ uint32_t address,
++ uint32_t value)
++{
++#if defined(__DAL_REGISTER_LOGGER__)
++ if (true == dal_reg_logger_should_dump_register()) {
++ dal_reg_logger_rw_count_increment();
++ DRM_INFO("%s 0x%x 0x%x\n", __func__, address, value);
++ }
++#endif
++ cgs_write_register(ctx->cgs_device, address, value);
++}
++
++static inline uint32_t dal_read_index_reg(
++ const struct dc_context *ctx,
++ enum cgs_ind_reg addr_space,
++ uint32_t index)
++{
++ return cgs_read_ind_register(ctx->cgs_device,addr_space,index);
++}
++
++static inline void dal_write_index_reg(
++ const struct dc_context *ctx,
++ enum cgs_ind_reg addr_space,
++ uint32_t index,
++ uint32_t value)
++{
++ cgs_write_ind_register(ctx->cgs_device,addr_space,index,value);
++}
++
++enum platform_method {
++ PM_GET_AVAILABLE_METHODS = 1 << 0,
++ PM_GET_LID_STATE = 1 << 1,
++ PM_GET_EXTENDED_BRIGHNESS_CAPS = 1 << 2
++};
++
++struct platform_info_params {
++ enum platform_method method;
++ void *data;
++};
++
++struct platform_info_brightness_caps {
++ uint8_t ac_level_percentage;
++ uint8_t dc_level_percentage;
++};
++
++struct platform_info_ext_brightness_caps {
++ struct platform_info_brightness_caps basic_caps;
++ struct data_point {
++ uint8_t luminance;
++ uint8_t signal_level;
++ } data_points[99];
++
++ uint8_t data_points_num;
++ uint8_t min_input_signal;
++ uint8_t max_input_signal;
++};
++
++bool dal_get_platform_info(
++ struct dc_context *ctx,
++ struct platform_info_params *params);
++
++
++static inline uint32_t dal_bios_cmd_table_para_revision(
++ struct dc_context *ctx,
++ uint32_t index)
++{
++ uint8_t frev;
++ uint8_t crev;
++
++ if (cgs_atom_get_cmd_table_revs(
++ ctx->cgs_device,
++ index,
++ &frev,
++ &crev) != 0)
++ return 0;
++
++ return crev;
++}
++
++/* Calls to notification */
++
++/* Notify display manager for hotplug event */
++void dal_notify_hotplug(
++ struct dc_context *ctx,
++ uint32_t display_index,
++ bool is_connected);
++
++
++void dal_notify_setmode_complete(
++ struct dc_context *ctx,
++ uint32_t h_total,
++ uint32_t v_total,
++ uint32_t h_active,
++ uint32_t v_active,
++ uint32_t pix_clk_in_khz);
++
++/* End of notification calls */
++
++/*
++ *
++ * Delay functions.
++ *
++ *
++ */
++
++/* Following the guidance:
++ * https://www.kernel.org/doc/Documentation/timers/timers-howto.txt
++ *
++ * This is a busy wait for nano seconds and should be used only for
++ * extremely short ranges
++ */
++void dal_delay_in_nanoseconds(uint32_t nanoseconds);
++
++
++/*
++ *
++ * atombios services
++ *
++ */
++
++bool dal_exec_bios_cmd_table(
++ struct dc_context *ctx,
++ uint32_t index,
++ void *params);
++
++/*
++ *
++ * print-out services
++ *
++ */
++#define dal_log_to_buffer(buffer, size, fmt, args)\
++ vsnprintf(buffer, size, fmt, args)
++
++long dal_get_pid(void);
++long dal_get_tgid(void);
++
++/*
++ *
++ * general debug capabilities
++ *
++ */
++
++#endif /* __DAL_SERVICES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dal_services_types.h b/drivers/gpu/drm/amd/dal/dal_services_types.h
+new file mode 100644
+index 0000000..89c73c6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dal_services_types.h
+@@ -0,0 +1,62 @@
++/*
++ * 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_SERVICES_TYPES_H__
++#define __DAL_SERVICES_TYPES_H__
++
++#define INVALID_DISPLAY_INDEX 0xffffffff
++
++#if defined __KERNEL__
++
++#include <asm/byteorder.h>
++#include <linux/types.h>
++#include <drm/drmP.h>
++
++#include "cgs_linux.h"
++
++#if defined(__BIG_ENDIAN) && !defined(BIGENDIAN_CPU)
++#define BIGENDIAN_CPU
++#elif defined(__LITTLE_ENDIAN) && !defined(LITTLEENDIAN_CPU)
++#define LITTLEENDIAN_CPU
++#endif
++
++#undef READ
++#undef WRITE
++#undef FRAME_SIZE
++
++#define dal_output_to_console(fmt, ...) DRM_INFO(fmt, ##__VA_ARGS__)
++
++#define dal_error(fmt, ...) DRM_ERROR(fmt, ##__VA_ARGS__)
++
++#define dal_debug(fmt, ...) DRM_DEBUG_KMS(fmt, ##__VA_ARGS__)
++
++#define dal_vlog(fmt, args) vprintk(fmt, args)
++
++#define dal_min(x, y) min(x, y)
++#define dal_max(x, y) max(x, y)
++
++#endif
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/Makefile b/drivers/gpu/drm/amd/dal/dc/Makefile
+new file mode 100644
+index 0000000..6926356
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/Makefile
+@@ -0,0 +1,24 @@
++#
++# Makefile for Display Core (dc) component.
++#
++
++DC_LIBS = adapter asic_capability audio basics bios calcs connector \
++dcs gpio gpu i2caux irq
++
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++DC_LIBS += dce110
++endif
++
++AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DAL_PATH)/dc/,$(DC_LIBS)))
++
++include $(AMD_DC)
++
++DISPLAY_CORE = dc.o dc_link.o dc_resource.o dc_target.o dc_sink.o dc_stream.o \
++dc_hw_sequencer.o dc_surface.o dc_link_hwss.o dc_link_dp.o
++
++AMD_DISPLAY_CORE = $(addprefix $(AMDDALPATH)/dc/core/,$(DISPLAY_CORE))
++
++AMD_DAL_FILES += $(AMD_DISPLAY_CORE)
++
++
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/Makefile b/drivers/gpu/drm/amd/dal/dc/adapter/Makefile
+new file mode 100644
+index 0000000..8ede504
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/Makefile
+@@ -0,0 +1,18 @@
++#
++# Makefile for the 'adapter' sub-component of DAL.
++# It provides the control and status of HW adapter.
++
++ADAPTER = adapter_service.o hw_ctx_adapter_service.o wireless_data_source.o
++
++AMD_DAL_ADAPTER = $(addprefix $(AMDDALPATH)/dc/adapter/,$(ADAPTER))
++
++AMD_DAL_FILES += $(AMD_DAL_ADAPTER)
++
++
++###############################################################################
++# DCE 11x
++###############################################################################
++
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++AMD_DAL_FILES += $(AMDDALPATH)/dc/adapter/dce110/hw_ctx_adapter_service_dce110.o
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
+new file mode 100644
+index 0000000..4f9a637
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.c
+@@ -0,0 +1,2037 @@
++/*
++ * 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 "dal_services.h"
++
++#include "include/adapter_service_interface.h"
++#include "include/i2caux_interface.h"
++#include "include/asic_capability_types.h"
++#include "include/bios_parser_interface.h"
++#include "include/gpio_service_interface.h"
++#include "include/asic_capability_interface.h"
++#include "include/logger_interface.h"
++
++#include "adapter_service.h"
++#include "hw_ctx_adapter_service.h"
++#include "wireless_data_source.h"
++
++#include "atom.h"
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/hw_ctx_adapter_service_dce110.h"
++#endif
++
++/*
++ * Adapter service feature entry table.
++ *
++ * This is an array of features that is used to generate feature set. Each
++ * entry consists three element:
++ *
++ * Feature name, default value, and if this feature is a boolean type. A
++ * feature can only be a boolean or int type.
++ *
++ * Example 1: a boolean type feature
++ * FEATURE_ENABLE_HW_EDID_POLLING, false, true
++ *
++ * First element is feature name: EATURE_ENABLE_HW_EDID_POLLING, it has a
++ * default value 0, and it is a boolean feature.
++ *
++ * Example 2: an int type feature
++ * FEATURE_DCP_PROGRAMMING_WA, 0x1FF7, false
++ *
++ * In this case, the default value is 0x1FF7 and not a boolean type, which
++ * makes it an int type.
++ */
++
++static
++#if !defined(DAL_CZ_BRINGUP)
++const
++#endif
++struct feature_source_entry feature_entry_table[] = {
++ /* Feature name | default value | is boolean type */
++ {FEATURE_ENABLE_HW_EDID_POLLING, false, true},
++ {FEATURE_DP_SINK_DETECT_POLL_DATA_PIN, false, true},
++ {FEATURE_UNDERFLOW_INTERRUPT, false, true},
++ {FEATURE_ALLOW_WATERMARK_ADJUSTMENT, false, true},
++ {FEATURE_LIGHT_SLEEP, false, true},
++ {FEATURE_DCP_DITHER_FRAME_RANDOM_ENABLE, false, true},
++ {FEATURE_DCP_DITHER_RGB_RANDOM_ENABLE, false, true},
++ {FEATURE_DCP_DITHER_HIGH_PASS_RANDOM_ENABLE, false, true},
++ {FEATURE_LINE_BUFFER_ENHANCED_PIXEL_DEPTH, false, true},
++ {FEATURE_MAXIMIZE_URGENCY_WATERMARKS, false, true},
++ {FEATURE_MAXIMIZE_STUTTER_MARKS, false, true},
++ {FEATURE_MAXIMIZE_NBP_MARKS, false, true},
++ /*
++ * We meet HW I2C issue when test S3 resume on KB.
++ * An EPR is created for debug the issue.
++ * Make Test has already been implemented
++ * with HW I2C. The work load for revert back to SW I2C in make test
++ * is big. Below is workaround for this issue.
++ * Driver uses SW I2C.
++ * Make Test uses HW I2C.
++ */
++#if defined(DAL_CZ_BRINGUP)
++ {FEATURE_RESTORE_USAGE_I2C_SW_ENGINE, true, true},
++#else
++ {FEATURE_RESTORE_USAGE_I2C_SW_ENGINE, false, true},
++#endif
++ {FEATURE_USE_MAX_DISPLAY_CLK, false, true},
++ {FEATURE_ALLOW_EDP_RESOURCE_SHARING, false, true},
++ {FEATURE_SUPPORT_DP_YUV, false, true},
++ {FEATURE_SUPPORT_DP_Y_ONLY, false, true},
++ {FEATURE_DISABLE_DP_GTC_SYNC, true, true},
++ {FEATURE_MODIFY_TIMINGS_FOR_WIRELESS, false, true},
++ {FEATURE_DCP_BIT_DEPTH_REDUCTION_MODE, 0, false},
++ {FEATURE_DCP_DITHER_MODE, 0, false},
++ {FEATURE_DCP_PROGRAMMING_WA, 0, false},
++ {FEATURE_NO_HPD_LOW_POLLING_VCC_OFF, false, true},
++ {FEATURE_ENABLE_DFS_BYPASS, false, true},
++ {FEATURE_WIRELESS_FULL_TIMING_ADJUSTMENT, false, true},
++ {FEATURE_MAX_COFUNC_NON_DP_DISPLAYS, 2, false},
++ {FEATURE_WIRELESS_LIMIT_720P, false, true},
++ {FEATURE_MODIFY_TIMINGS_FOR_WIRELESS, false, true},
++ {FEATURE_SUPPORTED_HDMI_CONNECTION_NUM, 0, false},
++ {FEATURE_DETECT_REQUIRE_HPD_HIGH, false, true},
++ {FEATURE_NO_HPD_LOW_POLLING_VCC_OFF, false, true},
++ {FEATURE_LB_HIGH_RESOLUTION, false, true},
++ {FEATURE_MAX_CONTROLLER_NUM, 0, false},
++ {FEATURE_DRR_SUPPORT, AS_DRR_SUPPORT_ENABLED, false},
++ {FEATURE_STUTTER_MODE, 15, false},
++ {FEATURE_DP_DISPLAY_FORCE_SS_ENABLE, false, true},
++ {FEATURE_REPORT_CE_MODE_ONLY, false, true},
++ {FEATURE_ALLOW_OPTIMIZED_MODE_AS_DEFAULT, false, true},
++ {FEATURE_DDC_READ_FORCE_REPEATED_START, false, true},
++ {FEATURE_FORCE_TIMING_RESYNC, false, true},
++ {FEATURE_TMDS_DISABLE_DITHERING, false, true},
++ {FEATURE_HDMI_DISABLE_DITHERING, false, true},
++ {FEATURE_DP_DISABLE_DITHERING, false, true},
++ {FEATURE_EMBEDDED_DISABLE_DITHERING, true, true},
++ {FEATURE_ALLOW_SELF_REFRESH, false, true},
++ {FEATURE_ALLOW_DYNAMIC_PIXEL_ENCODING_CHANGE, false, true},
++ {FEATURE_ALLOW_HSYNC_VSYNC_ADJUSTMENT, false, true},
++ {FEATURE_FORCE_PSR, false, true},
++ {FEATURE_PSR_SETUP_TIME_TEST, 0, false},
++ {FEATURE_POWER_GATING_PIPE_IN_TILE, true, true},
++ {FEATURE_POWER_GATING_LB_PORTION, true, true},
++ {FEATURE_PREFER_3D_TIMING, false, true},
++ {FEATURE_VARI_BRIGHT_ENABLE, true, true},
++ {FEATURE_PSR_ENABLE, false, true},
++ {FEATURE_WIRELESS_ENABLE_COMPRESSED_AUDIO, false, true},
++ {FEATURE_WIRELESS_INCLUDE_UNVERIFIED_TIMINGS, true, true},
++ {FEATURE_EDID_STRESS_READ, false, true},
++ {FEATURE_DP_FRAME_PACK_STEREO3D, false, true},
++ {FEATURE_DISPLAY_PREFERRED_VIEW, 0, false},
++ {FEATURE_ALLOW_HDMI_WITHOUT_AUDIO, false, true},
++ {FEATURE_ABM_2_0, false, true},
++ {FEATURE_SUPPORT_MIRABILIS, false, true},
++ {FEATURE_OPTIMIZATION, 0xFFFF, false},
++ {FEATURE_PERF_MEASURE, 0, false},
++ {FEATURE_MIN_BACKLIGHT_LEVEL, 0, false},
++ {FEATURE_MAX_BACKLIGHT_LEVEL, 255, false},
++ {FEATURE_LOAD_DMCU_FIRMWARE, true, true},
++ {FEATURE_DISABLE_AZ_CLOCK_GATING, false, true},
++ {FEATURE_ENABLE_GPU_SCALING, false, true},
++ {FEATURE_DONGLE_SINK_COUNT_CHECK, true, true},
++ {FEATURE_INSTANT_UP_SCALE_DOWN_SCALE, false, true},
++ {FEATURE_TILED_DISPLAY, false, true},
++ {FEATURE_PREFERRED_ABM_CONFIG_SET, 0, false},
++ {FEATURE_CHANGE_SW_I2C_SPEED, 50, false},
++ {FEATURE_CHANGE_HW_I2C_SPEED, 50, false},
++ {FEATURE_CHANGE_I2C_SPEED_CONTROL, false, true},
++ {FEATURE_DEFAULT_PSR_LEVEL, 0, false},
++ {FEATURE_MAX_CLOCK_SOURCE_NUM, 0, false},
++ {FEATURE_REPORT_SINGLE_SELECTED_TIMING, false, true},
++ {FEATURE_ALLOW_HDMI_HIGH_CLK_DP_DONGLE, true, true},
++ {FEATURE_SUPPORT_EXTERNAL_PANEL_DRR, false, true},
++ {FEATURE_LVDS_SAFE_PIXEL_CLOCK_RANGE, 0, false},
++ {FEATURE_ABM_CONFIG, 0, false},
++ {FEATURE_WIRELESS_ENABLE, false, true},
++ {FEATURE_ALLOW_DIRECT_MEMORY_ACCESS_TRIG, false, true},
++ {FEATURE_FORCE_STATIC_SCREEN_EVENT_TRIGGERS, 0, false},
++ {FEATURE_USE_PPLIB, true, true},
++ {FEATURE_DISABLE_LPT_SUPPORT, false, true},
++ {FEATURE_DUMMY_FBC_BACKEND, false, true},
++ {FEATURE_DPMS_AUDIO_ENDPOINT_CONTROL, true, true},
++ {FEATURE_DISABLE_FBC_COMP_CLK_GATE, false, true},
++ {FEATURE_PIXEL_PERFECT_OUTPUT, false, true},
++ {FEATURE_8BPP_SUPPORTED, false, true}
++};
++
++
++/* Stores entire ASIC features by sets */
++uint32_t adapter_feature_set[FEATURE_MAXIMUM/32];
++
++enum {
++ LEGACY_MAX_NUM_OF_CONTROLLERS = 2,
++ DEFAULT_NUM_COFUNC_NON_DP_DISPLAYS = 2
++};
++
++/*
++ * get_feature_entries_num
++ *
++ * Get number of feature entries
++ */
++static inline uint32_t get_feature_entries_num(void)
++{
++ return ARRAY_SIZE(feature_entry_table);
++}
++
++static void get_platform_info_methods(
++ struct adapter_service *as)
++{
++ struct platform_info_params params;
++ uint32_t mask = 0;
++
++ params.data = &mask;
++ params.method = PM_GET_AVAILABLE_METHODS;
++
++ if (dal_get_platform_info(as->ctx, &params))
++ as->platform_methods_mask = mask;
++
++
++}
++
++static void initialize_backlight_caps(
++ struct adapter_service *as)
++{
++ struct firmware_info fw_info;
++ struct embedded_panel_info panel_info;
++ struct platform_info_ext_brightness_caps caps;
++ struct platform_info_params params;
++ bool custom_curve_present = false;
++ bool custom_min_max_present = false;
++
++ if (!(PM_GET_EXTENDED_BRIGHNESS_CAPS & as->platform_methods_mask)) {
++ dal_logger_write(as->ctx->logger,
++ LOG_MAJOR_BACKLIGHT,
++ LOG_MINOR_BACKLIGHT_BRIGHTESS_CAPS,
++ "This method is not supported\n");
++ return;
++ }
++
++ if (dal_bios_parser_get_firmware_info
++ (as->bios_parser, &fw_info) != BP_RESULT_OK ||
++ dal_bios_parser_get_embedded_panel_info
++ (as->bios_parser, &panel_info) != BP_RESULT_OK)
++ return;
++
++ params.data = &caps;
++ params.method = PM_GET_EXTENDED_BRIGHNESS_CAPS;
++
++ if (dal_get_platform_info(as->ctx, &params)) {
++ as->ac_level_percentage = caps.basic_caps.ac_level_percentage;
++ as->dc_level_percentage = caps.basic_caps.dc_level_percentage;
++ custom_curve_present = (caps.data_points_num > 0);
++ custom_min_max_present = true;
++ } else
++ return;
++ /* Choose minimum backlight level base on priority:
++ * extended caps,VBIOS,default */
++ if (custom_min_max_present)
++ as->backlight_8bit_lut[0] = caps.min_input_signal;
++
++ else if (fw_info.min_allowed_bl_level > 0)
++ as->backlight_8bit_lut[0] = fw_info.min_allowed_bl_level;
++
++ else
++ as->backlight_8bit_lut[0] = DEFAULT_MIN_BACKLIGHT;
++
++ /* Choose maximum backlight level base on priority:
++ * extended caps,default */
++ if (custom_min_max_present)
++ as->backlight_8bit_lut[100] = caps.max_input_signal;
++
++ else
++ as->backlight_8bit_lut[100] = DEFAULT_MAX_BACKLIGHT;
++
++ if (as->backlight_8bit_lut[100] > ABSOLUTE_BACKLIGHT_MAX)
++ as->backlight_8bit_lut[100] = ABSOLUTE_BACKLIGHT_MAX;
++
++ if (as->backlight_8bit_lut[0] > as->backlight_8bit_lut[100])
++ as->backlight_8bit_lut[0] = as->backlight_8bit_lut[100];
++
++ if (custom_curve_present) {
++ uint16_t index = 1;
++ uint16_t i;
++ uint16_t num_of_data_points = (caps.data_points_num <= 99 ?
++ caps.data_points_num : 99);
++ /* Filling translation table from data points -
++ * between every two provided data points we
++ * lineary interpolate missing values
++ */
++ for (i = 0 ; i < num_of_data_points; i++) {
++ uint16_t luminance = caps.data_points[i].luminance;
++ uint16_t signal_level =
++ caps.data_points[i].signal_level;
++
++ if (signal_level < as->backlight_8bit_lut[0])
++ signal_level = as->backlight_8bit_lut[0];
++
++ if (signal_level > as->backlight_8bit_lut[100])
++ signal_level = as->backlight_8bit_lut[100];
++
++ /* Lineary interpolate missing values */
++ if (index < luminance) {
++ uint16_t base_value =
++ as->backlight_8bit_lut[index-1];
++ uint16_t delta_signal =
++ signal_level - base_value;
++ uint16_t delta_luma = luminance - index + 1;
++ uint16_t step = delta_signal;
++
++ for (; index < luminance ; index++) {
++ as->backlight_8bit_lut[index] =
++ base_value +
++ (step / delta_luma);
++ step += delta_signal;
++ }
++ }
++ /* Now [index == luminance], so we can add
++ * data point to the translation table */
++ as->backlight_8bit_lut[index++] = signal_level;
++ }
++ /* Complete the final segment of interpolation -
++ * between last datapoint and maximum value */
++ if (index < 100) {
++ uint16_t base_value = as->backlight_8bit_lut[index-1];
++ uint16_t delta_signal =
++ as->backlight_8bit_lut[100]-base_value;
++ uint16_t delta_luma = 100 - index + 1;
++ uint16_t step = delta_signal;
++
++ for (; index < 100 ; index++) {
++ as->backlight_8bit_lut[index] = base_value +
++ (step / delta_luma);
++ step += delta_signal;
++ }
++ }
++ }
++ /* build backlight translation table based on default curve */
++ else {
++ /* Default backlight curve can be defined by
++ * polinomial F(x) = A(x*x) + Bx + C.
++ * Backlight curve should always satisfy
++ * F(0) = min, F(100) = max, so polinomial coefficients are:
++ * A is 0.0255 - B/100 - min/10000 -
++ * (255-max)/10000 = (max - min)/10000 - B/100
++ * B is adjustable factor to modify the curve.
++ * Bigger B results in less concave curve.
++ * B range is [0..(max-min)/100]
++ * C is backlight minimum
++ */
++ uint16_t delta = as->backlight_8bit_lut[100] -
++ as->backlight_8bit_lut[0];
++ uint16_t coeffc = as->backlight_8bit_lut[0];
++ uint16_t coeffb = (BACKLIGHT_CURVE_COEFFB < delta ?
++ BACKLIGHT_CURVE_COEFFB : delta);
++ uint16_t coeffa = delta - coeffb;
++ uint16_t i;
++ uint32_t temp;
++
++ for (i = 1; i < 100 ; i++) {
++ temp = (coeffa * i * i) / BACKLIGHT_CURVE_COEFFA_FACTOR;
++ as->backlight_8bit_lut[i] = temp + (coeffb * i) /
++ BACKLIGHT_CURVE_COEFFB_FACTOR + coeffc;
++ }
++ }
++ as->backlight_caps_initialized = true;
++}
++
++static void log_overriden_features(
++ struct adapter_service *as,
++ const char *feature_name,
++ enum adapter_feature_id id,
++ bool bool_feature,
++ uint32_t value)
++{
++ if (bool_feature)
++ dal_logger_write(as->ctx->logger,
++ LOG_MAJOR_FEATURE_OVERRIDE,
++ LOG_MINOR_FEATURE_OVERRIDE,
++ "Overridden %s is %s now\n",
++ feature_name,
++ (value == 0) ? "disabled" : "enabled");
++ else
++ dal_logger_write(as->ctx->logger,
++ LOG_MAJOR_FEATURE_OVERRIDE,
++ LOG_MINOR_FEATURE_OVERRIDE,
++ "Overridden %s new value: %d\n",
++ feature_name,
++ value);
++}
++
++/*************************************
++ * Local static functions definition *
++ *************************************/
++
++#define check_bool_feature(feature) \
++case FEATURE_ ## feature: \
++ if (param->bool_param_enable_mask & \
++ (1 << DAL_PARAM_ ## feature)) { \
++ *data = param->bool_param_values & \
++ (1 << DAL_PARAM_ ## feature); \
++ ret = true; \
++ feature_name = "FEATURE_" #feature; \
++ } \
++ break
++
++#define check_int_feature(feature) \
++case FEATURE_ ## feature: \
++ if (param->int_param_values[DAL_PARAM_ ## feature] != \
++ DAL_PARAM_INVALID_INT) { \
++ *data = param->int_param_values[DAL_PARAM_ ## feature];\
++ ret = true;\
++ bool_feature = false;\
++ feature_name = "FEATURE_" #feature;\
++ } \
++ break
++
++/*
++ * override_default_parameters
++ *
++ * Override features (from runtime parameter)
++ * corresponding to Adapter Service Feature ID
++ */
++static bool override_default_parameters(
++ struct adapter_service *as,
++ const struct dal_override_parameters *param,
++ const uint32_t idx,
++ uint32_t *data)
++{
++ bool ret = false;
++ bool bool_feature = true;
++ char *feature_name;
++
++ if (idx >= get_feature_entries_num()) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ switch (feature_entry_table[idx].feature_id) {
++ check_int_feature(MAX_COFUNC_NON_DP_DISPLAYS);
++ check_int_feature(DRR_SUPPORT);
++ check_bool_feature(LIGHT_SLEEP);
++ check_bool_feature(MAXIMIZE_STUTTER_MARKS);
++ check_bool_feature(MAXIMIZE_URGENCY_WATERMARKS);
++ check_bool_feature(USE_MAX_DISPLAY_CLK);
++ check_bool_feature(ENABLE_DFS_BYPASS);
++ check_bool_feature(POWER_GATING_PIPE_IN_TILE);
++ check_bool_feature(POWER_GATING_LB_PORTION);
++ check_bool_feature(PSR_ENABLE);
++ check_bool_feature(VARI_BRIGHT_ENABLE);
++ check_bool_feature(USE_PPLIB);
++ check_bool_feature(DISABLE_LPT_SUPPORT);
++ check_bool_feature(DUMMY_FBC_BACKEND);
++ check_bool_feature(ENABLE_GPU_SCALING);
++ default:
++ return false;
++ }
++ if (ret)
++ log_overriden_features(
++ as,
++ feature_name,
++ feature_entry_table[idx].feature_id,
++ bool_feature,
++ *data);
++
++ return ret;
++}
++
++/*
++ * get_feature_value_from_data_sources
++ *
++ * For a given feature, determine its value from ASIC cap and wireless
++ * data source.
++ * idx : index of feature_entry_table for the feature id.
++ */
++static bool get_feature_value_from_data_sources(
++ const struct adapter_service *as,
++ const uint32_t idx,
++ uint32_t *data)
++{
++ if (idx >= get_feature_entries_num()) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ switch (feature_entry_table[idx].feature_id) {
++ case FEATURE_MAX_COFUNC_NON_DP_DISPLAYS:
++ *data = as->asic_cap->data[ASIC_DATA_MAX_COFUNC_NONDP_DISPLAYS];
++ break;
++
++ case FEATURE_WIRELESS_LIMIT_720P:
++ *data = as->asic_cap->caps.WIRELESS_LIMIT_TO_720P;
++ break;
++
++ case FEATURE_WIRELESS_FULL_TIMING_ADJUSTMENT:
++ *data = as->asic_cap->caps.WIRELESS_FULL_TIMING_ADJUSTMENT;
++ break;
++
++ case FEATURE_MODIFY_TIMINGS_FOR_WIRELESS:
++ *data = as->asic_cap->caps.WIRELESS_TIMING_ADJUSTMENT;
++ break;
++
++ case FEATURE_SUPPORTED_HDMI_CONNECTION_NUM:
++ *data =
++ as->asic_cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM];
++ break;
++
++ case FEATURE_DETECT_REQUIRE_HPD_HIGH:
++ *data = as->asic_cap->caps.HPD_CHECK_FOR_EDID;
++ break;
++
++ case FEATURE_NO_HPD_LOW_POLLING_VCC_OFF:
++ *data = as->asic_cap->caps.NO_VCC_OFF_HPD_POLLING;
++ break;
++
++ case FEATURE_STUTTER_MODE:
++ *data = as->asic_cap->data[ASIC_DATA_STUTTERMODE];
++ break;
++
++ case FEATURE_WIRELESS_ENABLE:
++ *data = as->wireless_data.wireless_enable;
++ break;
++
++ case FEATURE_8BPP_SUPPORTED:
++ *data = as->asic_cap->caps.SUPPORT_8BPP;
++ break;
++
++ default:
++ return false;
++ }
++
++ return true;
++}
++
++/* get_bool_value
++ *
++ * Get the boolean value of a given feature
++ */
++static bool get_bool_value(
++ const uint32_t set,
++ const uint32_t idx)
++{
++ if (idx >= 32) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ return ((set & (1 << idx)) != 0);
++}
++
++/*
++ * get_hpd_info
++ *
++ * Get HPD information from BIOS
++ */
++static bool get_hpd_info(struct adapter_service *as,
++ struct graphics_object_id id,
++ struct graphics_object_hpd_info *info)
++{
++ return BP_RESULT_OK ==
++ dal_bios_parser_get_hpd_info(as->bios_parser, id, info);
++}
++
++/*
++ * lookup_feature_entry
++ *
++ * Find the entry index of a given feature in feature table
++ */
++static uint32_t lookup_feature_entry(
++ enum adapter_feature_id feature_id)
++{
++ uint32_t entries_num = get_feature_entries_num();
++ uint32_t i = 0;
++
++ while (i != entries_num) {
++ if (feature_entry_table[i].feature_id == feature_id)
++ break;
++
++ ++i;
++ }
++
++ return i;
++}
++
++/*
++ * set_bool_value
++ *
++ * Set the boolean value of a given feature
++ */
++static void set_bool_value(
++ uint32_t *set,
++ const uint32_t idx,
++ bool value)
++{
++ if (idx >= 32) {
++ ASSERT_CRITICAL(false);
++ return;
++ }
++
++ if (value)
++ *set |= (1 << idx);
++ else
++ *set &= ~(1 << idx);
++}
++
++/*
++ * generate_feature_set
++ *
++ * Generate the internal feature set from multiple data sources
++ */
++static bool generate_feature_set(
++ struct adapter_service *as,
++ const struct dal_override_parameters *param)
++{
++ uint32_t i = 0;
++ uint32_t value = 0;
++ uint32_t set_idx = 0;
++ uint32_t internal_idx = 0;
++ uint32_t entry_num = 0;
++ const struct feature_source_entry *entry = NULL;
++
++ dc_service_memset(adapter_feature_set, 0, sizeof(adapter_feature_set));
++ entry_num = get_feature_entries_num();
++
++
++ while (i != entry_num) {
++ entry = &feature_entry_table[i];
++
++ if (entry->feature_id <= FEATURE_UNKNOWN ||
++ entry->feature_id >= FEATURE_MAXIMUM) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ set_idx = (uint32_t)((entry->feature_id - 1) / 32);
++ internal_idx = (uint32_t)((entry->feature_id - 1) % 32);
++
++ /* TODO: wireless, runtime parameter, vbios */
++ if (!override_default_parameters(as, param, i, &value)) {
++ if (!get_feature_value_from_data_sources(
++ as, i, &value)) {
++ /*
++ * Can't find feature values from
++ * above data sources
++ * Assign default value
++ */
++ value = entry->default_value;
++ }
++ }
++
++ if (entry->is_boolean_type)
++ set_bool_value(&adapter_feature_set[set_idx],
++ internal_idx,
++ value != 0);
++ else
++ adapter_feature_set[set_idx] = value;
++
++ i++;
++ }
++
++ return true;
++}
++
++
++/*
++ * create_hw_ctx
++ *
++ * Create HW context for adapter service. This is DCE specific.
++ */
++static struct hw_ctx_adapter_service *create_hw_ctx(
++ enum dce_version dce_version,
++ struct dc_context *ctx)
++{
++ switch (dce_version) {
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ return dal_adapter_service_create_hw_ctx_dce110(ctx);
++#endif
++ default:
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++}
++
++/*
++ * adapter_service_destruct
++ *
++ * Release memory of objects in adapter service
++ */
++static void adapter_service_destruct(
++ struct adapter_service *as)
++{
++ dal_adapter_service_destroy_hw_ctx(&as->hw_ctx);
++ dal_i2caux_destroy(&as->i2caux);
++ dal_bios_parser_destroy(&as->bios_parser);
++ dal_gpio_service_destroy(&as->gpio_service);
++ dal_asic_capability_destroy(&as->asic_cap);
++ dal_bios_parser_destroy_integrated_info(as->ctx, &as->integrated_info);
++}
++
++/*
++ * adapter_service_construct
++ *
++ * Construct the derived type of adapter service
++ */
++static bool adapter_service_construct(
++ struct adapter_service *as,
++ struct as_init_data *init_data)
++{
++ if (!init_data)
++ return false;
++
++ /* Create ASIC capability */
++ as->ctx = init_data->ctx;
++ as->asic_cap = dal_asic_capability_create(
++ &init_data->hw_init_data, as->ctx);
++
++ if (!as->asic_cap) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++#if defined(DAL_CZ_BRINGUP)
++ if (dal_adapter_service_get_dce_version(as) == DCE_VERSION_11_0) {
++ uint32_t i;
++
++ for (i = 0; i < ARRAY_SIZE(feature_entry_table); i++) {
++ enum adapter_feature_id id =
++ feature_entry_table[i].feature_id;
++ if (id == FEATURE_MAXIMIZE_URGENCY_WATERMARKS ||
++ id == FEATURE_MAXIMIZE_STUTTER_MARKS ||
++ id == FEATURE_MAXIMIZE_NBP_MARKS)
++ feature_entry_table[i].default_value = true;
++ }
++ }
++#endif
++
++ /* Generate feature set table */
++ if (!generate_feature_set(as, init_data->display_param)) {
++ ASSERT_CRITICAL(false);
++ goto failed_to_generate_features;
++ }
++
++ /* Create BIOS parser */
++ init_data->bp_init_data.ctx = init_data->ctx;
++ as->bios_parser =
++ dal_bios_parser_create(&init_data->bp_init_data, as);
++
++ if (!as->bios_parser) {
++ ASSERT_CRITICAL(false);
++ goto failed_to_create_bios_parser;
++ }
++
++ /* Create GPIO service */
++ as->gpio_service =
++ dal_gpio_service_create(
++ dal_adapter_service_get_dce_version(as),
++ as->ctx);
++
++ if (!as->gpio_service) {
++ ASSERT_CRITICAL(false);
++ goto failed_to_create_gpio_service;
++ }
++
++ /* Create I2C AUX */
++ as->i2caux = dal_i2caux_create(as, as->ctx);
++
++ if (!as->i2caux) {
++ ASSERT_CRITICAL(false);
++ goto failed_to_create_i2caux;
++ }
++
++ /* Create Adapter Service HW Context*/
++ as->hw_ctx = create_hw_ctx(
++ dal_adapter_service_get_dce_version(as),
++ as->ctx);
++
++ if (!as->hw_ctx) {
++ ASSERT_CRITICAL(false);
++ goto failed_to_create_hw_ctx;
++ }
++
++ /* Avoid wireless encoder creation in upstream branch. */
++
++ /* Integrated info is not provided on discrete ASIC. NULL is allowed */
++ as->integrated_info = dal_bios_parser_create_integrated_info(
++ as->bios_parser);
++
++ dal_bios_parser_post_init(as->bios_parser);
++
++ /* Generate backlight translation table and initializes
++ other brightness properties */
++ as->backlight_caps_initialized = false;
++
++ get_platform_info_methods(as);
++
++ initialize_backlight_caps(as);
++
++ return true;
++
++failed_to_generate_features:
++ dal_adapter_service_destroy_hw_ctx(&as->hw_ctx);
++
++failed_to_create_hw_ctx:
++ dal_i2caux_destroy(&as->i2caux);
++
++failed_to_create_i2caux:
++ dal_gpio_service_destroy(&as->gpio_service);
++
++failed_to_create_gpio_service:
++ dal_bios_parser_destroy(&as->bios_parser);
++
++failed_to_create_bios_parser:
++ dal_asic_capability_destroy(&as->asic_cap);
++
++ return false;
++}
++
++/*
++ * Global function definition
++ */
++
++/*
++ * dal_adapter_service_create
++ *
++ * Create adapter service
++ */
++struct adapter_service *dal_adapter_service_create(
++ struct as_init_data *init_data)
++{
++ struct adapter_service *as;
++
++ as = dc_service_alloc(init_data->ctx, sizeof(struct adapter_service));
++
++ if (!as) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (adapter_service_construct(as, init_data))
++ return as;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(init_data->ctx, as);
++
++ return NULL;
++}
++
++/*
++ * dal_adapter_service_destroy
++ *
++ * Destroy adapter service and objects it contains
++ */
++void dal_adapter_service_destroy(
++ struct adapter_service **as)
++{
++ if (!as) {
++ ASSERT_CRITICAL(false);
++ return;
++ }
++
++ if (!*as) {
++ ASSERT_CRITICAL(false);
++ return;
++ }
++
++ adapter_service_destruct(*as);
++
++ dc_service_free((*as)->ctx, *as);
++
++ *as = NULL;
++}
++
++/*
++ * dal_adapter_service_get_dce_version
++ *
++ * Get the DCE version of current ASIC
++ */
++enum dce_version dal_adapter_service_get_dce_version(
++ const struct adapter_service *as)
++{
++ uint32_t version = as->asic_cap->data[ASIC_DATA_DCE_VERSION];
++
++ switch (version) {
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case 0x110:
++ return DCE_VERSION_11_0;
++#endif
++ default:
++ ASSERT_CRITICAL(false);
++ return DCE_VERSION_UNKNOWN;
++ }
++}
++
++/*
++ * dal_adapter_service_get_controllers_num
++ *
++ * Get number of controllers
++ */
++uint8_t dal_adapter_service_get_controllers_num(
++ struct adapter_service *as)
++{
++ uint32_t result = as->asic_cap->data[ASIC_DATA_CONTROLLERS_NUM];
++
++ /* Check the "max num of controllers" feature,
++ * use it for debugging purposes only */
++ /* TODO implement
++ * dal_adapter_service_get_feature_value(as, ) */
++
++ return result;
++}
++
++
++/** Get total number of connectors.
++ *
++ * \param as Adapter Service
++ *
++ * \return Total number of connectors. It is up-to-the caller to decide
++ * if the number is valid.
++ */
++uint8_t dal_adapter_service_get_connectors_num(
++ struct adapter_service *as)
++{
++ uint8_t vbios_connectors_num = 0;
++ uint8_t wireless_connectors_num = 0;
++
++ vbios_connectors_num = dal_bios_parser_get_connectors_number(
++ as->bios_parser);
++ wireless_connectors_num = wireless_get_connectors_num(as);
++
++ return vbios_connectors_num + wireless_connectors_num;
++}
++
++static bool is_wireless_object(struct graphics_object_id id)
++{
++ if ((id.type == OBJECT_TYPE_ENCODER &&
++ id.id == ENCODER_ID_INTERNAL_WIRELESS) ||
++ (id.type == OBJECT_TYPE_CONNECTOR && id.id ==
++ CONNECTOR_ID_WIRELESS) ||
++ (id.type == OBJECT_TYPE_CONNECTOR && id.id ==
++ CONNECTOR_ID_MIRACAST))
++ return true;
++ return false;
++}
++
++/**
++ * Get the number of source objects of an object
++ *
++ * \param [in] as: Adapter Service
++ *
++ * \param [in] id: The graphics object id
++ *
++ * \return
++ * The number of the source objects of an object
++ */
++uint32_t dal_adapter_service_get_src_num(
++ struct adapter_service *as, struct graphics_object_id id)
++{
++ if (is_wireless_object(id))
++ return wireless_get_srcs_num(as, id);
++ else
++ return dal_bios_parser_get_src_number(as->bios_parser, id);
++}
++
++/**
++ * Get the source objects of an object
++ *
++ * \param [in] id The graphics object id
++ * \param [in] index Enumerating index which starts at 0
++ *
++ * \return If enumerating successfully, return the VALID source object id,
++ * otherwise, returns "zeroed out" object id.
++ * Client should call dal_graphics_object_id_is_valid() to check
++ * weather the id is valid.
++ */
++struct graphics_object_id dal_adapter_service_get_src_obj(
++ struct adapter_service *as,
++ struct graphics_object_id id,
++ uint32_t index)
++{
++ struct graphics_object_id src_object_id;
++
++ if (is_wireless_object(id))
++ src_object_id = wireless_get_src_obj_id(as, id, index);
++ else {
++ if (BP_RESULT_OK !=
++ dal_bios_parser_get_src_obj(
++ as->bios_parser, id, index, &src_object_id))
++ src_object_id =
++ dal_graphics_object_id_init(
++ 0,
++ ENUM_ID_UNKNOWN,
++ OBJECT_TYPE_UNKNOWN);
++ }
++
++ return src_object_id;
++}
++
++/** Get connector object id associated with a connector index.
++ *
++ * \param as Adapter Service
++ *
++ * \param connector_index Index of connector between zero and total number
++ * returned by dal_adapter_service_get_connectors_num()
++ *
++ * \return graphics object id corresponding to the connector_index.
++ */
++struct graphics_object_id dal_adapter_service_get_connector_obj_id(
++ struct adapter_service *as,
++ uint8_t connector_index)
++{
++ uint8_t bios_connectors_num =
++ dal_bios_parser_get_connectors_number(as->bios_parser);
++
++ if (connector_index >= bios_connectors_num)
++ return wireless_get_connector_id(
++ as,
++ connector_index);
++ else
++ return dal_bios_parser_get_connector_id(
++ as->bios_parser,
++ connector_index);
++}
++
++bool dal_adapter_service_get_device_tag(
++ struct adapter_service *as,
++ struct graphics_object_id connector_object_id,
++ uint32_t device_tag_index,
++ struct connector_device_tag_info *info)
++{
++ if (BP_RESULT_OK == dal_bios_parser_get_device_tag(as->bios_parser,
++ connector_object_id, device_tag_index, info))
++ return true;
++ else
++ return false;
++}
++
++/* Check if DeviceId is supported by ATOM_OBJECT_HEADER support info */
++bool dal_adapter_service_is_device_id_supported(struct adapter_service *as,
++ struct device_id id)
++{
++ return dal_bios_parser_is_device_id_supported(as->bios_parser, id);
++}
++
++bool dal_adapter_service_is_meet_underscan_req(struct adapter_service *as)
++{
++ struct firmware_info fw_info;
++ enum bp_result bp_result = dal_adapter_service_get_firmware_info(
++ as, &fw_info);
++ uint32_t disp_clk_limit =
++ as->asic_cap->data[ASIC_DATA_MIN_DISPCLK_FOR_UNDERSCAN];
++ if (BP_RESULT_OK == bp_result) {
++ dal_logger_write(as->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_ADAPTER_SERVICE,
++ "Read firmware is NULL");
++ return false;
++ }
++ if (fw_info.default_display_engine_pll_frequency < disp_clk_limit)
++ return false;
++ return true;
++}
++
++bool dal_adapter_service_underscan_for_hdmi_only(struct adapter_service *as)
++{
++ return as->asic_cap->caps.UNDERSCAN_FOR_HDMI_ONLY;
++}
++/*
++ * dal_adapter_service_get_clock_sources_num
++ *
++ * Get number of clock sources
++ */
++uint8_t dal_adapter_service_get_clock_sources_num(
++ struct adapter_service *as)
++{
++ struct firmware_info fw_info;
++ uint32_t max_clk_src = 0;
++ uint32_t num = as->asic_cap->data[ASIC_DATA_CLOCKSOURCES_NUM];
++
++ /*
++ * Check is system supports the use of the External clock source
++ * as a clock source for DP
++ */
++ enum bp_result bp_result =
++ dal_bios_parser_get_firmware_info(as->bios_parser,
++ &fw_info);
++
++ if (BP_RESULT_OK == bp_result &&
++ fw_info.external_clock_source_frequency_for_dp != 0)
++ ++num;
++
++ /*
++ * Add clock source for wireless if supported
++ */
++ num += (uint32_t)wireless_get_clocks_num(as);
++
++ /* Check the "max number of clock sources" feature */
++ if (dal_adapter_service_get_feature_value(
++ FEATURE_MAX_CLOCK_SOURCE_NUM,
++ &max_clk_src,
++ sizeof(uint32_t)))
++ if ((max_clk_src != 0) && (max_clk_src < num))
++ num = max_clk_src;
++
++ return num;
++}
++
++/*
++ * dal_adapter_service_get_func_controllers_num
++ *
++ * Get number of controllers
++ */
++uint8_t dal_adapter_service_get_func_controllers_num(
++ struct adapter_service *as)
++{
++ uint32_t result =
++ as->asic_cap->data[ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM];
++
++ /* Check the "max num of controllers" feature,
++ * use it for debugging purposes only */
++
++ /* Limit number of controllers by OS */
++
++ struct asic_feature_flags flags;
++
++ flags.raw = as->asic_cap->data[ASIC_DATA_FEATURE_FLAGS];
++
++ if (flags.bits.LEGACY_CLIENT &&
++ (result > LEGACY_MAX_NUM_OF_CONTROLLERS))
++ result = LEGACY_MAX_NUM_OF_CONTROLLERS;
++
++ return result;
++}
++
++/*
++ * dal_adapter_service_is_feature_supported
++ *
++ * Return if a given feature is supported by the ASIC. The feature has to be
++ * a boolean type.
++ */
++bool dal_adapter_service_is_feature_supported(
++ enum adapter_feature_id feature_id)
++{
++ bool data = 0;
++
++ dal_adapter_service_get_feature_value(feature_id, &data, sizeof(bool));
++
++ return data;
++}
++
++/**
++ * Reports maximum number of confunctional non-DP displays.
++ * Value can be overriden if FEATURE_REPORT_SINGLE_SELECTED_TIMING feature is
++ * enabled.
++ *
++ * \return
++ * Maximum number of confunctional non-DP displays
++ */
++uint32_t dal_adapter_service_get_max_cofunc_non_dp_displays(void)
++{
++ uint32_t non_dp_displays = DEFAULT_NUM_COFUNC_NON_DP_DISPLAYS;
++
++ if (true == dal_adapter_service_get_feature_value(
++ FEATURE_MAX_COFUNC_NON_DP_DISPLAYS,
++ &non_dp_displays,
++ sizeof(non_dp_displays))) {
++ /* the cached value exist */
++ /* TODO: add more logic as per-DAL2 */
++ }
++
++ return non_dp_displays;
++}
++
++uint32_t dal_adapter_service_get_single_selected_timing_signals(void)
++{
++ uint32_t signals_bitmap = 0;
++
++ if (dal_adapter_service_is_feature_supported(
++ FEATURE_REPORT_SINGLE_SELECTED_TIMING)) {
++ /* the cached value exist */
++ /* TODO: add more logic as per-DAL2 */
++ signals_bitmap = 0;
++ }
++
++ return signals_bitmap;
++}
++
++/*
++ * dal_adapter_service_get_i2c_info
++ *
++ * Get I2C information from BIOS
++ */
++bool dal_adapter_service_get_i2c_info(
++ struct adapter_service *as,
++ struct graphics_object_id id,
++ struct graphics_object_i2c_info *i2c_info)
++{
++ if (!i2c_info) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ return BP_RESULT_OK ==
++ dal_bios_parser_get_i2c_info(as->bios_parser, id, i2c_info);
++}
++
++/*
++ * dal_adapter_service_obtain_ddc
++ *
++ * Obtain DDC
++ */
++struct ddc *dal_adapter_service_obtain_ddc(
++ struct adapter_service *as,
++ struct graphics_object_id id)
++{
++ struct graphics_object_i2c_info i2c_info;
++ struct gpio_ddc_hw_info hw_info;
++
++
++ if (!dal_adapter_service_get_i2c_info(as, id, &i2c_info))
++ return NULL;
++
++ hw_info.ddc_channel = i2c_info.i2c_line;
++ hw_info.hw_supported = i2c_info.i2c_hw_assist;
++
++ return dal_gpio_service_create_ddc(
++ as->gpio_service,
++ i2c_info.gpio_info.clk_a_register_index,
++ 1 << i2c_info.gpio_info.clk_a_shift,
++ &hw_info);
++}
++
++/*
++ * dal_adapter_service_release_ddc
++ *
++ * Release DDC
++ */
++void dal_adapter_service_release_ddc(
++ struct adapter_service *as,
++ struct ddc *ddc)
++{
++ dal_gpio_service_destroy_ddc(&ddc);
++}
++
++/*
++ * dal_adapter_service_obtain_hpd_irq
++ *
++ * Obtain HPD interrupt request
++ */
++struct irq *dal_adapter_service_obtain_hpd_irq(
++ struct adapter_service *as,
++ struct graphics_object_id id)
++{
++ enum bp_result bp_result;
++
++ struct graphics_object_hpd_info hpd_info;
++ struct gpio_pin_info pin_info;
++
++ if (!get_hpd_info(as, id, &hpd_info))
++ return NULL;
++
++ bp_result = dal_bios_parser_get_gpio_pin_info(as->bios_parser,
++ hpd_info.hpd_int_gpio_uid, &pin_info);
++
++ if (bp_result != BP_RESULT_OK) {
++ ASSERT(bp_result == BP_RESULT_NORECORD);
++ return NULL;
++ }
++
++ return dal_gpio_service_create_irq(
++ as->gpio_service,
++ pin_info.offset,
++ pin_info.mask);
++}
++
++/*
++ * dal_adapter_service_release_irq
++ *
++ * Release interrupt request
++ */
++void dal_adapter_service_release_irq(
++ struct adapter_service *as,
++ struct irq *irq)
++{
++ dal_gpio_service_destroy_irq(&irq);
++}
++
++/*
++ * dal_adapter_service_get_ss_info_num
++ *
++ * Get number of spread spectrum entries from BIOS
++ */
++uint32_t dal_adapter_service_get_ss_info_num(
++ struct adapter_service *as,
++ enum as_signal_type signal)
++{
++ return dal_bios_parser_get_ss_entry_number(as->bios_parser, signal);
++}
++
++/*
++ * dal_adapter_service_get_ss_info
++ *
++ * Get spread spectrum info from BIOS
++ */
++bool dal_adapter_service_get_ss_info(
++ struct adapter_service *as,
++ enum as_signal_type signal,
++ uint32_t idx,
++ struct spread_spectrum_info *info)
++{
++ enum bp_result bp_result =
++ dal_bios_parser_get_spread_spectrum_info(
++ as->bios_parser, signal, idx, info);
++
++ return BP_RESULT_OK == bp_result;
++}
++
++/*
++ * dal_adapter_service_get_integrated_info
++ *
++ * Get integrated information on BIOS
++ */
++bool dal_adapter_service_get_integrated_info(
++ struct adapter_service *as,
++ struct integrated_info *info)
++{
++ if (info == NULL || as->integrated_info == NULL)
++ return false;
++
++ dc_service_memmove(info, as->integrated_info, sizeof(struct integrated_info));
++
++ return true;
++}
++
++/*
++ * dal_adapter_service_is_dfs_bypass_enabled
++ *
++ * Check if DFS bypass is enabled
++ */
++bool dal_adapter_service_is_dfs_bypass_enabled(
++ struct adapter_service *as)
++{
++ if (as->integrated_info == NULL)
++ return false;
++ if ((as->integrated_info->gpu_cap_info & DFS_BYPASS_ENABLE) &&
++ dal_adapter_service_is_feature_supported(
++ FEATURE_ENABLE_DFS_BYPASS))
++ return true;
++ else
++ return false;
++}
++
++/*
++ * dal_adapter_service_get_sw_i2c_speed
++ *
++ * Get SW I2C speed
++ */
++uint32_t dal_adapter_service_get_sw_i2c_speed(
++ struct adapter_service *as)
++{
++ /* TODO: only from ASIC caps. Feature key is not implemented*/
++ return as->asic_cap->data[ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ];
++}
++
++/*
++ * dal_adapter_service_get_hw_i2c_speed
++ *
++ * Get HW I2C speed
++ */
++uint32_t dal_adapter_service_get_hw_i2c_speed(
++ struct adapter_service *as)
++{
++ /* TODO: only from ASIC caps. Feature key is not implemented*/
++ return as->asic_cap->data[ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ];
++}
++
++/*
++ * dal_adapter_service_get_mc_latency
++ *
++ * Get memory controller latency
++ */
++uint32_t dal_adapter_service_get_mc_latency(
++ struct adapter_service *as)
++{
++ return as->asic_cap->data[ASIC_DATA_MC_LATENCY];
++}
++
++/*
++ * dal_adapter_service_get_asic_vram_bit_width
++ *
++ * Get the video RAM bit width set on the ASIC
++ */
++uint32_t dal_adapter_service_get_asic_vram_bit_width(
++ struct adapter_service *as)
++{
++ return as->asic_cap->data[ASIC_DATA_VRAM_BITWIDTH];
++}
++
++/*
++ * dal_adapter_service_get_asic_bugs
++ *
++ * Get the bug flags set on this ASIC
++ */
++struct asic_bugs dal_adapter_service_get_asic_bugs(
++ struct adapter_service *as)
++{
++ return as->asic_cap->bugs;
++}
++
++
++struct dal_asic_runtime_flags dal_adapter_service_get_asic_runtime_flags(
++ struct adapter_service *as)
++{
++ return as->asic_cap->runtime_flags;
++}
++
++/*
++ * dal_adapter_service_get_line_buffer_size
++ *
++ * Get line buffer size
++ */
++uint32_t dal_adapter_service_get_line_buffer_size(
++ struct adapter_service *as)
++{
++ return as->asic_cap->data[ASIC_DATA_LINEBUFFER_SIZE];
++}
++
++/*
++ * dal_adapter_service_get_bandwidth_tuning_params
++ *
++ * Get parameters for bandwidth tuning
++ */
++bool dal_adapter_service_get_bandwidth_tuning_params(
++ struct adapter_service *as,
++ union bandwidth_tuning_params *params)
++{
++ /* TODO: add implementation */
++ /* note: data comes from runtime parameters */
++ return false;
++}
++
++/*
++ * dal_adapter_service_get_feature_flags
++ *
++ * Get a copy of ASIC feature flags
++ */
++struct asic_feature_flags dal_adapter_service_get_feature_flags(
++ struct adapter_service *as)
++{
++ struct asic_feature_flags result = { { 0 } };
++
++ if (!as) {
++ ASSERT_CRITICAL(false);
++ return result;
++ }
++
++ result.raw = as->asic_cap->data[ASIC_DATA_FEATURE_FLAGS];
++
++ return result;
++}
++
++/*
++ * dal_adapter_service_get_dram_bandwidth_efficiency
++ *
++ * Get efficiency of DRAM
++ */
++uint32_t dal_adapter_service_get_dram_bandwidth_efficiency(
++ struct adapter_service *as)
++{
++ return as->asic_cap->data[ASIC_DATA_DRAM_BANDWIDTH_EFFICIENCY];
++}
++
++/*
++ * dal_adapter_service_obtain_gpio
++ *
++ * Obtain GPIO
++ */
++struct gpio *dal_adapter_service_obtain_gpio(
++ struct adapter_service *as,
++ enum gpio_id id,
++ uint32_t en)
++{
++ return dal_gpio_service_create_gpio_ex(
++ as->gpio_service, id, en,
++ GPIO_PIN_OUTPUT_STATE_DEFAULT);
++}
++
++/*
++ * dal_adapter_service_obtain_stereo_gpio
++ *
++ * Obtain GPIO for stereo3D
++ */
++struct gpio *dal_adapter_service_obtain_stereo_gpio(
++ struct adapter_service *as)
++{
++ const bool have_param_stereo_gpio = false;
++
++ struct asic_feature_flags result;
++
++ result.raw = as->asic_cap->data[ASIC_DATA_FEATURE_FLAGS];
++
++ /* Case 1 : Workstation stereo */
++ if (result.bits.WORKSTATION_STEREO)
++ /* "active low" <--> "default 3d right eye polarity" = false */
++ return dal_gpio_service_create_gpio_ex(
++ as->gpio_service, GPIO_ID_GENERIC, GPIO_GENERIC_A,
++ GPIO_PIN_OUTPUT_STATE_ACTIVE_LOW);
++ /* Case 2 : runtime parameter override for sideband stereo */
++ else if (have_param_stereo_gpio) {
++ /* TODO implement */
++ return NULL;
++ /* Case 3 : VBIOS gives us GPIO for sideband stereo */
++ } else {
++ const struct graphics_object_id id =
++ dal_graphics_object_id_init(
++ GENERIC_ID_STEREO,
++ ENUM_ID_1,
++ OBJECT_TYPE_GENERIC);
++
++ struct bp_gpio_cntl_info cntl_info;
++ struct gpio_pin_info pin_info;
++
++ /* Get GPIO record for this object.
++ * Stereo GPIO record should have exactly one entry
++ * where active state defines stereosync polarity */
++ if (1 != dal_bios_parser_get_gpio_record(
++ as->bios_parser, id, &cntl_info, 1)) {
++ return NULL;
++ } else if (BP_RESULT_OK != dal_bios_parser_get_gpio_pin_info(
++ as->bios_parser, cntl_info.id, &pin_info)) {
++ /*ASSERT_CRITICAL(false);*/
++ return NULL;
++ } else
++ return dal_gpio_service_create_gpio_ex(
++ as->gpio_service,
++ pin_info.offset, pin_info.mask,
++ cntl_info.state);
++ }
++}
++
++/*
++ * dal_adapter_service_release_gpio
++ *
++ * Release GPIO
++ */
++void dal_adapter_service_release_gpio(
++ struct adapter_service *as,
++ struct gpio *gpio)
++{
++ dal_gpio_service_destroy_gpio(&gpio);
++}
++
++/*
++ * dal_adapter_service_get_firmware_info
++ *
++ * Get firmware information from BIOS
++ */
++bool dal_adapter_service_get_firmware_info(
++ struct adapter_service *as,
++ struct firmware_info *info)
++{
++ return dal_bios_parser_get_firmware_info(as->bios_parser, info) ==
++ BP_RESULT_OK;
++}
++
++/*
++ * dal_adapter_service_get_audio_support
++ *
++ * Get information on audio support
++ */
++union audio_support dal_adapter_service_get_audio_support(
++ struct adapter_service *as)
++{
++ return dal_adapter_service_hw_ctx_get_audio_support(as->hw_ctx);
++}
++
++/*
++ * dal_adapter_service_get_stream_engines_num
++ *
++ * Get number of stream engines
++ */
++uint8_t dal_adapter_service_get_stream_engines_num(
++ struct adapter_service *as)
++{
++ return as->asic_cap->data[ASIC_DATA_DIGFE_NUM];
++}
++
++/*
++ * dal_adapter_service_get_feature_value
++ *
++ * Get the cached value of a given feature. This value can be a boolean, int,
++ * or characters.
++ */
++bool dal_adapter_service_get_feature_value(
++ const enum adapter_feature_id feature_id,
++ void *data,
++ uint32_t size)
++{
++ uint32_t entry_idx = 0;
++ uint32_t set_idx = 0;
++ uint32_t set_internal_idx = 0;
++
++ if (feature_id >= FEATURE_MAXIMUM || feature_id <= FEATURE_UNKNOWN) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ if (data == NULL) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ entry_idx = lookup_feature_entry(feature_id);
++ set_idx = (uint32_t)((feature_id - 1)/32);
++ set_internal_idx = (uint32_t)((feature_id - 1) % 32);
++
++ if (entry_idx >= get_feature_entries_num()) {
++ /* Cannot find this entry */
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ if (feature_entry_table[entry_idx].is_boolean_type) {
++ if (size != sizeof(bool)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ *(bool *)data = get_bool_value(adapter_feature_set[set_idx],
++ set_internal_idx);
++ } else {
++ if (size != sizeof(uint32_t)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ *(uint32_t *)data = adapter_feature_set[set_idx];
++ }
++
++ return true;
++}
++
++/*
++ * dal_adapter_service_get_memory_type_multiplier
++ *
++ * Get multiplier for the memory type
++ */
++uint32_t dal_adapter_service_get_memory_type_multiplier(
++ struct adapter_service *as)
++{
++ return as->asic_cap->data[ASIC_DATA_MEMORYTYPE_MULTIPLIER];
++}
++
++/*
++ * dal_adapter_service_get_bios_parser
++ *
++ * Get BIOS parser handler
++ */
++struct bios_parser *dal_adapter_service_get_bios_parser(
++ struct adapter_service *as)
++{
++ return as->bios_parser;
++}
++
++/*
++ * dal_adapter_service_get_i2caux
++ *
++ * Get i2c aux handler
++ */
++struct i2caux *dal_adapter_service_get_i2caux(
++ struct adapter_service *as)
++{
++ return as->i2caux;
++}
++
++bool dal_adapter_service_initialize_hw_data(
++ struct adapter_service *as)
++{
++ return as->hw_ctx->funcs->power_up(as->hw_ctx);
++}
++
++struct graphics_object_id dal_adapter_service_enum_fake_path_resource(
++ struct adapter_service *as,
++ uint32_t index)
++{
++ return as->hw_ctx->funcs->enum_fake_path_resource(as->hw_ctx, index);
++}
++
++struct graphics_object_id dal_adapter_service_enum_stereo_sync_object(
++ struct adapter_service *as,
++ uint32_t index)
++{
++ return as->hw_ctx->funcs->enum_stereo_sync_object(as->hw_ctx, index);
++}
++
++struct graphics_object_id dal_adapter_service_enum_sync_output_object(
++ struct adapter_service *as,
++ uint32_t index)
++{
++ return as->hw_ctx->funcs->enum_sync_output_object(as->hw_ctx, index);
++}
++
++struct graphics_object_id dal_adapter_service_enum_audio_object(
++ struct adapter_service *as,
++ uint32_t index)
++{
++ return as->hw_ctx->funcs->enum_audio_object(as->hw_ctx, index);
++}
++
++
++void dal_adapter_service_update_audio_connectivity(
++ struct adapter_service *as,
++ uint32_t number_of_audio_capable_display_path)
++{
++ as->hw_ctx->funcs->update_audio_connectivity(
++ as->hw_ctx,
++ number_of_audio_capable_display_path,
++ dal_adapter_service_get_controllers_num(as));
++}
++
++bool dal_adapter_service_has_embedded_display_connector(
++ struct adapter_service *as)
++{
++ uint8_t index;
++ uint8_t num_connectors = dal_adapter_service_get_connectors_num(as);
++
++ if (num_connectors == 0 || num_connectors > ENUM_ID_COUNT)
++ return false;
++
++ for (index = 0; index < num_connectors; index++) {
++ struct graphics_object_id obj_id =
++ dal_adapter_service_get_connector_obj_id(as, index);
++ enum connector_id connector_id =
++ dal_graphics_object_id_get_connector_id(obj_id);
++
++ if ((connector_id == CONNECTOR_ID_LVDS) ||
++ (connector_id == CONNECTOR_ID_EDP))
++ return true;
++ }
++
++ return false;
++}
++
++bool dal_adapter_service_get_embedded_panel_info(
++ struct adapter_service *as,
++ struct embedded_panel_info *info)
++{
++ enum bp_result result;
++
++ if (info == NULL)
++ /*TODO: add DALASSERT_MSG here*/
++ return false;
++
++ result = dal_bios_parser_get_embedded_panel_info(
++ as->bios_parser, info);
++
++ return result == BP_RESULT_OK;
++}
++
++bool dal_adapter_service_enum_embedded_panel_patch_mode(
++ struct adapter_service *as,
++ uint32_t index,
++ struct embedded_panel_patch_mode *mode)
++{
++ enum bp_result result;
++
++ if (mode == NULL)
++ /*TODO: add DALASSERT_MSG here*/
++ return false;
++
++ result = dal_bios_parser_enum_embedded_panel_patch_mode(
++ as->bios_parser, index, mode);
++
++ return result == BP_RESULT_OK;
++}
++
++bool dal_adapter_service_get_faked_edid_len(
++ struct adapter_service *as,
++ uint32_t *len)
++{
++ enum bp_result result;
++
++ result = dal_bios_parser_get_faked_edid_len(
++ as->bios_parser,
++ len);
++ return result == BP_RESULT_OK;
++}
++
++bool dal_adapter_service_get_faked_edid_buf(
++ struct adapter_service *as,
++ uint8_t *buf,
++ uint32_t len)
++{
++ enum bp_result result;
++
++ result = dal_bios_parser_get_faked_edid_buf(
++ as->bios_parser,
++ buf,
++ len);
++ return result == BP_RESULT_OK;
++
++}
++
++/*
++ * dal_adapter_service_is_fusion
++ *
++ * Is this Fusion ASIC
++ */
++bool dal_adapter_service_is_fusion(struct adapter_service *as)
++{
++ return as->asic_cap->caps.IS_FUSION;
++}
++
++/*
++ * dal_adapter_service_is_dfsbyass_dynamic
++ *
++ *
++ **/
++bool dal_adapter_service_is_dfsbyass_dynamic(struct adapter_service *as)
++{
++ return as->asic_cap->caps.DFSBYPASS_DYNAMIC_SUPPORT;
++}
++
++/*
++ * dal_adapter_service_should_optimize
++ *
++ * @brief Reports whether driver settings allow requested optimization
++ *
++ * @param
++ * as: adapter service handler
++ * feature: for which optimization is validated
++ *
++ * @return
++ * true if requested feature can be optimized
++ */
++bool dal_adapter_service_should_optimize(
++ struct adapter_service *as, enum optimization_feature feature)
++{
++ uint32_t supported_optimization = 0;
++ struct dal_asic_runtime_flags flags;
++
++ if (!dal_adapter_service_get_feature_value(FEATURE_OPTIMIZATION,
++ &supported_optimization, sizeof(uint32_t)))
++ return false;
++
++ /* Retrieve ASIC runtime flags */
++ flags = dal_adapter_service_get_asic_runtime_flags(as);
++
++ /* Check runtime flags against different optimization features */
++ switch (feature) {
++ case OF_SKIP_HW_PROGRAMMING_ON_ENABLED_EMBEDDED_DISPLAY:
++ if (!flags.flags.bits.OPTIMIZED_DISPLAY_PROGRAMMING_ON_BOOT)
++ return false;
++ break;
++
++ case OF_SKIP_RESET_OF_ALL_HW_ON_S3RESUME:
++ if (as->integrated_info == NULL ||
++ !flags.flags.bits.SKIP_POWER_DOWN_ON_RESUME)
++ return false;
++ break;
++ case OF_SKIP_POWER_DOWN_INACTIVE_ENCODER:
++ if (!dal_adapter_service_get_asic_runtime_flags(as).flags.bits.
++ SKIP_POWER_DOWN_ON_RESUME)
++ return false;
++ break;
++ default:
++ break;
++ }
++
++ return (supported_optimization & feature) != 0;
++}
++
++/*
++ * dal_adapter_service_is_in_accelerated_mode
++ *
++ * @brief Determine if driver is in accelerated mode
++ *
++ * @param
++ * as: Adapter Service handler
++ *
++ * @out
++ * True if driver is in accelerated mode, false otherwise.
++ */
++bool dal_adapter_service_is_in_accelerated_mode(struct adapter_service *as)
++{
++ return dal_bios_parser_is_accelerated_mode(as->bios_parser);
++}
++
++struct ddc *dal_adapter_service_obtain_ddc_from_i2c_info(
++ struct adapter_service *as,
++ struct graphics_object_i2c_info *info)
++{
++ struct gpio_ddc_hw_info hw_info = {
++ info->i2c_hw_assist,
++ info->i2c_line };
++ return dal_gpio_service_create_ddc(as->gpio_service,
++ info->gpio_info.clk_a_register_index,
++ (1 << info->gpio_info.clk_a_shift), &hw_info);
++}
++
++struct bdf_info dal_adapter_service_get_adapter_info(struct adapter_service *as)
++{
++ return as->bdf_info;
++}
++
++/*
++ * dal_adapter_service_should_psr_skip_wait_for_pll_lock
++ *
++ * @brief Determine if this ASIC needs to wait on PLL lock bit
++ *
++ * @param
++ * as: Adapter Service handle
++ *
++ * @out
++ * True if ASIC does not need to wait for PLL lock bit, i.e. skip the wait.
++ */
++bool dal_adapter_service_should_psr_skip_wait_for_pll_lock(
++ struct adapter_service *as)
++{
++ return as->asic_cap->caps.SKIP_PSR_WAIT_FOR_PLL_LOCK_BIT;
++}
++
++bool dal_adapter_service_is_lid_open(struct adapter_service *as)
++{
++ bool is_lid_open = false;
++ struct platform_info_params params;
++
++ params.data = &is_lid_open;
++ params.method = PM_GET_LID_STATE;
++
++ if ((PM_GET_LID_STATE & as->platform_methods_mask) &&
++ dal_get_platform_info(as->ctx, &params))
++ return is_lid_open;
++
++#if defined(CONFIG_DRM_AMD_DAL_VBIOS_PRESENT)
++ return dal_bios_parser_is_lid_open(as->bios_parser);
++#else
++ return false;
++#endif
++}
++
++bool dal_adapter_service_get_panel_backlight_default_levels(
++ struct adapter_service *as,
++ struct panel_backlight_levels *levels)
++{
++ if (!as->backlight_caps_initialized)
++ return false;
++
++ levels->ac_level_percentage = as->ac_level_percentage;
++ levels->dc_level_percentage = as->dc_level_percentage;
++ return true;
++}
++
++bool dal_adapter_service_get_panel_backlight_boundaries(
++ struct adapter_service *as,
++ struct panel_backlight_boundaries *boundaries)
++{
++ if (!as->backlight_caps_initialized)
++ return false;
++ if (boundaries != NULL) {
++ boundaries->min_signal_level = as->backlight_8bit_lut[0];
++ boundaries->max_signal_level =
++ as->backlight_8bit_lut[SIZEOF_BACKLIGHT_LUT - 1];
++ return true;
++ }
++ return false;
++}
++
++
++uint32_t dal_adapter_service_get_view_port_pixel_granularity(
++ struct adapter_service *as)
++{
++ return as->asic_cap->data[ASIC_DATA_VIEWPORT_PIXEL_GRANULARITY];
++}
++
++/**
++ * Get number of paths per DP 1.2 connector from the runtime parameter if it
++ * exists.
++ * A check to see if MST is supported for the generation of ASIC is done
++ *
++ * \return
++ * Number of paths per DP 1.2 connector is exists in runtime parameters
++ * or ASIC cap
++ */
++uint32_t dal_adapter_service_get_num_of_path_per_dp_mst_connector(
++ struct adapter_service *as)
++{
++ if (as->asic_cap->caps.DP_MST_SUPPORTED == 0) {
++ /* ASIC doesn't support DP MST at all */
++ return 0;
++ }
++
++ return as->asic_cap->data[ASIC_DATA_PATH_NUM_PER_DPMST_CONNECTOR];
++}
++
++uint32_t dal_adapter_service_get_num_of_underlays(
++ struct adapter_service *as)
++{
++ return as->asic_cap->data[ASIC_DATA_NUM_OF_VIDEO_PLANES];
++}
++
++bool dal_adapter_service_get_encoder_cap_info(
++ struct adapter_service *as,
++ struct graphics_object_id id,
++ struct graphics_object_encoder_cap_info *info)
++{
++ struct bp_encoder_cap_info bp_cap_info = {0};
++ enum bp_result result;
++
++ if (NULL == info) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ /*
++ * Retrieve Encoder Capability Information from VBIOS and store the
++ * call result (success or fail)
++ * Info from VBIOS about HBR2 has two fields:
++ *
++ * - dpHbr2Cap: indicates supported/not supported by HW Encoder
++ * - dpHbr2En : indicates DP spec compliant/not compliant
++ */
++ result = dal_bios_parser_get_encoder_cap_info(
++ as->bios_parser,
++ id,
++ &bp_cap_info);
++
++ /* Set dp_hbr2_validated flag (it's equal to Enable) */
++ info->dp_hbr2_validated = bp_cap_info.DP_HBR2_EN;
++
++ if (result == BP_RESULT_OK) {
++ info->dp_hbr2_cap = bp_cap_info.DP_HBR2_CAP;
++ return true;
++ }
++
++ return false;
++}
++
++bool dal_adapter_service_is_mc_tuning_req(struct adapter_service *as)
++{
++ return as->asic_cap->caps.NEED_MC_TUNING ? true : false;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.h b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.h
+new file mode 100644
+index 0000000..25ac648
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/adapter_service.h
+@@ -0,0 +1,67 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DAL_ADAPTER_SERVICE_H__
++#define __DAL_ADAPTER_SERVICE_H__
++
++/* Include */
++#include "include/adapter_service_interface.h"
++#include "wireless_data_source.h"
++
++/*
++ * Forward declaration
++ */
++struct gpio_service;
++struct asic_cap;
++
++/* Adapter service */
++struct adapter_service {
++ struct dc_context *ctx;
++ struct asic_capability *asic_cap;
++ struct bios_parser *bios_parser;
++ struct gpio_service *gpio_service;
++ struct i2caux *i2caux;
++ struct wireless_data wireless_data;
++ struct hw_ctx_adapter_service *hw_ctx;
++ struct integrated_info *integrated_info;
++ struct bdf_info bdf_info;
++ uint32_t platform_methods_mask;
++ uint32_t ac_level_percentage;
++ uint32_t dc_level_percentage;
++ uint32_t backlight_caps_initialized;
++ uint32_t backlight_8bit_lut[SIZEOF_BACKLIGHT_LUT];
++};
++
++/* Type of feature with its runtime parameter and default value */
++struct feature_source_entry {
++ enum adapter_feature_id feature_id;
++ uint32_t default_value;
++ bool is_boolean_type;
++};
++
++/* Stores entire ASIC features by sets */
++extern uint32_t adapter_feature_set[];
++
++#endif /* __DAL_ADAPTER_SERVICE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/dce110/hw_ctx_adapter_service_dce110.c b/drivers/gpu/drm/amd/dal/dc/adapter/dce110/hw_ctx_adapter_service_dce110.c
+new file mode 100644
+index 0000000..31c2aab
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/dce110/hw_ctx_adapter_service_dce110.c
+@@ -0,0 +1,303 @@
++/*
++ * 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 "dal_services.h"
++#include "../hw_ctx_adapter_service.h"
++
++#include "hw_ctx_adapter_service_dce110.h"
++
++#include "include/logger_interface.h"
++#include "include/grph_object_id.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#ifndef mmCC_DC_HDMI_STRAPS
++#define mmCC_DC_HDMI_STRAPS 0x4819
++#define CC_DC_HDMI_STRAPS__HDMI_DISABLE_MASK 0x40
++#define CC_DC_HDMI_STRAPS__HDMI_DISABLE__SHIFT 0x6
++#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER_MASK 0x700
++#define CC_DC_HDMI_STRAPS__AUDIO_STREAM_NUMBER__SHIFT 0x8
++#endif
++
++static const struct graphics_object_id invalid_go = {
++ 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN, 0
++};
++
++/* Macro */
++#define AUDIO_STRAPS_HDMI_ENABLE 0x2
++
++#define FROM_HW_CTX(ptr) \
++ container_of((ptr), struct hw_ctx_adapter_service_dce110, base)
++
++static const uint32_t audio_index_reg_offset[] = {
++ /*CZ has 3 DIGs but 4 audio endpoints*/
++ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_INDEX
++};
++
++static const uint32_t audio_data_reg_offset[] = {
++ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA,
++ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_DATA,
++ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_DATA,
++ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_DATA,
++};
++
++enum {
++ MAX_NUMBER_OF_AUDIO_PINS = 4
++};
++
++static void destruct(
++ struct hw_ctx_adapter_service_dce110 *hw_ctx)
++{
++ /* There is nothing to destruct at the moment */
++ dal_adapter_service_destruct_hw_ctx(&hw_ctx->base);
++}
++
++static void destroy(
++ struct hw_ctx_adapter_service *ptr)
++{
++ struct hw_ctx_adapter_service_dce110 *hw_ctx =
++ FROM_HW_CTX(ptr);
++
++ destruct(hw_ctx);
++
++ dc_service_free(ptr->ctx, hw_ctx);
++}
++
++/*
++ * enum_audio_object
++ *
++ * @brief enumerate audio object
++ *
++ * @param
++ * const struct hw_ctx_adapter_service *hw_ctx - [in] provides num of endpoints
++ * uint32_t index - [in] audio index
++ *
++ * @return
++ * grphic object id
++ */
++static struct graphics_object_id enum_audio_object(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index)
++{
++ uint32_t number_of_connected_audio_endpoints =
++ FROM_HW_CTX(hw_ctx)->number_of_connected_audio_endpoints;
++
++ if (index >= number_of_connected_audio_endpoints ||
++ number_of_connected_audio_endpoints == 0)
++ return invalid_go;
++ else
++ return dal_graphics_object_id_init(
++ AUDIO_ID_INTERNAL_AZALIA,
++ (enum object_enum_id)(index + 1),
++ OBJECT_TYPE_AUDIO);
++}
++
++static uint32_t get_number_of_connected_audio_endpoints_multistream(
++ struct dc_context *ctx)
++{
++ uint32_t num_connected_audio_endpoints = 0;
++ uint32_t i;
++ uint32_t default_config =
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT;
++
++ /* find the total number of streams available via the
++ * AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT
++ * registers (one for each pin) starting from pin 1
++ * up to the max number of audio pins.
++ * We stop on the first pin where
++ * PORT_CONNECTIVITY == 1 (as instructed by HW team).
++ */
++ for (i = 0; i < MAX_NUMBER_OF_AUDIO_PINS; i++) {
++ uint32_t value = 0;
++
++ set_reg_field_value(value,
++ default_config,
++ AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ AZALIA_ENDPOINT_REG_INDEX);
++
++ dal_write_reg(ctx, audio_index_reg_offset[i], value);
++
++ value = 0;
++ value = dal_read_reg(ctx, audio_data_reg_offset[i]);
++
++ /* 1 means not supported*/
++ if (get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_CONFIGURATION_DEFAULT,
++ PORT_CONNECTIVITY) == 1)
++ break;
++
++ num_connected_audio_endpoints++;
++ }
++
++ return num_connected_audio_endpoints;
++
++}
++
++/*
++ * get_number_of_connected_audio_endpoints
++ */
++static uint32_t get_number_of_connected_audio_endpoints(
++ struct hw_ctx_adapter_service *hw_ctx)
++{
++ uint32_t addr = mmCC_DC_HDMI_STRAPS;
++ uint32_t value = 0;
++ uint32_t field = 0;
++
++ if (hw_ctx->cached_audio_straps == AUDIO_STRAPS_NOT_ALLOWED)
++ /* audio straps indicate no audio supported */
++ return 0;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ field = get_reg_field_value(
++ value, CC_DC_HDMI_STRAPS, AUDIO_STREAM_NUMBER);
++ if (field == 1)
++ /* multi streams not supported */
++ return 1;
++ else if (field == 0)
++ /* multi streams supported */
++ return get_number_of_connected_audio_endpoints_multistream(
++ hw_ctx->ctx);
++
++ /* unexpected value */
++ ASSERT_CRITICAL(false);
++ return field;
++}
++
++
++/*
++ * power_up
++ *
++ * @brief
++ * Determine and cache audio support from register.
++ *
++ * @param
++ * struct hw_ctx_adapter_service *hw_ctx - [in] adapter service hw context
++ *
++ * @return
++ * true if succeed, false otherwise
++ */
++static bool power_up(
++ struct hw_ctx_adapter_service *hw_ctx)
++{
++ struct hw_ctx_adapter_service_dce110 *hw_ctx_dce11 =
++ FROM_HW_CTX(hw_ctx);
++ /* Allow DP audio all the time
++ * without additional pinstrap check on Fusion */
++
++
++ {
++ uint32_t value = 0;
++ uint32_t field = 0;
++
++ value = dal_read_reg(hw_ctx->ctx, mmCC_DC_HDMI_STRAPS);
++ field = get_reg_field_value(
++ value, CC_DC_HDMI_STRAPS, HDMI_DISABLE);
++
++ if (field == 0) {
++ hw_ctx->cached_audio_straps = AUDIO_STRAPS_DP_HDMI_AUDIO;
++ } else {
++ value = dal_read_reg(
++ hw_ctx->ctx, mmDC_PINSTRAPS);
++ field = get_reg_field_value(
++ value,
++ DC_PINSTRAPS,
++ DC_PINSTRAPS_AUDIO);
++
++ if (field & AUDIO_STRAPS_HDMI_ENABLE)
++ hw_ctx->cached_audio_straps =
++ AUDIO_STRAPS_DP_HDMI_AUDIO_ON_DONGLE;
++ else
++ hw_ctx->cached_audio_straps =
++ AUDIO_STRAPS_DP_AUDIO_ALLOWED;
++ }
++
++ }
++
++ /* get the number of connected audio endpoints */
++ hw_ctx_dce11->number_of_connected_audio_endpoints =
++ get_number_of_connected_audio_endpoints(hw_ctx);
++
++ return true;
++}
++
++static void update_audio_connectivity(
++ struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t number_of_audio_capable_display_path,
++ uint32_t number_of_controllers)
++{
++ /* this one should be empty on DCE110 */
++}
++
++static const struct hw_ctx_adapter_service_funcs funcs = {
++ .destroy = destroy,
++ .power_up = power_up,
++ .enum_fake_path_resource = NULL,
++ .enum_stereo_sync_object = NULL,
++ .enum_sync_output_object = NULL,
++ .enum_audio_object = enum_audio_object,
++ .update_audio_connectivity = update_audio_connectivity
++};
++
++static bool construct(
++ struct hw_ctx_adapter_service_dce110 *hw_ctx,
++ struct dc_context *ctx)
++{
++ if (!dal_adapter_service_construct_hw_ctx(&hw_ctx->base, ctx)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ hw_ctx->base.funcs = &funcs;
++ hw_ctx->number_of_connected_audio_endpoints = 0;
++
++ return true;
++}
++
++struct hw_ctx_adapter_service *
++ dal_adapter_service_create_hw_ctx_dce110(
++ struct dc_context *ctx)
++{
++ struct hw_ctx_adapter_service_dce110 *hw_ctx =
++ dc_service_alloc(ctx, sizeof(struct hw_ctx_adapter_service_dce110));
++
++ if (!hw_ctx) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (construct(hw_ctx, ctx))
++ return &hw_ctx->base;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(ctx, hw_ctx);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/dce110/hw_ctx_adapter_service_dce110.h b/drivers/gpu/drm/amd/dal/dc/adapter/dce110/hw_ctx_adapter_service_dce110.h
+new file mode 100644
+index 0000000..092b671
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/dce110/hw_ctx_adapter_service_dce110.h
+@@ -0,0 +1,40 @@
++/*
++ * 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_HW_CTX_ADAPTER_SERVICE_DCE110_H__
++#define __DAL_HW_CTX_ADAPTER_SERVICE_DCE110_H__
++
++struct hw_ctx_adapter_service_dce110 {
++ struct hw_ctx_adapter_service base;
++ uint32_t number_of_connected_audio_endpoints;
++};
++
++struct hw_ctx_adapter_service *
++ dal_adapter_service_create_hw_ctx_dce110(
++ struct dc_context *ctx);
++
++#endif /* __DAL_HW_CTX_ADAPTER_SERVICE_DCE110_H__ */
++
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/hw_ctx_adapter_service.c b/drivers/gpu/drm/amd/dal/dc/adapter/hw_ctx_adapter_service.c
+new file mode 100644
+index 0000000..5fa886f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/hw_ctx_adapter_service.c
+@@ -0,0 +1,164 @@
++/*
++ * 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 "dal_services.h"
++#include "include/adapter_service_types.h"
++#include "include/grph_object_id.h"
++#include "hw_ctx_adapter_service.h"
++
++static const struct graphics_object_id invalid_go = {
++ 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN
++};
++
++static void destroy(
++ struct hw_ctx_adapter_service *hw_ctx)
++{
++ /* Attention!
++ * You must override impl method in derived class */
++ BREAK_TO_DEBUGGER();
++}
++
++static bool power_up(
++ struct hw_ctx_adapter_service *hw_ctx)
++{
++ /* Attention!
++ * You must override impl method in derived class */
++ BREAK_TO_DEBUGGER();
++
++ return false;
++}
++
++static struct graphics_object_id enum_fake_path_resource(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index)
++{
++ return invalid_go;
++}
++
++static struct graphics_object_id enum_stereo_sync_object(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index)
++{
++ return invalid_go;
++}
++
++static struct graphics_object_id enum_sync_output_object(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index)
++{
++ return invalid_go;
++}
++
++static struct graphics_object_id enum_audio_object(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index)
++{
++ /* by default, we only allow one audio */
++
++ if (index > 0)
++ return invalid_go;
++ else if (hw_ctx->cached_audio_straps == AUDIO_STRAPS_NOT_ALLOWED)
++ return invalid_go;
++ else
++ return dal_graphics_object_id_init(
++ AUDIO_ID_INTERNAL_AZALIA,
++ ENUM_ID_1,
++ OBJECT_TYPE_AUDIO);
++}
++
++static void update_audio_connectivity(
++ struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t number_of_audio_capable_display_path,
++ uint32_t number_of_controllers)
++{
++ /* Attention!
++ * You must override impl method in derived class */
++ BREAK_TO_DEBUGGER();
++}
++
++static const struct hw_ctx_adapter_service_funcs funcs = {
++ destroy,
++ power_up,
++ enum_fake_path_resource,
++ enum_stereo_sync_object,
++ enum_sync_output_object,
++ enum_audio_object,
++ update_audio_connectivity
++};
++
++bool dal_adapter_service_construct_hw_ctx(
++ struct hw_ctx_adapter_service *hw_ctx,
++ struct dc_context *ctx)
++{
++
++ hw_ctx->ctx = ctx;
++ hw_ctx->funcs = &funcs;
++ hw_ctx->cached_audio_straps = AUDIO_STRAPS_NOT_ALLOWED;
++
++ return true;
++}
++
++union audio_support dal_adapter_service_hw_ctx_get_audio_support(
++ const struct hw_ctx_adapter_service *hw_ctx)
++{
++ union audio_support result;
++
++ result.raw = 0;
++
++ switch (hw_ctx->cached_audio_straps) {
++ case AUDIO_STRAPS_DP_HDMI_AUDIO:
++ result.bits.HDMI_AUDIO_NATIVE = true;
++ /* do not break ! */
++ case AUDIO_STRAPS_DP_HDMI_AUDIO_ON_DONGLE:
++ result.bits.HDMI_AUDIO_ON_DONGLE = true;
++ /* do not break ! */
++ case AUDIO_STRAPS_DP_AUDIO_ALLOWED:
++ result.bits.DP_AUDIO = true;
++ break;
++ default:
++ break;
++ }
++
++ return result;
++}
++
++void dal_adapter_service_destruct_hw_ctx(
++ struct hw_ctx_adapter_service *hw_ctx)
++{
++ /* There is nothing to destruct at the moment */
++}
++
++void dal_adapter_service_destroy_hw_ctx(
++ struct hw_ctx_adapter_service **ptr)
++{
++ if (!ptr || !*ptr) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ (*ptr)->funcs->destroy(*ptr);
++
++ *ptr = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/hw_ctx_adapter_service.h b/drivers/gpu/drm/amd/dal/dc/adapter/hw_ctx_adapter_service.h
+new file mode 100644
+index 0000000..f98c2d4
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/hw_ctx_adapter_service.h
+@@ -0,0 +1,86 @@
++/*
++ * 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_HW_CTX_ADAPTER_SERVICE_H__
++#define __DAL_HW_CTX_ADAPTER_SERVICE_H__
++
++enum audio_straps {
++ AUDIO_STRAPS_NOT_ALLOWED = 0,
++ AUDIO_STRAPS_DP_AUDIO_ALLOWED,
++ AUDIO_STRAPS_DP_HDMI_AUDIO_ON_DONGLE,
++ AUDIO_STRAPS_DP_HDMI_AUDIO
++};
++
++struct hw_ctx_adapter_service;
++
++struct hw_ctx_adapter_service_funcs {
++ void (*destroy)(
++ struct hw_ctx_adapter_service *hw_ctx);
++ /* Initializes relevant HW registers
++ * and caches relevant data from HW registers */
++ bool (*power_up)(
++ struct hw_ctx_adapter_service *hw_ctx);
++ /* Enumerate fake path resources */
++ struct graphics_object_id (*enum_fake_path_resource)(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index);
++ /* Enumerate stereo sync objects */
++ struct graphics_object_id (*enum_stereo_sync_object)(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index);
++ /* Enumerate (H/V) sync output objects */
++ struct graphics_object_id (*enum_sync_output_object)(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index);
++ /* Enumerate audio objects */
++ struct graphics_object_id (*enum_audio_object)(
++ const struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t index);
++ void (*update_audio_connectivity)(
++ struct hw_ctx_adapter_service *hw_ctx,
++ uint32_t number_of_audio_capable_display_path,
++ uint32_t number_of_controllers);
++};
++
++struct hw_ctx_adapter_service {
++ struct dc_context *ctx;
++ const struct hw_ctx_adapter_service_funcs *funcs;
++ enum audio_straps cached_audio_straps;
++};
++
++bool dal_adapter_service_construct_hw_ctx(
++ struct hw_ctx_adapter_service *hw_ctx,
++ struct dc_context *ctx);
++
++union audio_support dal_adapter_service_hw_ctx_get_audio_support(
++ const struct hw_ctx_adapter_service *hw_ctx);
++
++void dal_adapter_service_destruct_hw_ctx(
++ struct hw_ctx_adapter_service *hw_ctx);
++
++void dal_adapter_service_destroy_hw_ctx(
++ struct hw_ctx_adapter_service **ptr);
++
++#endif /* __DAL_HW_CTX_ADAPTER_SERVICE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/wireless_data_source.c b/drivers/gpu/drm/amd/dal/dc/adapter/wireless_data_source.c
+new file mode 100644
+index 0000000..dcb885d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/wireless_data_source.c
+@@ -0,0 +1,209 @@
++/*
++ * 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 "dal_services.h"
++#include "adapter_service.h"
++#include "wireless_data_source.h"
++
++#include "atom.h"
++
++/*construct wireless data*/
++bool wireless_data_init(struct wireless_data *data,
++ struct bios_parser *bp,
++ struct wireless_init_data *init_data)
++{
++ struct firmware_info info;
++
++ if (data == NULL || bp == NULL || init_data == NULL) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ data->miracast_connector_enable = false;
++ data->wireless_disp_path_enable = false;
++ data->wireless_enable = false;
++
++ /* Wireless it not supported if VCE is not supported */
++ if (!init_data->vce_supported)
++ return true;
++
++ if (init_data->miracast_target_required)
++ data->miracast_connector_enable = true;
++
++ /*
++ * If override is in place for platform support, we will both
++ * enable wireless display as a feature (i.e. CCC aspect) and
++ * enable the wireless display path without any further checks.
++ */
++ if (init_data->platform_override) {
++ data->wireless_enable = true;
++ data->wireless_disp_path_enable = true;
++ } else {
++ /*
++ * Check if SBIOS sets remote display enable, exposed
++ * through VBIOS. This is only valid for APU, not dGPU
++ */
++ dal_bios_parser_get_firmware_info(bp, &info);
++
++ if ((REMOTE_DISPLAY_ENABLE ==
++ info.remote_display_config) &&
++ init_data->fusion) {
++ data->wireless_enable = true;
++ data->wireless_disp_path_enable = true;
++ }
++ }
++
++ /*
++ * If remote display path override is enabled, we enable just the
++ * remote display path. This is mainly used for testing purposes
++ */
++ if (init_data->remote_disp_path_override)
++ data->wireless_disp_path_enable = true;
++
++ return true;
++}
++
++uint8_t wireless_get_clocks_num(
++ struct adapter_service *as)
++{
++ if (as->wireless_data.wireless_enable ||
++ as->wireless_data.wireless_disp_path_enable)
++ return 1;
++ else
++ return 0;
++}
++
++static uint8_t wireless_get_encoders_num(
++ struct adapter_service *as)
++{
++ if (as->wireless_data.wireless_enable ||
++ as->wireless_data.wireless_disp_path_enable)
++ return 1;
++ else
++ return 0;
++}
++
++uint8_t wireless_get_connectors_num(
++ struct adapter_service *as)
++{
++ uint8_t wireless_connectors_num = 0;
++
++ if (as->wireless_data.wireless_enable &&
++ as->wireless_data.miracast_connector_enable)
++ wireless_connectors_num++;
++
++ if (as->wireless_data.wireless_disp_path_enable)
++ wireless_connectors_num++;
++
++ return wireless_connectors_num;
++}
++
++struct graphics_object_id wireless_get_connector_id(
++ struct adapter_service *as,
++ uint8_t index)
++{
++ struct graphics_object_id unknown_object_id =
++ dal_graphics_object_id_init(
++ 0,
++ ENUM_ID_UNKNOWN,
++ OBJECT_TYPE_UNKNOWN);
++
++ if (!as->wireless_data.wireless_enable &&
++ !as->wireless_data.wireless_disp_path_enable)
++ return unknown_object_id;
++
++ else if (!as->wireless_data.miracast_connector_enable)
++ return dal_graphics_object_id_init(
++ CONNECTOR_ID_WIRELESS,
++ ENUM_ID_1,
++ OBJECT_TYPE_CONNECTOR);
++
++ switch (index) {
++ case 0:
++ return dal_graphics_object_id_init(
++ CONNECTOR_ID_WIRELESS,
++ ENUM_ID_1,
++ OBJECT_TYPE_CONNECTOR);
++ break;
++ case 1:
++ return dal_graphics_object_id_init(
++ CONNECTOR_ID_MIRACAST,
++ ENUM_ID_1,
++ OBJECT_TYPE_CONNECTOR);
++ break;
++ default:
++ return unknown_object_id;
++ }
++}
++
++uint8_t wireless_get_srcs_num(
++ struct adapter_service *as,
++ struct graphics_object_id id)
++{
++ switch (id.type) {
++ case OBJECT_TYPE_CONNECTOR:
++ return wireless_get_encoders_num(as);
++ case OBJECT_TYPE_ENCODER:
++ return 1;
++
++ default:
++ ASSERT_CRITICAL(false);
++ break;
++ }
++
++ return 0;
++}
++
++struct graphics_object_id wireless_get_src_obj_id(
++ struct adapter_service *as,
++ struct graphics_object_id id,
++ uint8_t index)
++{
++ if (index < wireless_get_srcs_num(as, id)) {
++ switch (id.type) {
++ case OBJECT_TYPE_CONNECTOR:
++ return dal_graphics_object_id_init(
++ ENCODER_ID_INTERNAL_WIRELESS,
++ ENUM_ID_1,
++ OBJECT_TYPE_ENCODER);
++ break;
++ case OBJECT_TYPE_ENCODER:
++ return dal_graphics_object_id_init(
++ 0,
++ ENUM_ID_1,
++ OBJECT_TYPE_GPU);
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ break;
++ }
++ }
++
++ return dal_graphics_object_id_init(
++ 0,
++ ENUM_ID_UNKNOWN,
++ OBJECT_TYPE_UNKNOWN);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/adapter/wireless_data_source.h b/drivers/gpu/drm/amd/dal/dc/adapter/wireless_data_source.h
+new file mode 100644
+index 0000000..54b140a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/adapter/wireless_data_source.h
+@@ -0,0 +1,80 @@
++/*
++ * 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_WIRELESS_DATA_SOURCE_H__
++#define __DAL_WIRELESS_DATA_SOURCE_H__
++
++/* Include */
++#include "include/grph_object_id.h"
++
++/*
++ * Forward declaration
++ */
++struct adapter_service;
++struct bios_parser;
++
++/* Wireless data init structure */
++struct wireless_init_data {
++ bool fusion; /* Fusion flag */
++ bool platform_override; /* Override for platform BIOS option */
++ bool remote_disp_path_override; /* Override enabling wireless path */
++ bool vce_supported; /* Existence of VCE block on this DCE */
++ bool miracast_target_required; /* OS requires Miracast target */
++};
++
++/* Wireless data */
++struct wireless_data {
++ bool wireless_enable;
++ bool wireless_disp_path_enable;
++ bool miracast_connector_enable;
++};
++
++
++/*construct wireless data*/
++bool wireless_data_init(
++ struct wireless_data *data,
++ struct bios_parser *bp,
++ struct wireless_init_data *init_data);
++
++uint8_t wireless_get_clocks_num(
++ struct adapter_service *as);
++
++uint8_t wireless_get_connectors_num(
++ struct adapter_service *as);
++
++struct graphics_object_id wireless_get_connector_id(
++ struct adapter_service *as,
++ uint8_t connector_index);
++
++uint8_t wireless_get_srcs_num(
++ struct adapter_service *as,
++ struct graphics_object_id id);
++
++struct graphics_object_id wireless_get_src_obj_id(
++ struct adapter_service *as,
++ struct graphics_object_id id,
++ uint8_t index);
++
++#endif /* __DAL_WIRELESS_DATA_SOURCE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile b/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
+new file mode 100644
+index 0000000..5e01a86
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/Makefile
+@@ -0,0 +1,23 @@
++#
++# Makefile for the 'asic_capability' sub-component of DAL.
++#
++
++ASIC_CAPABILITY = asic_capability.o
++
++AMD_DAL_ASIC_CAPABILITY = \
++ $(addprefix $(AMDDALPATH)/dc/asic_capability/,$(ASIC_CAPABILITY))
++
++AMD_DAL_FILES += $(AMD_DAL_ASIC_CAPABILITY)
++
++
++###############################################################################
++# DCE 11x
++###############################################################################
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++ASIC_CAPABILITY_DCE11 = carrizo_asic_capability.o
++
++AMD_DAL_ASIC_CAPABILITY_DCE11 = \
++ $(addprefix $(AMDDALPATH)/dc/asic_capability/,$(ASIC_CAPABILITY_DCE11))
++
++AMD_DAL_FILES += $(AMD_DAL_ASIC_CAPABILITY_DCE11)
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c b/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
+new file mode 100644
+index 0000000..a532e2f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/asic_capability.c
+@@ -0,0 +1,178 @@
++/*
++ * 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 "dal_services.h"
++
++#include "include/logger_interface.h"
++
++#include "include/asic_capability_interface.h"
++#include "include/asic_capability_types.h"
++#include "include/dal_types.h"
++#include "include/dal_asic_id.h"
++
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "carrizo_asic_capability.h"
++#endif
++
++/*
++ * Initializes asic_capability instance.
++ */
++static bool construct(
++ struct asic_capability *cap,
++ struct hw_asic_id *init,
++ struct dc_context *ctx)
++{
++ bool asic_supported = false;
++
++ cap->ctx = ctx;
++ dc_service_memset(cap->data, 0, sizeof(cap->data));
++
++ /* ASIC data */
++ cap->data[ASIC_DATA_VRAM_TYPE] = init->vram_type;
++ cap->data[ASIC_DATA_VRAM_BITWIDTH] = init->vram_width;
++ cap->data[ASIC_DATA_FEATURE_FLAGS] = init->feature_flags;
++ cap->runtime_flags = init->runtime_flags;
++ cap->data[ASIC_DATA_REVISION_ID] = init->hw_internal_rev;
++ cap->data[ASIC_DATA_MAX_UNDERSCAN_PERCENTAGE] = 10;
++ cap->data[ASIC_DATA_VIEWPORT_PIXEL_GRANULARITY] = 4;
++ cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM] = 1;
++ cap->data[ASIC_DATA_NUM_OF_VIDEO_PLANES] = 0;
++ cap->data[ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ] = 25;
++
++ /* ASIC basic capability */
++ cap->caps.UNDERSCAN_FOR_HDMI_ONLY = true;
++ cap->caps.SUPPORT_CEA861E_FINAL = true;
++ cap->caps.MIRABILIS_SUPPORTED = false;
++ cap->caps.MIRABILIS_ENABLED_BY_DEFAULT = false;
++ cap->caps.WIRELESS_LIMIT_TO_720P = false;
++ cap->caps.WIRELESS_FULL_TIMING_ADJUSTMENT = false;
++ cap->caps.WIRELESS_TIMING_ADJUSTMENT = true;
++ cap->caps.WIRELESS_COMPRESSED_AUDIO = false;
++ cap->caps.VCE_SUPPORTED = false;
++ cap->caps.HPD_CHECK_FOR_EDID = false;
++ cap->caps.NO_VCC_OFF_HPD_POLLING = false;
++ cap->caps.NEED_MC_TUNING = false;
++ cap->caps.SUPPORT_8BPP = true;
++
++ /* ASIC stereo 3D capability */
++ cap->stereo_3d_caps.SUPPORTED = true;
++
++ switch (init->chip_family) {
++ case FAMILY_CI:
++ break;
++
++ case FAMILY_KV:
++ if (ASIC_REV_IS_KALINDI(init->hw_internal_rev) ||
++ ASIC_REV_IS_BHAVANI(init->hw_internal_rev)) {
++ } else {
++ }
++ break;
++
++ case FAMILY_CZ:
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ carrizo_asic_capability_create(cap, init);
++ asic_supported = true;
++#endif
++ break;
++
++ default:
++ /* unsupported "chip_family" */
++ break;
++ }
++
++ if (false == asic_supported) {
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_MASK_ALL,
++ "%s: ASIC not supported!\n", __func__);
++ }
++
++ return asic_supported;
++}
++
++static void destruct(
++ struct asic_capability *cap)
++{
++ /* nothing to do (yet?) */
++}
++
++/*
++ * dal_asic_capability_create
++ *
++ * Creates asic capability based on DCE version.
++ */
++struct asic_capability *dal_asic_capability_create(
++ struct hw_asic_id *init,
++ struct dc_context *ctx)
++{
++ struct asic_capability *cap;
++
++ if (!init) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ cap = dc_service_alloc(ctx, sizeof(struct asic_capability));
++
++ if (!cap) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ if (construct(cap, init, ctx))
++ return cap;
++
++ BREAK_TO_DEBUGGER();
++
++ dc_service_free(ctx, cap);
++
++ return NULL;
++}
++
++/*
++ * dal_asic_capability_destroy
++ *
++ * Destroy allocated memory.
++ */
++void dal_asic_capability_destroy(
++ struct asic_capability **cap)
++{
++ if (!cap) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ if (!*cap) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ destruct(*cap);
++
++ dc_service_free((*cap)->ctx, *cap);
++
++ *cap = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/carrizo_asic_capability.c b/drivers/gpu/drm/amd/dal/dc/asic_capability/carrizo_asic_capability.c
+new file mode 100644
+index 0000000..f57d3f7
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/carrizo_asic_capability.c
+@@ -0,0 +1,146 @@
++/*
++ * 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 "dal_services.h"
++
++#include "include/asic_capability_interface.h"
++#include "include/asic_capability_types.h"
++
++#include "carrizo_asic_capability.h"
++
++#include "atom.h"
++#include "dce/dce_11_0_d.h"
++#include "smu/smu_8_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++#include "dal_asic_id.h"
++
++#define ixVCE_HARVEST_FUSE_MACRO__ADDRESS 0xC0014074
++
++/*
++ * carrizo_asic_capability_create
++ *
++ * Create and initiate Carrizo capability.
++ */
++void carrizo_asic_capability_create(struct asic_capability *cap,
++ struct hw_asic_id *init)
++{
++ uint32_t e_fuse_setting;
++ /* ASIC data */
++ cap->data[ASIC_DATA_CONTROLLERS_NUM] = 3;
++ cap->data[ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM] = 3;
++ cap->data[ASIC_DATA_LINEBUFFER_NUM] = 3;
++ cap->data[ASIC_DATA_PATH_NUM_PER_DPMST_CONNECTOR] = 4;
++ cap->data[ASIC_DATA_DCE_VERSION] = 0x110; /* DCE 11 */
++ cap->data[ASIC_DATA_LINEBUFFER_SIZE] = 1712 * 144;
++ cap->data[ASIC_DATA_DRAM_BANDWIDTH_EFFICIENCY] = 45;
++ cap->data[ASIC_DATA_CLOCKSOURCES_NUM] = 2;
++ cap->data[ASIC_DATA_MC_LATENCY] = 5000;
++ cap->data[ASIC_DATA_STUTTERMODE] = 0x200A;
++ cap->data[ASIC_DATA_VIEWPORT_PIXEL_GRANULARITY] = 2;
++ cap->data[ASIC_DATA_MAX_COFUNC_NONDP_DISPLAYS] = 2;
++ cap->data[ASIC_DATA_MEMORYTYPE_MULTIPLIER] = 2;
++ cap->data[ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ] = 100;
++ cap->data[ASIC_DATA_NUM_OF_VIDEO_PLANES] = 1;
++ cap->data[ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM] = 3;
++
++ /* ASIC basic capability */
++ cap->caps.IS_FUSION = true;
++ cap->caps.DP_MST_SUPPORTED = true;
++ cap->caps.PANEL_SELF_REFRESH_SUPPORTED = true;
++ cap->caps.MIRABILIS_SUPPORTED = true;
++ cap->caps.NO_VCC_OFF_HPD_POLLING = true;
++ cap->caps.VCE_SUPPORTED = true;
++ cap->caps.HPD_CHECK_FOR_EDID = true;
++ cap->caps.DFSBYPASS_DYNAMIC_SUPPORT = true;
++ cap->caps.SUPPORT_8BPP = false;
++
++ /* ASIC stereo 3d capability */
++ cap->stereo_3d_caps.DISPLAY_BASED_ON_WS = true;
++ cap->stereo_3d_caps.HDMI_FRAME_PACK = true;
++ cap->stereo_3d_caps.INTERLACE_FRAME_PACK = true;
++ cap->stereo_3d_caps.DISPLAYPORT_FRAME_PACK = true;
++ cap->stereo_3d_caps.DISPLAYPORT_FRAME_ALT = true;
++ cap->stereo_3d_caps.INTERLEAVE = true;
++
++ e_fuse_setting = dal_read_index_reg(cap->ctx,CGS_IND_REG__SMC,ixVCE_HARVEST_FUSE_MACRO__ADDRESS);
++
++ /* Bits [28:27]*/
++ switch ((e_fuse_setting >> 27) & 0x3) {
++ case 0:
++ /*both VCE engine are working*/
++ cap->caps.VCE_SUPPORTED = true;
++ cap->caps.WIRELESS_TIMING_ADJUSTMENT = false;
++ /*TODO:
++ cap->caps.wirelessLowVCEPerformance = false;
++ m_AsicCaps.vceInstance0Enabled = true;
++ m_AsicCaps.vceInstance1Enabled = true;*/
++ cap->caps.NEED_MC_TUNING = true;
++ break;
++
++ case 1:
++ cap->caps.VCE_SUPPORTED = true;
++ cap->caps.WIRELESS_TIMING_ADJUSTMENT = true;
++ /*TODO:
++ m_AsicCaps.wirelessLowVCEPerformance = false;
++ m_AsicCaps.vceInstance1Enabled = true;*/
++ cap->caps.NEED_MC_TUNING = true;
++ break;
++
++ case 2:
++ cap->caps.VCE_SUPPORTED = true;
++ cap->caps.WIRELESS_TIMING_ADJUSTMENT = true;
++ /*TODO:
++ m_AsicCaps.wirelessLowVCEPerformance = false;
++ m_AsicCaps.vceInstance0Enabled = true;*/
++ cap->caps.NEED_MC_TUNING = true;
++ break;
++
++ case 3:
++ /* VCE_DISABLE = 0x3 - both VCE
++ * instances are in harvesting,
++ * no VCE supported any more.
++ */
++ cap->caps.VCE_SUPPORTED = false;
++ break;
++
++ default:
++ break;
++ }
++
++ if (ASIC_REV_IS_STONEY(init->hw_internal_rev))
++ {
++ /* Stoney is the same DCE11, but only two pipes, three digs.
++ * and HW added 64bit back for non SG */
++ cap->data[ASIC_DATA_CONTROLLERS_NUM] = 2;
++ cap->data[ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM] = 2;
++ cap->data[ASIC_DATA_LINEBUFFER_NUM] = 2;
++ /*3 DP MST per connector, limited by number of pipe and number
++ * of Dig.*/
++ cap->data[ASIC_DATA_PATH_NUM_PER_DPMST_CONNECTOR] = 2;
++
++ }
++
++
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/asic_capability/carrizo_asic_capability.h b/drivers/gpu/drm/amd/dal/dc/asic_capability/carrizo_asic_capability.h
+new file mode 100644
+index 0000000..d1e9b83
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/asic_capability/carrizo_asic_capability.h
+@@ -0,0 +1,36 @@
++/*
++ * 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_CARRIZO_ASIC_CAPABILITY_H__
++#define __DAL_CARRIZO_ASIC_CAPABILITY_H__
++
++/* Forward declaration */
++struct asic_capability;
++
++/* Create and initialize Carrizo data */
++void carrizo_asic_capability_create(struct asic_capability *cap,
++ struct hw_asic_id *init);
++
++#endif /* __DAL_CARRIZO_ASIC_CAPABILITY_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/Makefile b/drivers/gpu/drm/amd/dal/dc/audio/Makefile
+new file mode 100644
+index 0000000..0999372
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/Makefile
+@@ -0,0 +1,22 @@
++#
++# Makefile for the 'audio' sub-component of DAL.
++# It provides the control and status of HW adapter resources,
++# that are global for the ASIC and sharable between pipes.
++
++AUDIO = audio_base.o hw_ctx_audio.o
++
++AMD_DAL_AUDIO = $(addprefix $(AMDDALPATH)/dc/audio/,$(AUDIO))
++
++AMD_DAL_FILES += $(AMD_DAL_AUDIO)
++
++
++###############################################################################
++# DCE 11x
++###############################################################################
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++AUDIO_DCE11 = audio_dce110.o hw_ctx_audio_dce110.o
++
++AMD_DAL_AUDIO_DCE11 = $(addprefix $(AMDDALPATH)/dc/audio/dce110/,$(AUDIO_DCE11))
++
++AMD_DAL_FILES += $(AMD_DAL_AUDIO_DCE11)
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/audio.h b/drivers/gpu/drm/amd/dal/dc/audio/audio.h
+new file mode 100644
+index 0000000..ad2dc18
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/audio.h
+@@ -0,0 +1,195 @@
++/*
++ * 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_AUDIO_H__
++#define __DAL_AUDIO_H__
++
++#include "include/audio_interface.h"
++#include "hw_ctx_audio.h"
++#include "include/link_service_types.h"
++
++/***** only for hook functions *****/
++/**
++ *which will be overwritten by derived audio object.
++ *audio hw context object is independent object
++ */
++
++struct audio;
++
++struct audio_funcs {
++ /*
++ *get_object_id
++ *get_object_type
++ *enumerate_input_signals
++ *enumerate_output_signals
++ *is_input_signal_supported
++ *is_output_signal_supported
++ *set_object_properties
++ *get_object_properties
++ */
++
++ void (*destroy)(struct audio **audio);
++ /*power_up
++ *power_down
++ *release_hw_base
++ */
++
++ /* setup audio */
++ enum audio_result (*setup)(
++ struct audio *audio,
++ struct audio_output *output,
++ struct audio_info *info);
++
++ enum audio_result (*enable_output)(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal);
++
++ enum audio_result (*disable_output)(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal);
++
++ /*enable_azalia_audio_jack_presence
++ * disable_azalia_audio_jack_presence
++ */
++
++ enum audio_result (*unmute)(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal);
++
++ enum audio_result (*mute)(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal);
++
++ /* SW initialization that cannot be done in constructor. This will
++ * be done is audio_power_up but is not in audio_interface. It is only
++ * called by power_up
++ */
++ enum audio_result (*initialize)(
++ struct audio *audio);
++
++ /* enable channel splitting mapping */
++ void (*enable_channel_splitting_mapping)(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable);
++
++ /* get current multi channel split. */
++ enum audio_result (*get_channel_splitting_mapping)(
++ struct audio *audio,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping);
++
++ /* set payload value for the unsolicited response */
++ void (*set_unsolicited_response_payload)(
++ struct audio *audio,
++ enum audio_payload payload);
++
++ /* Update audio wall clock source */
++ void (*setup_audio_wall_dto)(
++ struct audio *audio,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info);
++
++ /* options and features supported by Audio */
++ struct audio_feature_support (*get_supported_features)(
++ struct audio *audio);
++
++ /*
++ *check_audio_bandwidth
++ *write_reg
++ *read_reg
++ *enable_gtc_embedding_with_group
++ *disable_gtc_embedding
++ *register_interrupt
++ *unregister_interrupt
++ *process_interrupt
++ *create_hw_ctx
++ *getHwCtx
++ *setHwCtx
++ *handle_interrupt
++ */
++};
++
++struct audio {
++ /* hook functions. they will be overwritten by specific ASIC */
++ const struct audio_funcs *funcs;
++ /* TODO: static struct audio_funcs funcs;*/
++
++ /*external structures - get service from external*/
++ struct graphics_object_id id;
++ struct adapter_service *adapter_service;
++ /* audio HW context */
++ struct hw_ctx_audio *hw_ctx;
++ struct dc_context *ctx;
++ /* audio supports input and output signals */
++ uint32_t input_signals;
++ uint32_t output_signals;
++};
++
++/* - functions defined by audio.h will be used by audio component only.
++ * but audio.c also implements some function defined by dal\include
++ */
++
++/* graphics_object_base implemention
++ * 1.input_signals and output_signals are moved
++ * into audio object.
++ *
++ * 2.Get the Graphics Object ID
++ *
++ * Outside audio:
++ * use dal_graphics_object_id_get_audio_id
++ * Within audio:
++ * use audio->go_base.id
++ *
++ * 3. Get the Graphics Object Type
++ *
++ * use object_id.type
++ * not function implemented.
++ * 4. Common Graphics Object Properties
++ * use object id ->go_properties.multi_path
++ * not function implemented.
++ */
++
++bool dal_audio_construct_base(
++ struct audio *audio,
++ const struct audio_init_data *init_data);
++
++void dal_audio_destruct_base(
++ struct audio *audio);
++
++void dal_audio_release_hw_base(
++ struct audio *audio);
++
++#endif /* __DAL_AUDIO__ */
++
++
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
+new file mode 100644
+index 0000000..6bac3ed
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/audio_base.c
+@@ -0,0 +1,463 @@
++/*
++ * 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 "dal_services.h"
++
++#include "include/logger_interface.h"
++
++#include "audio.h"
++#include "hw_ctx_audio.h"
++
++#include "dce110/audio_dce110.h"
++
++/***** static function : only used within audio.c *****/
++
++/* stub for hook functions */
++static void destroy(
++ struct audio **audio)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++static enum audio_result setup(
++ struct audio *audio,
++ struct audio_output *output,
++ struct audio_info *info)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return AUDIO_RESULT_OK;
++}
++
++static enum audio_result enable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return AUDIO_RESULT_OK;
++}
++
++static enum audio_result disable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return AUDIO_RESULT_OK;
++}
++
++static enum audio_result unmute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return AUDIO_RESULT_OK;
++}
++
++static enum audio_result mute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return AUDIO_RESULT_OK;
++}
++
++static enum audio_result initialize(
++ struct audio *audio)
++{
++ /*DCE specific, must be implemented in derived. Implemeentaion of
++ *initialize will create audio hw context. create_hw_ctx
++ */
++ BREAK_TO_DEBUGGER();
++ return AUDIO_RESULT_OK;
++}
++
++static void enable_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* get current multi channel split. */
++static enum audio_result get_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return AUDIO_RESULT_OK;
++}
++
++/* set payload value for the unsolicited response */
++static void set_unsolicited_response_payload(
++ struct audio *audio,
++ enum audio_payload payload)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* update audio wall clock source */
++static void setup_audio_wall_dto(
++ struct audio *audio,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++static struct audio_feature_support get_supported_features(struct audio *audio)
++{
++ /*DCE specific, must be implemented in derived*/
++ struct audio_feature_support features;
++
++ dc_service_memset(&features, 0, sizeof(features));
++
++ features.ENGINE_DIGA = 1;
++ features.ENGINE_DIGB = 1;
++
++ return features;
++}
++
++static const struct audio_funcs audio_funcs = {
++ .destroy = destroy,
++ .setup = setup,
++ .enable_output = enable_output,
++ .disable_output = disable_output,
++ .unmute = unmute,
++ .mute = mute,
++ .initialize = initialize,
++ .enable_channel_splitting_mapping =
++ enable_channel_splitting_mapping,
++ .get_channel_splitting_mapping =
++ get_channel_splitting_mapping,
++ .set_unsolicited_response_payload =
++ set_unsolicited_response_payload,
++ .setup_audio_wall_dto = setup_audio_wall_dto,
++ .get_supported_features = get_supported_features,
++};
++
++/***** SCOPE : declare in audio.h. use within dal-audio. *****/
++
++bool dal_audio_construct_base(
++ struct audio *audio,
++ const struct audio_init_data *init_data)
++{
++ enum signal_type signals = SIGNAL_TYPE_HDMI_TYPE_A;
++
++ ASSERT(init_data->as != NULL);
++
++ /* base hook functions */
++ audio->funcs = &audio_funcs;
++
++ /*setup pointers to get service from dal service compoenents*/
++ audio->adapter_service = init_data->as;
++
++ audio->ctx = init_data->ctx;
++
++ /* save audio endpoint number to identify object creating */
++ audio->id = init_data->audio_stream_id;
++
++ /* Fill supported signals. !!! be aware that android definition is
++ * already shift to vector.
++ */
++ signals |= SIGNAL_TYPE_DISPLAY_PORT;
++ signals |= SIGNAL_TYPE_DISPLAY_PORT_MST;
++ signals |= SIGNAL_TYPE_EDP;
++ signals |= SIGNAL_TYPE_DISPLAY_PORT;
++ signals |= SIGNAL_TYPE_WIRELESS;
++
++ /* Audio supports same set for input and output signals */
++ audio->input_signals = signals;
++ audio->output_signals = signals;
++
++ return true;
++}
++
++/* except hw_ctx, no other hw need reset. so do nothing */
++void dal_audio_destruct_base(
++ struct audio *audio)
++{
++}
++
++/* Enumerate Graphics Object supported Input/Output Signal Types */
++uint32_t dal_audio_enumerate_input_signals(
++ struct audio *audio)
++{
++ return audio->input_signals;
++}
++
++uint32_t dal_audio_enumerate_output_signals(
++ struct audio *audio)
++{
++ return audio->output_signals;
++}
++
++/* Check if signal supported by GraphicsObject */
++bool dal_audio_is_input_signal_supported(
++ struct audio *audio,
++ enum signal_type signal)
++{
++ return (signal & audio->output_signals) != 0;
++}
++
++bool dal_audio_is_output_signal_supported(
++ struct audio *audio,
++ enum signal_type signal)
++{
++ return (signal & audio->input_signals) != 0;
++}
++
++/***** SCOPE : declare in dal\include *****/
++
++/* audio object creator triage. memory allocate and release will be
++ * done within dal_audio_create_dcexx
++ */
++struct audio *dal_audio_create(
++ const struct audio_init_data *init_data)
++{
++ struct adapter_service *as;
++
++ if (init_data->as == NULL)
++ return NULL;
++
++ as = init_data->as;
++ switch (dal_adapter_service_get_dce_version(as)) {
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ return dal_audio_create_dce110(init_data);
++#endif
++ default:
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ return NULL;
++}
++
++/* audio object creator triage.
++ * memory for "struct audio dal_audio_create_dce8x" allocate
++ * will happens within dal_audio_dce8x. memory allocate is done
++ * with dal_audio_create_dce8x. memory release is initiated by
++ * dal_audio_destroy. It will call hook function which will finially
++ * used destroy() of dal_audio_dce8x. therefore, no memroy allocate
++ *and release happen physcially at audio base object.
++ */
++void dal_audio_destroy(
++ struct audio **audio)
++{
++ if (!audio || !*audio) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ (*audio)->funcs->destroy(audio);
++
++ *audio = NULL;
++}
++
++const struct graphics_object_id dal_audio_get_graphics_object_id(
++ const struct audio *audio)
++{
++ return audio->id;
++}
++
++/* enable azalia audio endpoint. This function call hw_ctx directly
++ *not overwitten at audio level.
++ */
++enum audio_result dal_audio_enable_azalia_audio_jack_presence(
++ struct audio *audio,
++ enum engine_id engine_id)
++{
++ audio->hw_ctx->funcs->enable_azalia_audio(audio->hw_ctx, engine_id);
++ return AUDIO_RESULT_OK;
++}
++
++/* disable azalia audio endpoint. This function call hw_ctx directly
++ *not overwitten at audio level.
++ */
++enum audio_result dal_audio_disable_azalia_audio_jack_presence(
++ struct audio *audio,
++ enum engine_id engine_id)
++{
++ audio->hw_ctx->funcs->disable_azalia_audio(audio->hw_ctx, engine_id);
++ return AUDIO_RESULT_OK;
++}
++
++/* get audio bandwidth information. This function call hw_ctx directly
++ *not overwitten at audio level.
++ */
++void dal_audio_check_audio_bandwidth(
++ struct audio *audio,
++ const struct audio_crtc_info *info,
++ uint32_t channel_count,
++ enum signal_type signal,
++ union audio_sample_rates *sample_rates)
++{
++ dal_hw_ctx_audio_check_audio_bandwidth(
++ audio->hw_ctx, info, channel_count, signal, sample_rates);
++}
++
++/* DP Audio register write access. This function call hw_ctx directly
++ * not overwitten at audio level.
++ */
++
++/*assign GTC group and enable GTC value embedding*/
++void dal_audio_enable_gtc_embedding_with_group(
++ struct audio *audio,
++ uint32_t group_num,
++ uint32_t audio_latency)
++{
++ audio->hw_ctx->funcs->enable_gtc_embedding_with_group(
++ audio->hw_ctx, group_num, audio_latency);
++}
++
++/* disable GTC value embedding */
++void dal_audio_disable_gtc_embedding(
++ struct audio *audio)
++{
++ audio->hw_ctx->funcs->disable_gtc_embedding(audio->hw_ctx);
++}
++
++/* perform power up sequence (boot up, resume, recovery) */
++enum audio_result dal_audio_power_up(
++ struct audio *audio)
++{
++ return audio->funcs->initialize(audio);
++}
++
++/* perform power down (shut down, stand by) */
++enum audio_result dal_audio_power_down(
++ struct audio *audio)
++{
++ return AUDIO_RESULT_OK;
++}
++
++/* setup audio */
++enum audio_result dal_audio_setup(
++ struct audio *audio,
++ struct audio_output *output,
++ struct audio_info *info)
++{
++ return audio->funcs->setup(audio, output, info);
++}
++
++/* enable audio */
++enum audio_result dal_audio_enable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ return audio->funcs->enable_output(audio, engine_id, signal);
++}
++
++/* disable audio */
++enum audio_result dal_audio_disable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ return audio->funcs->disable_output(audio, engine_id, signal);
++}
++
++/* unmute audio */
++enum audio_result dal_audio_unmute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ return audio->funcs->unmute(audio, engine_id, signal);
++}
++
++/* mute audio */
++enum audio_result dal_audio_mute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ return audio->funcs->mute(audio, engine_id, signal);
++}
++
++/* Enable multi channel split */
++void dal_audio_enable_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable)
++{
++ audio->funcs->enable_channel_splitting_mapping(
++ audio, engine_id, signal, audio_mapping, enable);
++}
++
++/* get current multi channel split. */
++enum audio_result dal_audio_get_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping)
++{
++ return audio->funcs->get_channel_splitting_mapping(
++ audio, engine_id, audio_mapping);
++}
++
++/* set payload value for the unsolicited response */
++void dal_audio_set_unsolicited_response_payload(
++ struct audio *audio,
++ enum audio_payload payload)
++{
++ audio->funcs->set_unsolicited_response_payload(audio, payload);
++}
++
++/* update audio wall clock source */
++void dal_audio_setup_audio_wall_dto(
++ struct audio *audio,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info)
++{
++ audio->funcs->setup_audio_wall_dto(audio, signal, crtc_info, pll_info);
++}
++
++struct audio_feature_support dal_audio_get_supported_features(
++ struct audio *audio)
++{
++ return audio->funcs->get_supported_features(audio);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c b/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c
+new file mode 100644
+index 0000000..f284870
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.c
+@@ -0,0 +1,452 @@
++/*
++ * 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 "dal_services.h"
++#include "include/logger_interface.h"
++
++#include "audio_dce110.h"
++
++/***** static functions *****/
++
++static void destruct(struct audio_dce110 *audio)
++{
++ /*release memory allocated for hw_ctx -- allocated is initiated
++ *by audio_dce110 power_up
++ *audio->base->hw_ctx = NULL is done within hw-ctx->destroy
++ */
++ if (audio->base.hw_ctx)
++ audio->base.hw_ctx->funcs->destroy(&(audio->base.hw_ctx));
++
++ /* reset base_audio_block */
++ dal_audio_destruct_base(&audio->base);
++}
++
++static void destroy(struct audio **ptr)
++{
++ struct audio_dce110 *audio = NULL;
++
++ audio = container_of(*ptr, struct audio_dce110, base);
++
++ destruct(audio);
++
++ /* release memory allocated for audio_dce110*/
++ dc_service_free((*ptr)->ctx, audio);
++ *ptr = NULL;
++}
++
++
++/* The inital call of hook function comes from audio object level.
++ *The passing object handle "struct audio *audio" point to base object
++ *already.There is not need to get base object from audio_dce110.
++ */
++
++/**
++* setup
++*
++* @brief
++* setup Audio HW block, to be called by dal_audio_setup
++*
++*/
++static enum audio_result setup(
++ struct audio *audio,
++ struct audio_output *output,
++ struct audio_info *info)
++{
++ switch (output->signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ /*setup HDMI audio engine*/
++ audio->hw_ctx->funcs->enable_afmt_clock(
++ audio->hw_ctx,
++ output->engine_id,
++ true);
++ audio->hw_ctx->funcs->setup_hdmi_audio(
++ audio->hw_ctx, output->engine_id, &output->crtc_info);
++
++ audio->hw_ctx->funcs->setup_azalia(
++ audio->hw_ctx,
++ output->engine_id,
++ output->signal,
++ &output->crtc_info,
++ &output->pll_info,
++ info);
++ break;
++
++ case SIGNAL_TYPE_WIRELESS:
++ /* setup Azalia block for Wireless Display - This
++ is different than for wired
++ displays because there is no
++ DIG to program.*/
++ /*TODO:
++ audio->hw_ctx->funcs->setup_azalia_for_vce(
++ audio->hw_ctx,
++ audio->signal,
++ audio->crtc_info,
++ info);
++ */
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ /* setup DP audio engine will be done at enable output */
++
++ /* setup Azalia block*/
++ audio->hw_ctx->funcs->setup_azalia(
++ audio->hw_ctx,
++ output->engine_id,
++ output->signal,
++ &output->crtc_info,
++ &output->pll_info,
++ info);
++
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* enable_output
++*
++* @brief
++* enable Audio HW block, to be called by dal_audio_enable_output
++*/
++static enum audio_result enable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ /* enable audio output */
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP: {
++ /* enable AFMT clock before enable audio*/
++ audio->hw_ctx->funcs->enable_afmt_clock(
++ audio->hw_ctx, engine_id, true);
++ /* setup DP audio engine */
++ audio->hw_ctx->funcs->setup_dp_audio(
++ audio->hw_ctx, engine_id);
++ /* enabl DP audio packets will be done at unblank */
++ audio->hw_ctx->funcs->enable_dp_audio(
++ audio->hw_ctx, engine_id);
++ }
++ break;
++ case SIGNAL_TYPE_WIRELESS:
++ /* route audio to VCE block */
++ audio->hw_ctx->funcs->setup_vce_audio(audio->hw_ctx);
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* disable_output
++*
++* @brief
++* disable Audio HW block, to be called by dal_audio_disable_output
++*
++*/
++static enum audio_result disable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_WIRELESS:
++ /* disable HDMI audio */
++ audio->hw_ctx->
++ funcs->disable_azalia_audio(
++ audio->hw_ctx, engine_id);
++ audio->hw_ctx->
++ funcs->enable_afmt_clock(
++ audio->hw_ctx, engine_id,
++ false);
++
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP: {
++ /* disable DP audio */
++ audio->hw_ctx->funcs->disable_dp_audio(
++ audio->hw_ctx, engine_id);
++ audio->hw_ctx->funcs->disable_azalia_audio(
++ audio->hw_ctx, engine_id);
++ audio->hw_ctx->funcs->enable_afmt_clock(
++ audio->hw_ctx, engine_id, false);
++ }
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* unmute
++*
++* @brief
++* unmute audio, to be called by dal_audio_unmute
++*
++*/
++static enum audio_result unmute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ /* unmute Azalia audio */
++ audio->hw_ctx->funcs->unmute_azalia_audio(
++ audio->hw_ctx, engine_id);
++ break;
++ case SIGNAL_TYPE_WIRELESS:
++ /*Do nothing for wireless display*/
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* mute
++*
++* @brief
++* mute audio, to be called by dal_audio_nmute
++*
++*/
++static enum audio_result mute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal)
++{
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ /* mute Azalia audio */
++ audio->hw_ctx->funcs->mute_azalia_audio(
++ audio->hw_ctx, engine_id);
++ break;
++ case SIGNAL_TYPE_WIRELESS:
++ /*Do nothing for wireless display*/
++ break;
++ default:
++ return AUDIO_RESULT_ERROR;
++ }
++ return AUDIO_RESULT_OK;
++}
++
++/**
++* initialize
++*
++* @brief
++* Perform SW initialization - create audio hw context. Then do HW
++* initialization. this function is called at dal_audio_power_up.
++*
++*/
++static enum audio_result initialize(
++ struct audio *audio)
++{
++ uint8_t audio_endpoint_enum_id = 0;
++
++ audio_endpoint_enum_id = audio->id.enum_id;
++
++ /* HW CTX already create*/
++ if (audio->hw_ctx != NULL)
++ return AUDIO_RESULT_OK;
++
++ audio->hw_ctx = dal_hw_ctx_audio_dce110_create(
++ audio->ctx,
++ audio_endpoint_enum_id);
++
++ if (audio->hw_ctx == NULL)
++ return AUDIO_RESULT_ERROR;
++
++ /* override HW default settings */
++ audio->hw_ctx->funcs->hw_initialize(audio->hw_ctx);
++
++ return AUDIO_RESULT_OK;
++}
++
++/* enable multi channel split */
++static void enable_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable)
++{
++ audio->hw_ctx->funcs->setup_channel_splitting_mapping(
++ audio->hw_ctx,
++ engine_id,
++ signal,
++ audio_mapping, enable);
++}
++
++/* get current multi channel split. */
++static enum audio_result get_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping)
++{
++ if (audio->hw_ctx->funcs->get_channel_splitting_mapping(
++ audio->hw_ctx, engine_id, audio_mapping)) {
++ return AUDIO_RESULT_OK;
++ } else {
++ return AUDIO_RESULT_ERROR;
++ }
++}
++
++/**
++* set_unsolicited_response_payload
++*
++* @brief
++* Set payload value for the unsolicited response
++*/
++static void set_unsolicited_response_payload(
++ struct audio *audio,
++ enum audio_payload payload)
++{
++ audio->hw_ctx->funcs->set_unsolicited_response_payload(
++ audio->hw_ctx, payload);
++}
++
++/**
++* setup_audio_wall_dto
++*
++* @brief
++* Update audio source clock from hardware context.
++*
++*/
++static void setup_audio_wall_dto(
++ struct audio *audio,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info)
++{
++ audio->hw_ctx->funcs->setup_audio_wall_dto(
++ audio->hw_ctx, signal, crtc_info, pll_info);
++}
++
++/**
++* get_supported_features
++*
++* @brief
++* options and features supported by Audio
++* returns supported engines, signals.
++* features are reported for HW audio/Azalia block rather then Audio object
++* itself the difference for DCE6.x is that MultiStream Audio is now supported
++*
++*/
++static struct audio_feature_support get_supported_features(struct audio *audio)
++{
++ struct audio_feature_support afs = {0};
++
++ afs.ENGINE_DIGA = 1;
++ afs.ENGINE_DIGB = 1;
++ afs.ENGINE_DIGC = 1;
++ afs.MULTISTREAM_AUDIO = 1;
++
++ return afs;
++}
++
++static const struct audio_funcs funcs = {
++ .destroy = destroy,
++ .setup = setup,
++ .enable_output = enable_output,
++ .disable_output = disable_output,
++ .unmute = unmute,
++ .mute = mute,
++ .initialize = initialize,
++ .enable_channel_splitting_mapping =
++ enable_channel_splitting_mapping,
++ .get_channel_splitting_mapping =
++ get_channel_splitting_mapping,
++ .set_unsolicited_response_payload =
++ set_unsolicited_response_payload,
++ .setup_audio_wall_dto = setup_audio_wall_dto,
++ .get_supported_features = get_supported_features,
++};
++
++static bool construct(
++ struct audio_dce110 *audio,
++ const struct audio_init_data *init_data)
++{
++ struct audio *base = &audio->base;
++
++ /* base audio construct*/
++ if (!dal_audio_construct_base(base, init_data))
++ return false;
++
++ /*vtable methods*/
++ base->funcs = &funcs;
++ return true;
++}
++
++
++/* --- audio scope functions --- */
++
++struct audio *dal_audio_create_dce110(
++ const struct audio_init_data *init_data)
++{
++ /*allocate memory for audio_dce110 */
++ struct audio_dce110 *audio = dc_service_alloc(init_data->ctx, sizeof(*audio));
++
++ if (audio == NULL) {
++ ASSERT_CRITICAL(audio);
++ return NULL;
++ }
++ /*pointer to base_audio_block of audio_dce110 ==> audio base object */
++ if (construct(audio, init_data))
++ return &audio->base;
++
++ dal_logger_write(
++ init_data->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "Failed to create audio object for DCE11\n");
++
++ /*release memory allocated if fail */
++ dc_service_free(init_data->ctx, audio);
++ return NULL;
++}
++
++/* Do not need expose construct_dce110 and destruct_dce110 becuase there is
++ *derived object after dce110
++ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h b/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h
+new file mode 100644
+index 0000000..e5ff823
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/dce110/audio_dce110.h
+@@ -0,0 +1,42 @@
++/*
++ * 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_AUDIO_DCE_110_H__
++#define __DAL_AUDIO_DCE_110_H__
++
++#include "audio/audio.h"
++#include "audio/hw_ctx_audio.h"
++#include "audio/dce110/hw_ctx_audio_dce110.h"
++
++
++
++struct audio_dce110 {
++ struct audio base;
++ /* dce-specific members are following */
++ /* none */
++};
++
++struct audio *dal_audio_create_dce110(const struct audio_init_data *init_data);
++
++#endif /*__DAL_AUDIO_DCE_110_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c b/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c
+new file mode 100644
+index 0000000..a13b2ab
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.c
+@@ -0,0 +1,1929 @@
++/*
++ * 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 "dal_services.h"
++#include "include/logger_interface.h"
++#include "../hw_ctx_audio.h"
++#include "hw_ctx_audio_dce110.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#define FROM_BASE(ptr) \
++ container_of((ptr), struct hw_ctx_audio_dce110, base)
++
++#define DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT 0x8000
++#define DP_AUDIO_DTO_MODULE_WITHOUT_SS 360
++#define DP_AUDIO_DTO_PHASE_WITHOUT_SS 24
++
++#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUDIO_FRONT_END 0
++#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC 1
++#define DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__REGISTER_PROGRAMMABLE 2
++
++#define FIRST_AUDIO_STREAM_ID 1
++
++#define NOT_IMPLEMENTED() DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_AUDIO, \
++ "Audio:%s()\n", __func__)
++
++static const uint32_t engine_offset[] = {
++ 0,
++ mmDIG1_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG2_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG3_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL
++};
++
++static void destruct(
++ struct hw_ctx_audio_dce110 *hw_ctx_dce110)
++{
++ dal_audio_destruct_hw_ctx_audio(&hw_ctx_dce110->base);
++}
++
++static void destroy(
++ struct hw_ctx_audio **ptr)
++{
++ struct hw_ctx_audio_dce110 *hw_ctx_dce110;
++
++ hw_ctx_dce110 = container_of(
++ *ptr, struct hw_ctx_audio_dce110, base);
++
++ destruct(hw_ctx_dce110);
++ /* release memory allocated for struct hw_ctx_audio_dce110 */
++ dc_service_free((*ptr)->ctx, hw_ctx_dce110);
++
++ *ptr = NULL;
++}
++
++/* --- helpers --- */
++static void write_indirect_azalia_reg(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t reg_index,
++ uint32_t reg_data)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++ /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */
++ {
++ addr =
++ FROM_BASE(hw_ctx)->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index;
++
++ set_reg_field_value(value, reg_index,
++ AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ AZALIA_ENDPOINT_REG_INDEX);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */
++ {
++ addr =
++ FROM_BASE(hw_ctx)->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data;
++
++ value = 0;
++ set_reg_field_value(value, reg_data,
++ AZALIA_F0_CODEC_ENDPOINT_DATA,
++ AZALIA_ENDPOINT_REG_DATA);
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ dal_logger_write(
++ hw_ctx->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_AUDIO,
++ "AUDIO:write_indirect_azalia_reg: index: %u data: %u\n",
++ reg_index, reg_data);
++}
++
++static uint32_t read_indirect_azalia_reg(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t reg_index)
++{
++ uint32_t ret_val = 0;
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++
++ /* AZALIA_F0_CODEC_ENDPOINT_INDEX endpoint index */
++ {
++ addr =
++ FROM_BASE(hw_ctx)->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index;
++
++ set_reg_field_value(value, reg_index,
++ AZALIA_F0_CODEC_ENDPOINT_INDEX,
++ AZALIA_ENDPOINT_REG_INDEX);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AZALIA_F0_CODEC_ENDPOINT_DATA endpoint data */
++ {
++ addr =
++ FROM_BASE(hw_ctx)->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ ret_val = value;
++ }
++
++ dal_logger_write(
++ hw_ctx->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_AUDIO,
++ "AUDIO:read_indirect_azalia_reg: index: %u data: %u\n",
++ reg_index, ret_val);
++
++ return ret_val;
++}
++
++/* expose/not expose HBR capability to Audio driver */
++static void set_high_bit_rate_capable(
++ const struct hw_ctx_audio *hw_ctx,
++ bool capable)
++{
++ uint32_t value = 0;
++
++ /* set high bit rate audio capable*/
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR);
++
++ set_reg_field_value(value, capable,
++ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR,
++ HBR_CAPABLE);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_HBR,
++ value);
++}
++
++/* set HBR channnel count *
++static void set_hbr_channel_count(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t hbr_channel_count)
++{
++ uint32_t value = 0;
++
++ if (hbr_channel_count > 7)
++ return;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL);
++
++ set_reg_field_value(value, hbr_channel_count,
++ AZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
++ HBR_CHANNEL_COUNT);
++
++ dal_write_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL, value);
++
++}
++
++*set compressed audio channel count *
++static void set_compressed_audio_channel_count(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t compressed_audio_ch_count)
++{
++ uint32_t value = 0;
++ if (compressed_audio_ch_count > 7)
++ return;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL);
++
++ set_reg_field_value(value, compressed_audio_ch_count,
++ AZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
++ COMPRESSED_CHANNEL_COUNT);
++
++ dal_write_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_CHANNEL_COUNT_CONTROL,
++ value);
++
++}
++*/
++/* set video latency in in ms/2+1 */
++static void set_video_latency(
++ const struct hw_ctx_audio *hw_ctx,
++ int latency_in_ms)
++{
++ uint32_t value = 0;
++
++ if ((latency_in_ms < 0) || (latency_in_ms > 255))
++ return;
++
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
++
++ set_reg_field_value(value, latency_in_ms,
++ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
++ VIDEO_LIPSYNC);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
++ value);
++
++}
++
++/* set audio latency in in ms/2+1 */
++static void set_audio_latency(
++ const struct hw_ctx_audio *hw_ctx,
++ int latency_in_ms)
++{
++ uint32_t value = 0;
++
++ if (latency_in_ms < 0)
++ latency_in_ms = 0;
++
++ if (latency_in_ms > 255)
++ latency_in_ms = 255;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC);
++
++ set_reg_field_value(value, latency_in_ms,
++ AZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
++ AUDIO_LIPSYNC);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC,
++ value);
++
++}
++
++/* enable HW/SW Sync */
++/*static void enable_hw_sw_sync(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ union AZALIA_CYCLIC_BUFFER_SYNC value;
++
++ value = dal_read_reg(mmAZALIA_CYCLIC_BUFFER_SYNC);
++ value.bits.CYCLIC_BUFFER_SYNC_ENABLE = 1;
++ dal_write_reg(mmAZALIA_CYCLIC_BUFFER_SYNC, value);
++}*/
++
++/* disable HW/SW Sync */
++/*static void disable_hw_sw_sync(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ union AZALIA_CYCLIC_BUFFER_SYNC value;
++
++ value = dal_read_reg(
++ mmAZALIA_CYCLIC_BUFFER_SYNC);
++ value.bits.CYCLIC_BUFFER_SYNC_ENABLE = 0;
++ dal_write_reg(
++ mmAZALIA_CYCLIC_BUFFER_SYNC, value);
++}*/
++
++/* update hardware with software's current position in cyclic buffer */
++/*static void update_sw_write_ptr(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t offset)
++{
++ union AZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER value;
++
++ value = dal_read_reg(
++ mmAZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER);
++ value.bits.APPLICATION_POSITION_IN_CYCLIC_BUFFER = offset;
++ dal_write_reg(
++ mmAZALIA_APPLICATION_POSITION_IN_CYCLIC_BUFFER,
++ value);
++}*/
++
++/* update Audio/Video association */
++/*static void update_av_association(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ uint32_t displayId)
++{
++
++}*/
++
++/* --- hook functions --- */
++static bool get_azalia_clock_info_hdmi(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t crtc_pixel_clock_in_khz,
++ uint32_t actual_pixel_clock_in_khz,
++ struct azalia_clock_info *azalia_clock_info);
++
++static bool get_azalia_clock_info_dp(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t requested_pixel_clock_in_khz,
++ const struct audio_pll_info *pll_info,
++ struct azalia_clock_info *azalia_clock_info);
++
++static void setup_audio_wall_dto(
++ const struct hw_ctx_audio *hw_ctx,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info)
++{
++ struct azalia_clock_info clock_info = { 0 };
++
++ uint32_t value = dal_read_reg(hw_ctx->ctx, mmDCCG_AUDIO_DTO_SOURCE);
++
++ /* TODO: GraphicsObject\inc\GraphicsObjectDefs.hpp(131):
++ *inline bool isHdmiSignal(SignalType signal)
++ *if (Signals::isHdmiSignal(signal))
++ */
++ if (dc_is_hdmi_signal(signal)) {
++ /*DTO0 Programming goal:
++ -generate 24MHz, 128*Fs from 24MHz
++ -use DTO0 when an active HDMI port is connected
++ (optionally a DP is connected) */
++
++ /* calculate DTO settings */
++ get_azalia_clock_info_hdmi(
++ hw_ctx,
++ crtc_info->requested_pixel_clock,
++ crtc_info->calculated_pixel_clock,
++ &clock_info);
++
++ /* On TN/SI, Program DTO source select and DTO select before
++ programming DTO modulo and DTO phase. These bits must be
++ programmed first, otherwise there will be no HDMI audio at boot
++ up. This is a HW sequence change (different from old ASICs).
++ Caution when changing this programming sequence.
++
++ HDMI enabled, using DTO0
++ program master CRTC for DTO0 */
++ {
++ set_reg_field_value(value,
++ pll_info->dto_source - DTO_SOURCE_ID0,
++ DCCG_AUDIO_DTO_SOURCE,
++ DCCG_AUDIO_DTO0_SOURCE_SEL);
++
++ set_reg_field_value(value,
++ 0,
++ DCCG_AUDIO_DTO_SOURCE,
++ DCCG_AUDIO_DTO_SEL);
++
++ dal_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO_SOURCE, value);
++ }
++
++ /* module */
++ {
++ value = dal_read_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO0_MODULE);
++ set_reg_field_value(value,
++ clock_info.audio_dto_module,
++ DCCG_AUDIO_DTO0_MODULE,
++ DCCG_AUDIO_DTO0_MODULE);
++ dal_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO0_MODULE, value);
++ }
++
++ /* phase */
++ {
++ value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO0_PHASE);
++ set_reg_field_value(value,
++ clock_info.audio_dto_phase,
++ DCCG_AUDIO_DTO0_PHASE,
++ DCCG_AUDIO_DTO0_PHASE);
++
++ dal_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO0_PHASE, value);
++ }
++
++ } else {
++ /*DTO1 Programming goal:
++ -generate 24MHz, 512*Fs, 128*Fs from 24MHz
++ -default is to used DTO1, and switch to DTO0 when an audio
++ master HDMI port is connected
++ -use as default for DP
++
++ calculate DTO settings */
++ get_azalia_clock_info_dp(
++ hw_ctx,
++ crtc_info->requested_pixel_clock,
++ pll_info,
++ &clock_info);
++
++ /* Program DTO select before programming DTO modulo and DTO
++ phase. default to use DTO1 */
++
++ {
++ set_reg_field_value(value, 1,
++ DCCG_AUDIO_DTO_SOURCE,
++ DCCG_AUDIO_DTO_SEL);
++ /*dal_write_reg(mmDCCG_AUDIO_DTO_SOURCE, value)*/
++
++ /* Select 512fs for DP TODO: web register definition
++ does not match register header file
++ set_reg_field_value(value, 1,
++ DCCG_AUDIO_DTO_SOURCE,
++ DCCG_AUDIO_DTO2_USE_512FBR_DTO);
++ */
++
++ dal_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO_SOURCE, value);
++ }
++
++ /* module */
++ {
++ value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO1_MODULE);
++
++ set_reg_field_value(value,
++ clock_info.audio_dto_module,
++ DCCG_AUDIO_DTO1_MODULE,
++ DCCG_AUDIO_DTO1_MODULE);
++
++ dal_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO1_MODULE, value);
++ }
++
++ /* phase */
++ {
++ value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO1_PHASE);
++
++ set_reg_field_value(value,
++ clock_info.audio_dto_phase,
++ DCCG_AUDIO_DTO1_PHASE,
++ DCCG_AUDIO_DTO1_PHASE);
++
++ dal_write_reg(hw_ctx->ctx,
++ mmDCCG_AUDIO_DTO1_PHASE, value);
++ }
++
++ /* DAL2 code separate DCCG_AUDIO_DTO_SEL and
++ DCCG_AUDIO_DTO2_USE_512FBR_DTO programming into two different
++ location. merge together should not hurt */
++ /*value.bits.DCCG_AUDIO_DTO2_USE_512FBR_DTO = 1;
++ dal_write_reg(mmDCCG_AUDIO_DTO_SOURCE, value);*/
++ }
++}
++
++/* setup HDMI audio */
++static void setup_hdmi_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ const struct audio_crtc_info *crtc_info)
++{
++ struct audio_clock_info audio_clock_info = {0};
++ uint32_t max_packets_per_line;
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ /* For now still do calculation, although this field is ignored when
++ above HDMI_PACKET_GEN_VERSION set to 1 */
++ max_packets_per_line =
++ dal_audio_hw_ctx_calc_max_audio_packets_per_line(
++ hw_ctx,
++ crtc_info);
++
++ /* HDMI_AUDIO_PACKET_CONTROL */
++ {
++ addr =
++ mmHDMI_AUDIO_PACKET_CONTROL + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, max_packets_per_line,
++ HDMI_AUDIO_PACKET_CONTROL,
++ HDMI_AUDIO_PACKETS_PER_LINE);
++ /* still apply RS600's default setting which is 1. */
++ set_reg_field_value(value, 1,
++ HDMI_AUDIO_PACKET_CONTROL,
++ HDMI_AUDIO_DELAY_EN);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_AUDIO_PACKET_CONTROL */
++ {
++ addr = mmAFMT_AUDIO_PACKET_CONTROL + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 1,
++ AFMT_AUDIO_PACKET_CONTROL,
++ AFMT_60958_CS_UPDATE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_AUDIO_PACKET_CONTROL2 */
++ {
++ addr = mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 0,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_AUDIO_LAYOUT_OVRD);
++
++ /*Register field changed.*/
++ set_reg_field_value(value, 0,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_60958_OSF_OVRD);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_PACKET_CONTROL */
++ {
++ addr = mmHDMI_ACR_PACKET_CONTROL + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 1,
++ HDMI_ACR_PACKET_CONTROL,
++ HDMI_ACR_AUTO_SEND);
++
++ /* Set HDMI_ACR_SOURCE to 0, to use hardwre
++ * computed CTS values.*/
++ set_reg_field_value(value, 0,
++ HDMI_ACR_PACKET_CONTROL,
++ HDMI_ACR_SOURCE);
++
++ /* For now clear HDMI_ACR_AUDIO_PRIORITY =>ACR packet has
++ higher priority over Audio Sample */
++ set_reg_field_value(value, 0,
++ HDMI_ACR_PACKET_CONTROL,
++ HDMI_ACR_AUDIO_PRIORITY);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* Program audio clock sample/regeneration parameters */
++ if (dal_audio_hw_ctx_get_audio_clock_info(
++ hw_ctx,
++ crtc_info->color_depth,
++ crtc_info->requested_pixel_clock,
++ crtc_info->calculated_pixel_clock,
++ &audio_clock_info)) {
++
++ /* HDMI_ACR_32_0__HDMI_ACR_CTS_32_MASK */
++ {
++ addr = mmHDMI_ACR_32_0 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, audio_clock_info.cts_32khz,
++ HDMI_ACR_32_0,
++ HDMI_ACR_CTS_32);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_32_1__HDMI_ACR_N_32_MASK */
++ {
++ addr = mmHDMI_ACR_32_1 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.n_32khz,
++ HDMI_ACR_32_1,
++ HDMI_ACR_N_32);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_44_0__HDMI_ACR_CTS_44_MASK */
++ {
++ addr = mmHDMI_ACR_44_0 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.cts_44khz,
++ HDMI_ACR_44_0,
++ HDMI_ACR_CTS_44);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_44_1__HDMI_ACR_N_44_MASK */
++ {
++ addr = mmHDMI_ACR_44_1 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.n_44khz,
++ HDMI_ACR_44_1,
++ HDMI_ACR_N_44);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_48_0__HDMI_ACR_CTS_48_MASK */
++ {
++ addr = mmHDMI_ACR_48_0 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.cts_48khz,
++ HDMI_ACR_48_0,
++ HDMI_ACR_CTS_48);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* HDMI_ACR_48_1__HDMI_ACR_N_48_MASK */
++ {
++ addr = mmHDMI_ACR_48_1 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, audio_clock_info.n_48khz,
++ HDMI_ACR_48_1,
++ HDMI_ACR_N_48);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* Video driver cannot know in advance which sample rate will
++ be used by HD Audio driver
++ HDMI_ACR_PACKET_CONTROL__HDMI_ACR_N_MULTIPLE field is
++ programmed below in interruppt callback */
++ } /* if */
++
++ /* AFMT_60958_0__AFMT_60958_CS_CHANNEL_NUMBER_L_MASK &
++ AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */
++ {
++ addr = mmAFMT_60958_0 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 1,
++ AFMT_60958_0,
++ AFMT_60958_CS_CHANNEL_NUMBER_L);
++
++ /*HW default */
++ set_reg_field_value(value, 0,
++ AFMT_60958_0,
++ AFMT_60958_CS_CLOCK_ACCURACY);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_60958_1 AFMT_60958_CS_CHALNNEL_NUMBER_R */
++ {
++ addr = mmAFMT_60958_1 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 2,
++ AFMT_60958_1,
++ AFMT_60958_CS_CHANNEL_NUMBER_R);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /*AFMT_60958_2 now keep this settings until
++ * Programming guide comes out*/
++ {
++ addr = mmAFMT_60958_2 + engine_offset[engine_id];
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 3,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_2);
++
++ set_reg_field_value(value, 4,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_3);
++
++ set_reg_field_value(value, 5,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_4);
++
++ set_reg_field_value(value, 6,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_5);
++
++ set_reg_field_value(value, 7,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_6);
++
++ set_reg_field_value(value, 8,
++ AFMT_60958_2,
++ AFMT_60958_CS_CHANNEL_NUMBER_7);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++}
++
++ /* setup DP audio */
++static void setup_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /* --- DP Audio packet configurations --- */
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ /* ATP Configuration */
++ {
++ addr = mmDP_SEC_AUD_N + engine_offset[engine_id];
++
++ set_reg_field_value(value,
++ DP_SEC_AUD_N__DP_SEC_AUD_N__DEFAULT,
++ DP_SEC_AUD_N,
++ DP_SEC_AUD_N);
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* Async/auto-calc timestamp mode */
++ {
++ addr = mmDP_SEC_TIMESTAMP +
++ engine_offset[engine_id];
++
++ value = 0;
++
++ set_reg_field_value(value,
++ DP_SEC_TIMESTAMP__DP_SEC_TIMESTAMP_MODE__AUTO_CALC,
++ DP_SEC_TIMESTAMP,
++ DP_SEC_TIMESTAMP_MODE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* --- The following are the registers
++ * copied from the SetupHDMI --- */
++
++
++ /* AFMT_AUDIO_PACKET_CONTROL */
++ {
++ addr = mmAFMT_AUDIO_PACKET_CONTROL +
++ engine_offset[engine_id];
++
++ value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value,
++ 1,
++ AFMT_AUDIO_PACKET_CONTROL,
++ AFMT_60958_CS_UPDATE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_AUDIO_PACKET_CONTROL2 */
++ {
++ addr =
++ mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
++
++ value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value,
++ 0,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_AUDIO_LAYOUT_OVRD);
++
++ set_reg_field_value(value,
++ 0,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_60958_OSF_OVRD);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_INFOFRAME_CONTROL0 */
++ {
++ addr =
++ mmAFMT_INFOFRAME_CONTROL0 + engine_offset[engine_id];
++
++ value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value,
++ 1,
++ AFMT_INFOFRAME_CONTROL0,
++ AFMT_AUDIO_INFO_UPDATE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* AFMT_60958_0__AFMT_60958_CS_CLOCK_ACCURACY_MASK */
++ {
++ addr = mmAFMT_60958_0 + engine_offset[engine_id];
++
++ value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value,
++ 0,
++ AFMT_60958_0,
++ AFMT_60958_CS_CLOCK_ACCURACY);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++}
++
++ /* setup VCE audio */
++static void setup_vce_audio(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ struct dc_context *ctx = hw_ctx->ctx;
++
++ NOT_IMPLEMENTED();
++
++ /*TODO:
++ const uint32_t addr = mmDOUT_DCE_VCE_CONTROL;
++ uint32_t value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx,
++ addr);
++
++ set_reg_field_value(value,
++ FROM_BASE(hw_ctx)->azalia_stream_id - 1,
++ DOUT_DCE_VCE_CONTROL,
++ DC_VCE_AUDIO_STREAM_SELECT);
++
++ dal_write_reg(hw_ctx->ctx,
++ addr, value);*/
++}
++
++static void enable_afmt_clock(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ bool enable_flag)
++{
++ uint32_t engine_offs = engine_offset[engine_id];
++ uint32_t value;
++ uint32_t count = 0;
++ uint32_t enable = enable_flag ? 1:0;
++
++ /* Enable Audio packets*/
++ value = dal_read_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs);
++
++ /*enable AFMT clock*/
++ set_reg_field_value(value, enable,
++ AFMT_CNTL, AFMT_AUDIO_CLOCK_EN);
++ dal_write_reg(hw_ctx->ctx, mmAFMT_CNTL + engine_offs, value);
++
++ /*wait for AFMT clock to turn on,
++ * the expectation is that this
++ * should complete in 1-2 reads)
++ */
++ do {
++ /* Wait for 1us between subsequent register reads.*/
++ dc_service_delay_in_microseconds(hw_ctx->ctx, 1);
++ value = dal_read_reg(hw_ctx->ctx,
++ mmAFMT_CNTL + engine_offs);
++ } while (get_reg_field_value(value,
++ AFMT_CNTL, AFMT_AUDIO_CLOCK_ON) !=
++ enable && count++ < 10);
++}
++
++/* enable Azalia audio */
++static void enable_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ uint32_t value;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
++
++ if (get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ AUDIO_ENABLED) != 1)
++ set_reg_field_value(value, 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ AUDIO_ENABLED);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ value);
++}
++
++/* disable Azalia audio */
++static void disable_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ uint32_t value;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL);
++
++ set_reg_field_value(value, 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ AUDIO_ENABLED);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_HOT_PLUG_CONTROL,
++ value);
++}
++
++/* enable DP audio */
++static void enable_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ const uint32_t addr = mmDP_SEC_CNTL + engine_offset[engine_id];
++
++ uint32_t value;
++
++ /* Enable Audio packets */
++ value = dal_read_reg(hw_ctx->ctx, addr);
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_ASP_ENABLE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++
++ /* Program the ATP and AIP next */
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_ATP_ENABLE);
++
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_AIP_ENABLE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++
++ /* Program STREAM_ENABLE after all the other enables. */
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++}
++
++/* disable DP audio */
++static void disable_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ const uint32_t addr = mmDP_SEC_CNTL + engine_offset[engine_id];
++
++ uint32_t value;
++
++ /* Disable Audio packets */
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_ASP_ENABLE);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_ATP_ENABLE);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_AIP_ENABLE);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_ACM_ENABLE);
++
++ set_reg_field_value(value, 0,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
++
++ /* This register shared with encoder info frame. Therefore we need to
++ keep master enabled if at least on of the fields is not 0 */
++ if (value != 0)
++ set_reg_field_value(value, 1,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++}
++
++static void configure_azalia(
++ const struct hw_ctx_audio *hw_ctx,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_info *audio_info)
++{
++ uint32_t speakers = audio_info->flags.info.ALLSPEAKERS;
++ uint32_t value;
++ uint32_t field = 0;
++ enum audio_format_code audio_format_code;
++ uint32_t format_index;
++ uint32_t index;
++ bool is_ac3_supported = false;
++ bool is_audio_format_supported = false;
++ union audio_sample_rates sample_rate;
++ uint32_t strlen = 0;
++
++ /* Speaker Allocation */
++ /*
++ uint32_t value;
++ uint32_t field = 0;*/
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
++
++ set_reg_field_value(value,
++ speakers,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ SPEAKER_ALLOCATION);
++
++ /* LFE_PLAYBACK_LEVEL = LFEPBL
++ * LFEPBL = 0 : Unknown or refer to other information
++ * LFEPBL = 1 : 0dB playback
++ * LFEPBL = 2 : +10dB playback
++ * LFE_BL = 3 : Reserved
++ */
++ set_reg_field_value(value,
++ 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ LFE_PLAYBACK_LEVEL);
++
++ set_reg_field_value(value,
++ 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ HDMI_CONNECTION);
++
++ set_reg_field_value(value,
++ 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ DP_CONNECTION);
++
++ field = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ EXTRA_CONNECTION_INFO);
++
++ field &= ~0x1;
++
++ set_reg_field_value(value,
++ field,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ EXTRA_CONNECTION_INFO);
++
++ /* set audio for output signal */
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ set_reg_field_value(value,
++ 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ HDMI_CONNECTION);
++
++ break;
++ case SIGNAL_TYPE_WIRELESS: {
++ /*LSB used for "is wireless" flag */
++ field = 0;
++ field = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ EXTRA_CONNECTION_INFO);
++ field |= 0x1;
++ set_reg_field_value(value,
++ field,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ EXTRA_CONNECTION_INFO);
++
++ set_reg_field_value(value,
++ 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ HDMI_CONNECTION);
++
++ }
++ break;
++ case SIGNAL_TYPE_EDP:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ set_reg_field_value(value,
++ 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ DP_CONNECTION);
++
++ break;
++ default:
++ break;
++ }
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER,
++ value);
++
++ /* Wireless Display identification */
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION);
++
++ set_reg_field_value(value,
++ signal == SIGNAL_TYPE_WIRELESS ? 1 : 0,
++ AZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION,
++ WIRELESS_DISPLAY_IDENTIFICATION);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_WIRELESS_DISPLAY_IDENTIFICATION,
++ value);
++
++ /* Audio Descriptors */
++ /* pass through all formats */
++ for (format_index = 0; format_index < AUDIO_FORMAT_CODE_COUNT;
++ format_index++) {
++ audio_format_code =
++ (AUDIO_FORMAT_CODE_FIRST + format_index);
++
++ /* those are unsupported, skip programming */
++ if (audio_format_code == AUDIO_FORMAT_CODE_1BITAUDIO ||
++ audio_format_code == AUDIO_FORMAT_CODE_DST)
++ continue;
++
++ value = 0;
++
++ /* check if supported */
++ is_audio_format_supported =
++ dal_audio_hw_ctx_is_audio_format_supported(
++ hw_ctx,
++ audio_info,
++ audio_format_code, &index);
++
++ if (is_audio_format_supported) {
++ const struct audio_mode *audio_mode =
++ &audio_info->modes[index];
++ union audio_sample_rates sample_rates =
++ audio_mode->sample_rates;
++ uint8_t byte2 = audio_mode->max_bit_rate;
++
++ /* adjust specific properties */
++ switch (audio_format_code) {
++ case AUDIO_FORMAT_CODE_LINEARPCM: {
++ dal_hw_ctx_audio_check_audio_bandwidth(
++ hw_ctx,
++ crtc_info,
++ audio_mode->channel_count,
++ signal,
++ &sample_rates);
++
++ byte2 = audio_mode->sample_size;
++
++ set_reg_field_value(value,
++ sample_rates.all,
++ AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
++ SUPPORTED_FREQUENCIES_STEREO);
++
++ }
++ break;
++ case AUDIO_FORMAT_CODE_AC3:
++ is_ac3_supported = true;
++ break;
++ case AUDIO_FORMAT_CODE_DOLBYDIGITALPLUS:
++ case AUDIO_FORMAT_CODE_DTS_HD:
++ case AUDIO_FORMAT_CODE_MAT_MLP:
++ case AUDIO_FORMAT_CODE_DST:
++ case AUDIO_FORMAT_CODE_WMAPRO:
++ byte2 = audio_mode->vendor_specific;
++ break;
++ default:
++ break;
++ }
++
++ /* fill audio format data */
++ set_reg_field_value(value,
++ audio_mode->channel_count - 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
++ MAX_CHANNELS);
++
++ set_reg_field_value(value,
++ sample_rates.all,
++ AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
++ SUPPORTED_FREQUENCIES);
++
++ set_reg_field_value(value,
++ byte2,
++ AZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0,
++ DESCRIPTOR_BYTE_2);
++
++ } /* if */
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0 +
++ format_index,
++ value);
++ } /* for */
++
++ if (is_ac3_supported)
++ dal_write_reg(hw_ctx->ctx,
++ mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_STREAM_FORMATS,
++ 0x05);
++
++ /* check for 192khz/8-Ch support for HBR requirements */
++ sample_rate.all = 0;
++ sample_rate.rate.RATE_192 = 1;
++ dal_hw_ctx_audio_check_audio_bandwidth(
++ hw_ctx,
++ crtc_info,
++ 8,
++ signal,
++ &sample_rate);
++
++ set_high_bit_rate_capable(hw_ctx, sample_rate.rate.RATE_192);
++
++ /* Audio and Video Lipsync */
++ set_video_latency(hw_ctx, audio_info->video_latency);
++ set_audio_latency(hw_ctx, audio_info->audio_latency);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->manufacture_id,
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
++ MANUFACTURER_ID);
++
++ set_reg_field_value(value, audio_info->product_id,
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
++ PRODUCT_ID);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO0,
++ value);
++
++
++ value = 0;
++
++ /*get display name string length */
++ while (audio_info->display_name[strlen++] != '\0') {
++ if (strlen >=
++ MAX_HW_AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS)
++ break;
++ }
++ set_reg_field_value(value, strlen,
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
++ SINK_DESCRIPTION_LEN);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO1,
++ value);
++
++
++ /*
++ *write the port ID:
++ *PORT_ID0 = display index
++ *PORT_ID1 = 16bit BDF
++ *(format MSB->LSB: 8bit Bus, 5bit Device, 3bit Function)
++ */
++
++ value = 0;
++
++ set_reg_field_value(value, audio_info->port_id[0],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2,
++ PORT_ID0);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO2,
++ value);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->port_id[1],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3,
++ PORT_ID1);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO3,
++ value);
++
++ /*write the 18 char monitor string */
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[0],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ DESCRIPTION0);
++
++ set_reg_field_value(value, audio_info->display_name[1],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ DESCRIPTION1);
++
++ set_reg_field_value(value, audio_info->display_name[2],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ DESCRIPTION2);
++
++ set_reg_field_value(value, audio_info->display_name[3],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ DESCRIPTION3);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO4,
++ value);
++
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[4],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ DESCRIPTION4);
++
++ set_reg_field_value(value, audio_info->display_name[5],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ DESCRIPTION5);
++
++ set_reg_field_value(value, audio_info->display_name[6],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ DESCRIPTION6);
++
++ set_reg_field_value(value, audio_info->display_name[7],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ DESCRIPTION7);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO5,
++ value);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[8],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ DESCRIPTION8);
++
++ set_reg_field_value(value, audio_info->display_name[9],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ DESCRIPTION9);
++
++ set_reg_field_value(value, audio_info->display_name[10],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ DESCRIPTION10);
++
++ set_reg_field_value(value, audio_info->display_name[11],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ DESCRIPTION11);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO6,
++ value);
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[12],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ DESCRIPTION12);
++
++ set_reg_field_value(value, audio_info->display_name[13],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ DESCRIPTION13);
++
++ set_reg_field_value(value, audio_info->display_name[14],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ DESCRIPTION14);
++
++ set_reg_field_value(value, audio_info->display_name[15],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ DESCRIPTION15);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO7,
++ value);
++
++
++ value = 0;
++ set_reg_field_value(value, audio_info->display_name[16],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
++ DESCRIPTION16);
++
++ set_reg_field_value(value, audio_info->display_name[17],
++ AZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
++ DESCRIPTION17);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_SINK_INFO8,
++ value);
++
++}
++
++/* setup Azalia HW block */
++static void setup_azalia(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info,
++ const struct audio_info *audio_info)
++{
++ uint32_t speakers = 0;
++ uint32_t channels = 0;
++
++ if (audio_info == NULL)
++ /* This should not happen.it does so we don't get BSOD*/
++ return;
++
++ speakers = audio_info->flags.info.ALLSPEAKERS;
++ channels = dal_audio_hw_ctx_speakers_to_channels(
++ hw_ctx,
++ audio_info->flags.speaker_flags).all;
++
++ /* setup the audio stream source select (audio -> dig mapping) */
++ {
++ const uint32_t addr =
++ mmAFMT_AUDIO_SRC_CONTROL + engine_offset[engine_id];
++
++ uint32_t value = 0;
++ /*convert one-based index to zero-based */
++ set_reg_field_value(value,
++ FROM_BASE(hw_ctx)->azalia_stream_id - 1,
++ AFMT_AUDIO_SRC_CONTROL,
++ AFMT_AUDIO_SRC_SELECT);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /* Channel allocation */
++ {
++ const uint32_t addr =
++ mmAFMT_AUDIO_PACKET_CONTROL2 + engine_offset[engine_id];
++ uint32_t value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value,
++ channels,
++ AFMT_AUDIO_PACKET_CONTROL2,
++ AFMT_AUDIO_CHANNEL_ENABLE);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ configure_azalia(hw_ctx, signal, crtc_info, audio_info);
++}
++
++/* unmute audio */
++static void unmute_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ const uint32_t addr = mmAFMT_AUDIO_PACKET_CONTROL +
++ engine_offset[engine_id];
++
++ uint32_t value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 1,
++ AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++}
++
++/* mute audio */
++static void mute_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ const uint32_t addr = mmAFMT_AUDIO_PACKET_CONTROL +
++ engine_offset[engine_id];
++
++ uint32_t value = 0;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 0,
++ AFMT_AUDIO_PACKET_CONTROL, AFMT_AUDIO_SAMPLE_SEND);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++}
++
++/* enable channel splitting mapping */
++static void setup_channel_splitting_mapping(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable)
++{
++ uint32_t value = 0;
++
++ if ((audio_mapping == NULL || audio_mapping->u32all == 0) && enable)
++ return;
++
++
++ value = audio_mapping->u32all;
++
++ if (enable == false)
++ /*0xFFFFFFFF;*/
++ value = MULTI_CHANNEL_SPLIT_NO_ASSO_INFO;
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_ASSOCIATION_INFO,
++ value);
++}
++
++/* get current channel spliting */
++static bool get_channel_splitting_mapping(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping)
++{
++ uint32_t value = 0;
++
++ if (audio_mapping == NULL)
++ return false;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_ASSOCIATION_INFO);
++
++ /*0xFFFFFFFF*/
++ if (get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_ASSOCIATION_INFO,
++ ASSOCIATION_INFO) !=
++ MULTI_CHANNEL_SPLIT_NO_ASSO_INFO) {
++ uint32_t multi_channel01_enable = 0;
++ uint32_t multi_channel23_enable = 0;
++ uint32_t multi_channel45_enable = 0;
++ uint32_t multi_channel67_enable = 0;
++ /* get the one we set.*/
++ audio_mapping->u32all = value;
++
++ /* check each enable status*/
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE);
++
++ multi_channel01_enable = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
++ MULTICHANNEL01_ENABLE);
++
++ multi_channel23_enable = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
++ MULTICHANNEL23_ENABLE);
++
++ multi_channel45_enable = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
++ MULTICHANNEL45_ENABLE);
++
++ multi_channel67_enable = get_reg_field_value(value,
++ AZALIA_F0_CODEC_PIN_CONTROL_MULTICHANNEL_ENABLE,
++ MULTICHANNEL67_ENABLE);
++
++ if (multi_channel01_enable == 0 &&
++ multi_channel23_enable == 0 &&
++ multi_channel45_enable == 0 &&
++ multi_channel67_enable == 0)
++ dal_logger_write(hw_ctx->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "Audio driver did not enable multi-channel\n");
++
++ return true;
++ }
++
++ return false;
++}
++
++/* set the payload value for the unsolicited response */
++static void set_unsolicited_response_payload(
++ const struct hw_ctx_audio *hw_ctx,
++ enum audio_payload payload)
++{
++ /* set the payload value for the unsolicited response
++ Jack presence is not required to be enabled */
++ uint32_t value = 0;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE);
++
++ set_reg_field_value(value, payload,
++ AZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
++ UNSOLICITED_RESPONSE_PAYLOAD);
++
++ set_reg_field_value(value, 1,
++ AZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
++ UNSOLICITED_RESPONSE_FORCE);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_PIN_CONTROL_UNSOLICITED_RESPONSE_FORCE,
++ value);
++}
++
++/* initialize HW state */
++static void hw_initialize(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ uint32_t stream_id = FROM_BASE(hw_ctx)->azalia_stream_id;
++ uint32_t addr;
++
++ /* we only need to program the following registers once, so we only do
++ it for the first audio stream.*/
++ if (stream_id != FIRST_AUDIO_STREAM_ID)
++ return;
++
++ /* Suport R5 - 32khz
++ * Suport R6 - 44.1khz
++ * Suport R7 - 48khz
++ */
++ addr = mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES;
++ {
++ uint32_t value;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 0x70,
++ AZALIA_F0_CODEC_FUNCTION_PARAMETER_SUPPORTED_SIZE_RATES,
++ AUDIO_RATE_CAPABILITIES);
++
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++
++ /*Keep alive bit to verify HW block in BU. */
++ addr = mmAZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES;
++ {
++ uint32_t value;
++
++ value = dal_read_reg(hw_ctx->ctx, addr);
++
++ set_reg_field_value(value, 1,
++ AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES,
++ CLKSTOP);
++
++ set_reg_field_value(value, 1,
++ AZALIA_F0_CODEC_FUNCTION_PARAMETER_POWER_STATES,
++ EPSS);
++ dal_write_reg(hw_ctx->ctx, addr, value);
++ }
++}
++
++/* Assign GTC group and enable GTC value embedding */
++static void enable_gtc_embedding_with_group(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t group_num,
++ uint32_t audio_latency)
++{
++ /*need to replace the static number with variable */
++ if (group_num <= 6) {
++ uint32_t value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING);
++
++ set_reg_field_value(
++ value,
++ group_num,
++ AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ PRESENTATION_TIME_EMBEDDING_GROUP);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ PRESENTATION_TIME_EMBEDDING_ENABLE);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ value);
++
++ /*update audio latency to LIPSYNC*/
++ set_audio_latency(hw_ctx, audio_latency);
++ } else {
++ dal_logger_write(
++ hw_ctx->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "GTC group number %d is too big",
++ group_num);
++ }
++}
++
++ /* Disable GTC value embedding */
++static void disable_gtc_embedding(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ uint32_t value = 0;
++
++ value = read_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING);
++
++ set_reg_field_value(value, 0,
++ AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ PRESENTATION_TIME_EMBEDDING_ENABLE);
++
++ set_reg_field_value(value, 0,
++ AZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ PRESENTATION_TIME_EMBEDDING_GROUP);
++
++ write_indirect_azalia_reg(
++ hw_ctx,
++ ixAZALIA_F0_CODEC_CONVERTER_CONTROL_GTC_EMBEDDING,
++ value);
++}
++
++/* search pixel clock value for Azalia HDMI Audio */
++static bool get_azalia_clock_info_hdmi(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t crtc_pixel_clock_in_khz,
++ uint32_t actual_pixel_clock_in_khz,
++ struct azalia_clock_info *azalia_clock_info)
++{
++ if (azalia_clock_info == NULL)
++ return false;
++
++ /* audio_dto_phase= 24 * 10,000;
++ * 24MHz in [100Hz] units */
++ azalia_clock_info->audio_dto_phase =
++ 24 * 10000;
++
++ /* audio_dto_module = PCLKFrequency * 10,000;
++ * [khz] -> [100Hz] */
++ azalia_clock_info->audio_dto_module =
++ actual_pixel_clock_in_khz * 10;
++
++ return true;
++}
++
++/* search pixel clock value for Azalia DP Audio */
++static bool get_azalia_clock_info_dp(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t requested_pixel_clock_in_khz,
++ const struct audio_pll_info *pll_info,
++ struct azalia_clock_info *azalia_clock_info)
++{
++ if (pll_info == NULL || azalia_clock_info == NULL)
++ return false;
++
++ /* Reported dpDtoSourceClockInkhz value for
++ * DCE8 already adjusted for SS, do not need any
++ * adjustment here anymore
++ */
++
++ /*audio_dto_phase = 24 * 10,000;
++ * 24MHz in [100Hz] units */
++ azalia_clock_info->audio_dto_phase = 24 * 10000;
++
++ /*audio_dto_module = dpDtoSourceClockInkhz * 10,000;
++ * [khz] ->[100Hz] */
++ azalia_clock_info->audio_dto_module =
++ pll_info->dp_dto_source_clock_in_khz * 10;
++
++ return true;
++}
++
++static const struct hw_ctx_audio_funcs funcs = {
++ .destroy = destroy,
++ .setup_audio_wall_dto =
++ setup_audio_wall_dto,
++ .setup_hdmi_audio =
++ setup_hdmi_audio,
++ .setup_dp_audio = setup_dp_audio,
++ .setup_vce_audio = setup_vce_audio,
++ .enable_azalia_audio =
++ enable_azalia_audio,
++ .disable_azalia_audio =
++ disable_azalia_audio,
++ .enable_dp_audio =
++ enable_dp_audio,
++ .disable_dp_audio =
++ disable_dp_audio,
++ .setup_azalia =
++ setup_azalia,
++ .disable_az_clock_gating = NULL,
++ .unmute_azalia_audio =
++ unmute_azalia_audio,
++ .mute_azalia_audio =
++ mute_azalia_audio,
++ .setup_channel_splitting_mapping =
++ setup_channel_splitting_mapping,
++ .get_channel_splitting_mapping =
++ get_channel_splitting_mapping,
++ .set_unsolicited_response_payload =
++ set_unsolicited_response_payload,
++ .hw_initialize =
++ hw_initialize,
++ .enable_gtc_embedding_with_group =
++ enable_gtc_embedding_with_group,
++ .disable_gtc_embedding =
++ disable_gtc_embedding,
++ .get_azalia_clock_info_hdmi =
++ get_azalia_clock_info_hdmi,
++ .get_azalia_clock_info_dp =
++ get_azalia_clock_info_dp,
++ .enable_afmt_clock = enable_afmt_clock
++};
++
++static bool construct(
++ struct hw_ctx_audio_dce110 *hw_ctx,
++ uint8_t azalia_stream_id,
++ struct dc_context *ctx)
++{
++ struct hw_ctx_audio *base = &hw_ctx->base;
++
++ if (!dal_audio_construct_hw_ctx_audio(base))
++ return false;
++
++ base->funcs = &funcs;
++
++ /* save audio endpoint or dig front for current dce110 audio object */
++ hw_ctx->azalia_stream_id = azalia_stream_id;
++ hw_ctx->base.ctx = ctx;
++
++ /* azalia audio endpoints register offsets. azalia is associated with
++ DIG front. save AUDIO register offset */
++ switch (azalia_stream_id) {
++ case 1: {
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index =
++ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX;
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data =
++ mmAZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA;
++ }
++ break;
++ case 2: {
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index =
++ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_INDEX;
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data =
++ mmAZF0ENDPOINT1_AZALIA_F0_CODEC_ENDPOINT_DATA;
++ }
++ break;
++ case 3: {
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index =
++ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_INDEX;
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data =
++ mmAZF0ENDPOINT2_AZALIA_F0_CODEC_ENDPOINT_DATA;
++ }
++ break;
++ case 4: {
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_index =
++ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_INDEX;
++ hw_ctx->az_mm_reg_offsets.
++ azf0endpointx_azalia_f0_codec_endpoint_data =
++ mmAZF0ENDPOINT3_AZALIA_F0_CODEC_ENDPOINT_DATA;
++ }
++ break;
++ default:
++ dal_logger_write(
++ hw_ctx->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "Invalid Azalia stream ID!");
++ break;
++ }
++
++ return true;
++}
++
++/* audio_dce110 is derived from audio directly, not via dce80 */
++struct hw_ctx_audio *dal_hw_ctx_audio_dce110_create(
++ struct dc_context *ctx,
++ uint32_t azalia_stream_id)
++{
++ /* allocate memory for struc hw_ctx_audio_dce110 */
++ struct hw_ctx_audio_dce110 *hw_ctx_dce110 =
++ dc_service_alloc(ctx, sizeof(struct hw_ctx_audio_dce110));
++
++ if (!hw_ctx_dce110) {
++ ASSERT_CRITICAL(hw_ctx_dce110);
++ return NULL;
++ }
++
++ /*return pointer to hw_ctx_audio back to caller -- audio object */
++ if (construct(
++ hw_ctx_dce110, azalia_stream_id, ctx))
++ return &hw_ctx_dce110->base;
++
++ dal_logger_write(
++ ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_AUDIO,
++ "Failed to create hw_ctx_audio for DCE11\n");
++
++
++ dc_service_free(ctx, hw_ctx_dce110);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h b/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h
+new file mode 100644
+index 0000000..1ad3826
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/dce110/hw_ctx_audio_dce110.h
+@@ -0,0 +1,47 @@
++/*
++ * 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_HW_CTX_AUDIO_DCE110_H__
++#define __DAL_HW_CTX_AUDIO_DCE110_H__
++
++#include "audio/hw_ctx_audio.h"
++
++struct hw_ctx_audio_dce110 {
++ struct hw_ctx_audio base;
++
++ /* azalia stream id 1 based indexing, corresponding to audio GO enumId*/
++ uint32_t azalia_stream_id;
++
++ /* azalia stream endpoint register offsets */
++ struct azalia_reg_offsets az_mm_reg_offsets;
++
++ /* audio encoder block MM register offset -- associate with DIG FRONT */
++};
++
++struct hw_ctx_audio *dal_hw_ctx_audio_dce110_create(
++ struct dc_context *ctx,
++ uint32_t azalia_stream_id);
++
++#endif /* __DAL_HW_CTX_AUDIO_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c b/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c
+new file mode 100644
+index 0000000..f1f1298
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.c
+@@ -0,0 +1,771 @@
++/*
++ * 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 "dal_services.h"
++
++#include "hw_ctx_audio.h"
++
++/* 25.2MHz/1.001*/
++/* 25.2MHz/1.001*/
++/* 25.2MHz*/
++/* 27MHz */
++/* 27MHz*1.001*/
++/* 27MHz*1.001*/
++/* 54MHz*/
++/* 54MHz*1.001*/
++/* 74.25MHz/1.001*/
++/* 74.25MHz*/
++/* 148.5MHz/1.001*/
++/* 148.5MHz*/
++
++static const struct audio_clock_info audio_clock_info_table[12] = {
++ {2517, 4576, 28125, 7007, 31250, 6864, 28125},
++ {2518, 4576, 28125, 7007, 31250, 6864, 28125},
++ {2520, 4096, 25200, 6272, 28000, 6144, 25200},
++ {2700, 4096, 27000, 6272, 30000, 6144, 27000},
++ {2702, 4096, 27027, 6272, 30030, 6144, 27027},
++ {2703, 4096, 27027, 6272, 30030, 6144, 27027},
++ {5400, 4096, 54000, 6272, 60000, 6144, 54000},
++ {5405, 4096, 54054, 6272, 60060, 6144, 54054},
++ {7417, 11648, 210937, 17836, 234375, 11648, 140625},
++ {7425, 4096, 74250, 6272, 82500, 6144, 74250},
++ {14835, 11648, 421875, 8918, 234375, 5824, 140625},
++ {14850, 4096, 148500, 6272, 165000, 6144, 148500}
++};
++
++static const struct audio_clock_info audio_clock_info_table_36bpc[12] = {
++ {2517, 9152, 84375, 7007, 48875, 9152, 56250},
++ {2518, 9152, 84375, 7007, 48875, 9152, 56250},
++ {2520, 4096, 37800, 6272, 42000, 6144, 37800},
++ {2700, 4096, 40500, 6272, 45000, 6144, 40500},
++ {2702, 8192, 81081, 6272, 45045, 8192, 54054},
++ {2703, 8192, 81081, 6272, 45045, 8192, 54054},
++ {5400, 4096, 81000, 6272, 90000, 6144, 81000},
++ {5405, 4096, 81081, 6272, 90090, 6144, 81081},
++ {7417, 11648, 316406, 17836, 351562, 11648, 210937},
++ {7425, 4096, 111375, 6272, 123750, 6144, 111375},
++ {14835, 11648, 632812, 17836, 703125, 11648, 421875},
++ {14850, 4096, 222750, 6272, 247500, 6144, 222750}
++};
++
++static const struct audio_clock_info audio_clock_info_table_48bpc[12] = {
++ {2517, 4576, 56250, 7007, 62500, 6864, 56250},
++ {2518, 4576, 56250, 7007, 62500, 6864, 56250},
++ {2520, 4096, 50400, 6272, 56000, 6144, 50400},
++ {2700, 4096, 54000, 6272, 60000, 6144, 54000},
++ {2702, 4096, 54054, 6267, 60060, 8192, 54054},
++ {2703, 4096, 54054, 6272, 60060, 8192, 54054},
++ {5400, 4096, 108000, 6272, 120000, 6144, 108000},
++ {5405, 4096, 108108, 6272, 120120, 6144, 108108},
++ {7417, 11648, 421875, 17836, 468750, 11648, 281250},
++ {7425, 4096, 148500, 6272, 165000, 6144, 148500},
++ {14835, 11648, 843750, 8918, 468750, 11648, 281250},
++ {14850, 4096, 297000, 6272, 330000, 6144, 297000}
++};
++
++
++/***** static function *****/
++
++/*
++ * except of HW context create function, caller will access other functions of
++ * hw ctx via handle hw_ctx. Memory allocation for struct hw_ctx_audio_dce8x
++ * will happen in hw_ctx_audio_dce8x. Memory allocation is done with
++ * dal_audio_create_hw_ctx_audio_dce8x. Memory release is done by caller
++ * via hw_ctx->functions.destroy(). It will finally use destroy() of
++ * hw_ctx_audio_dce8x. Therefore, no memory allocate and release happen
++ * physically at hw ctx base object.
++ */
++static void destroy(
++ struct hw_ctx_audio **ptr)
++{
++ /* Attention!
++ * You must override this method in derived class */
++}
++
++static void setup_audio_wall_dto(
++ const struct hw_ctx_audio *hw_ctx,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* setup HDMI audio */
++static void setup_hdmi_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ const struct audio_crtc_info *crtc_info)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++ /* setup DP audio */
++static void setup_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++ /* setup VCE audio */
++static void setup_vce_audio(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* enable Azalia audio */
++static void enable_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* disable Azalia audio */
++static void disable_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* enable DP audio */
++static void enable_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* disable DP audio */
++static void disable_dp_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* setup Azalia HW block */
++static void setup_azalia(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info,
++ const struct audio_info *audio_info)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* unmute audio */
++static void unmute_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* mute audio */
++static void mute_azalia_audio(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* enable channel splitting mapping */
++static void setup_channel_splitting_mapping(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* get current channel spliting */
++static bool get_channel_splitting_mapping(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return false;
++}
++
++/* set the payload value for the unsolicited response */
++static void set_unsolicited_response_payload(
++ const struct hw_ctx_audio *hw_ctx,
++ enum audio_payload payload)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* initialize HW state */
++static void hw_initialize(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* Assign GTC group and enable GTC value embedding */
++static void enable_gtc_embedding_with_group(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t groupNum,
++ uint32_t audioLatency)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* Disable GTC value embedding */
++static void disable_gtc_embedding(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* Disable Azalia Clock Gating Feature */
++static void disable_az_clock_gating(
++ const struct hw_ctx_audio *hw_ctx)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++}
++
++/* search pixel clock value for Azalia HDMI Audio */
++static bool get_azalia_clock_info_hdmi(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t crtc_pixel_clock_in_khz,
++ uint32_t actual_pixel_clock_in_khz,
++ struct azalia_clock_info *azalia_clock_info)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return false;
++}
++
++/* search pixel clock value for Azalia DP Audio */
++static bool get_azalia_clock_info_dp(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t requested_pixel_clock_in_khz,
++ const struct audio_pll_info *pll_info,
++ struct azalia_clock_info *azalia_clock_info)
++{
++ /*DCE specific, must be implemented in derived*/
++ BREAK_TO_DEBUGGER();
++ return false;
++}
++
++
++
++
++
++
++
++
++
++/*****SCOPE : within audio hw context dal-audio-hw-ctx *****/
++
++
++/* check whether specified sample rates can fit into a given timing */
++void dal_hw_ctx_audio_check_audio_bandwidth(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info,
++ uint32_t channel_count,
++ enum signal_type signal,
++ union audio_sample_rates *sample_rates)
++{
++ switch (signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ dal_audio_hw_ctx_check_audio_bandwidth_hdmi(
++ hw_ctx, crtc_info, channel_count, sample_rates);
++ break;
++ case SIGNAL_TYPE_EDP:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ dal_audio_hw_ctx_check_audio_bandwidth_dpsst(
++ hw_ctx, crtc_info, channel_count, sample_rates);
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ dal_audio_hw_ctx_check_audio_bandwidth_dpmst(
++ hw_ctx, crtc_info, channel_count, sample_rates);
++ break;
++ default:
++ break;
++ }
++}
++
++/*For HDMI, calculate if specified sample rates can fit into a given timing */
++void dal_audio_hw_ctx_check_audio_bandwidth_hdmi(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info,
++ uint32_t channel_count,
++ union audio_sample_rates *sample_rates)
++{
++ uint32_t samples;
++ uint32_t h_blank;
++ bool limit_freq_to_48_khz = false;
++ bool limit_freq_to_88_2_khz = false;
++ bool limit_freq_to_96_khz = false;
++ bool limit_freq_to_174_4_khz = false;
++
++ /* For two channels supported return whatever sink support,unmodified*/
++ if (channel_count > 2) {
++
++ /* Based on HDMI spec 1.3 Table 7.5 */
++ if ((crtc_info->requested_pixel_clock <= 27000) &&
++ (crtc_info->v_active <= 576) &&
++ !(crtc_info->interlaced) &&
++ !(crtc_info->pixel_repetition == 2 ||
++ crtc_info->pixel_repetition == 4)) {
++ limit_freq_to_48_khz = true;
++
++ } else if ((crtc_info->requested_pixel_clock <= 27000) &&
++ (crtc_info->v_active <= 576) &&
++ (crtc_info->interlaced) &&
++ (crtc_info->pixel_repetition == 2)) {
++ limit_freq_to_88_2_khz = true;
++
++ } else if ((crtc_info->requested_pixel_clock <= 54000) &&
++ (crtc_info->v_active <= 576) &&
++ !(crtc_info->interlaced)) {
++ limit_freq_to_174_4_khz = true;
++ }
++ }
++
++ /* Also do some calculation for the available Audio Bandwidth for the
++ * 8 ch (i.e. for the Layout 1 => ch > 2)
++ */
++ h_blank = crtc_info->h_total - crtc_info->h_active;
++
++ if (crtc_info->pixel_repetition)
++ h_blank *= crtc_info->pixel_repetition;
++
++ /*based on HDMI spec 1.3 Table 7.5 */
++ h_blank -= 58;
++ /*for Control Period */
++ h_blank -= 16;
++
++ samples = h_blank * 10;
++ /* Number of Audio Packets (multiplied by 10) per Line (for 8 ch number
++ * of Audio samples per line multiplied by 10 - Layout 1)
++ */
++ samples /= 32;
++ samples *= crtc_info->v_active;
++ /*Number of samples multiplied by 10, per second */
++ samples *= crtc_info->refresh_rate;
++ /*Number of Audio samples per second */
++ samples /= 10;
++
++ /* @todo do it after deep color is implemented
++ * 8xx - deep color bandwidth scaling
++ * Extra bandwidth is avaliable in deep color b/c link runs faster than
++ * pixel rate. This has the effect of allowing more tmds characters to
++ * be transmitted during blank
++ */
++
++ switch (crtc_info->color_depth) {
++ case COLOR_DEPTH_888:
++ samples *= 4;
++ break;
++ case COLOR_DEPTH_101010:
++ samples *= 5;
++ break;
++ case COLOR_DEPTH_121212:
++ samples *= 6;
++ break;
++ default:
++ samples *= 4;
++ break;
++ }
++
++ samples /= 4;
++
++ /*check limitation*/
++ if (samples < 88200)
++ limit_freq_to_48_khz = true;
++ else if (samples < 96000)
++ limit_freq_to_88_2_khz = true;
++ else if (samples < 176400)
++ limit_freq_to_96_khz = true;
++ else if (samples < 192000)
++ limit_freq_to_174_4_khz = true;
++
++ if (sample_rates != NULL) {
++ /* limit frequencies */
++ if (limit_freq_to_174_4_khz)
++ sample_rates->rate.RATE_192 = 0;
++
++ if (limit_freq_to_96_khz) {
++ sample_rates->rate.RATE_192 = 0;
++ sample_rates->rate.RATE_176_4 = 0;
++ }
++ if (limit_freq_to_88_2_khz) {
++ sample_rates->rate.RATE_192 = 0;
++ sample_rates->rate.RATE_176_4 = 0;
++ sample_rates->rate.RATE_96 = 0;
++ }
++ if (limit_freq_to_48_khz) {
++ sample_rates->rate.RATE_192 = 0;
++ sample_rates->rate.RATE_176_4 = 0;
++ sample_rates->rate.RATE_96 = 0;
++ sample_rates->rate.RATE_88_2 = 0;
++ }
++ }
++}
++
++/*For DP SST, calculate if specified sample rates can fit into a given timing */
++void dal_audio_hw_ctx_check_audio_bandwidth_dpsst(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info,
++ uint32_t channel_count,
++ union audio_sample_rates *sample_rates)
++{
++ /* do nothing */
++}
++
++/*For DP MST, calculate if specified sample rates can fit into a given timing */
++void dal_audio_hw_ctx_check_audio_bandwidth_dpmst(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info,
++ uint32_t channel_count,
++ union audio_sample_rates *sample_rates)
++{
++ /* do nothing */
++}
++
++/* calculate max number of Audio packets per line */
++uint32_t dal_audio_hw_ctx_calc_max_audio_packets_per_line(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info)
++{
++ uint32_t max_packets_per_line;
++
++ max_packets_per_line =
++ crtc_info->h_total - crtc_info->h_active;
++
++ if (crtc_info->pixel_repetition)
++ max_packets_per_line *= crtc_info->pixel_repetition;
++
++ /* for other hdmi features */
++ max_packets_per_line -= 58;
++ /* for Control Period */
++ max_packets_per_line -= 16;
++ /* Number of Audio Packets per Line */
++ max_packets_per_line /= 32;
++
++ return max_packets_per_line;
++}
++
++/**
++* speakersToChannels
++*
++* @brief
++* translate speakers to channels
++*
++* FL - Front Left
++* FR - Front Right
++* RL - Rear Left
++* RR - Rear Right
++* RC - Rear Center
++* FC - Front Center
++* FLC - Front Left Center
++* FRC - Front Right Center
++* RLC - Rear Left Center
++* RRC - Rear Right Center
++* LFE - Low Freq Effect
++*
++* FC
++* FLC FRC
++* FL FR
++*
++* LFE
++* ()
++*
++*
++* RL RR
++* RLC RRC
++* RC
++*
++* ch 8 7 6 5 4 3 2 1
++* 0b00000011 - - - - - - FR FL
++* 0b00000111 - - - - - LFE FR FL
++* 0b00001011 - - - - FC - FR FL
++* 0b00001111 - - - - FC LFE FR FL
++* 0b00010011 - - - RC - - FR FL
++* 0b00010111 - - - RC - LFE FR FL
++* 0b00011011 - - - RC FC - FR FL
++* 0b00011111 - - - RC FC LFE FR FL
++* 0b00110011 - - RR RL - - FR FL
++* 0b00110111 - - RR RL - LFE FR FL
++* 0b00111011 - - RR RL FC - FR FL
++* 0b00111111 - - RR RL FC LFE FR FL
++* 0b01110011 - RC RR RL - - FR FL
++* 0b01110111 - RC RR RL - LFE FR FL
++* 0b01111011 - RC RR RL FC - FR FL
++* 0b01111111 - RC RR RL FC LFE FR FL
++* 0b11110011 RRC RLC RR RL - - FR FL
++* 0b11110111 RRC RLC RR RL - LFE FR FL
++* 0b11111011 RRC RLC RR RL FC - FR FL
++* 0b11111111 RRC RLC RR RL FC LFE FR FL
++* 0b11000011 FRC FLC - - - - FR FL
++* 0b11000111 FRC FLC - - - LFE FR FL
++* 0b11001011 FRC FLC - - FC - FR FL
++* 0b11001111 FRC FLC - - FC LFE FR FL
++* 0b11010011 FRC FLC - RC - - FR FL
++* 0b11010111 FRC FLC - RC - LFE FR FL
++* 0b11011011 FRC FLC - RC FC - FR FL
++* 0b11011111 FRC FLC - RC FC LFE FR FL
++* 0b11110011 FRC FLC RR RL - - FR FL
++* 0b11110111 FRC FLC RR RL - LFE FR FL
++* 0b11111011 FRC FLC RR RL FC - FR FL
++* 0b11111111 FRC FLC RR RL FC LFE FR FL
++*
++* @param
++* speakers - speaker information as it comes from CEA audio block
++*/
++/* translate speakers to channels */
++union audio_cea_channels dal_audio_hw_ctx_speakers_to_channels(
++ const struct hw_ctx_audio *hw_ctx,
++ struct audio_speaker_flags speaker_flags)
++{
++ union audio_cea_channels cea_channels = {0};
++
++ /* these are one to one */
++ cea_channels.channels.FL = speaker_flags.FL_FR;
++ cea_channels.channels.FR = speaker_flags.FL_FR;
++ cea_channels.channels.LFE = speaker_flags.LFE;
++ cea_channels.channels.FC = speaker_flags.FC;
++
++ /* if Rear Left and Right exist move RC speaker to channel 7
++ * otherwise to channel 5
++ */
++ if (speaker_flags.RL_RR) {
++ cea_channels.channels.RL_RC = speaker_flags.RL_RR;
++ cea_channels.channels.RR = speaker_flags.RL_RR;
++ cea_channels.channels.RC_RLC_FLC = speaker_flags.RC;
++ } else {
++ cea_channels.channels.RL_RC = speaker_flags.RC;
++ }
++
++ /* FRONT Left Right Center and REAR Left Right Center are exclusive */
++ if (speaker_flags.FLC_FRC) {
++ cea_channels.channels.RC_RLC_FLC = speaker_flags.FLC_FRC;
++ cea_channels.channels.RRC_FRC = speaker_flags.FLC_FRC;
++ } else {
++ cea_channels.channels.RC_RLC_FLC = speaker_flags.RLC_RRC;
++ cea_channels.channels.RRC_FRC = speaker_flags.RLC_RRC;
++ }
++
++ return cea_channels;
++}
++
++/* check whether specified audio format supported */
++bool dal_audio_hw_ctx_is_audio_format_supported(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_info *audio_info,
++ enum audio_format_code audio_format_code,
++ uint32_t *format_index)
++{
++ uint32_t index;
++ uint32_t max_channe_index = 0;
++ bool found = false;
++
++ if (audio_info == NULL)
++ return found;
++
++ /* pass through whole array */
++ for (index = 0; index < audio_info->mode_count; index++) {
++ if (audio_info->modes[index].format_code == audio_format_code) {
++ if (found) {
++ /* format has multiply entries, choose one with
++ * highst number of channels */
++ if (audio_info->modes[index].channel_count >
++ audio_info->modes[max_channe_index].channel_count) {
++ max_channe_index = index;
++ }
++ } else {
++ /* format found, save it's index */
++ found = true;
++ max_channe_index = index;
++ }
++ }
++ }
++
++ /* return index */
++ if (found && format_index != NULL)
++ *format_index = max_channe_index;
++
++ return found;
++}
++
++/* search pixel clock value for HDMI */
++bool dal_audio_hw_ctx_get_audio_clock_info(
++ const struct hw_ctx_audio *hw_ctx,
++ enum dc_color_depth color_depth,
++ uint32_t crtc_pixel_clock_in_khz,
++ uint32_t actual_pixel_clock_in_khz,
++ struct audio_clock_info *audio_clock_info)
++{
++ const struct audio_clock_info *clock_info;
++ uint32_t index;
++ uint32_t crtc_pixel_clock_in_10khz = crtc_pixel_clock_in_khz / 10;
++ uint32_t audio_array_size;
++
++ if (audio_clock_info == NULL)
++ return false; /* should not happen */
++
++ switch (color_depth) {
++ case COLOR_DEPTH_161616:
++ clock_info = audio_clock_info_table_48bpc;
++ audio_array_size = ARRAY_SIZE(
++ audio_clock_info_table_48bpc);
++ break;
++ case COLOR_DEPTH_121212:
++ clock_info = audio_clock_info_table_36bpc;
++ audio_array_size = ARRAY_SIZE(
++ audio_clock_info_table_36bpc);
++ break;
++ default:
++ clock_info = audio_clock_info_table;
++ audio_array_size = ARRAY_SIZE(
++ audio_clock_info_table);
++ break;
++ }
++
++ if (clock_info != NULL) {
++ /* search for exact pixel clock in table */
++ for (index = 0; index < audio_array_size; index++) {
++ if (clock_info[index].pixel_clock_in_10khz >
++ crtc_pixel_clock_in_10khz)
++ break; /* not match */
++ else if (clock_info[index].pixel_clock_in_10khz ==
++ crtc_pixel_clock_in_10khz) {
++ /* match found */
++ if (audio_clock_info != NULL) {
++ *audio_clock_info = clock_info[index];
++ return true;
++ }
++ }
++ }
++ }
++
++
++ /* not found */
++ if (actual_pixel_clock_in_khz == 0)
++ actual_pixel_clock_in_khz = crtc_pixel_clock_in_khz;
++
++ /* See HDMI spec the table entry under
++ * pixel clock of "Other". */
++ audio_clock_info->pixel_clock_in_10khz =
++ actual_pixel_clock_in_khz / 10;
++ audio_clock_info->cts_32khz = actual_pixel_clock_in_khz;
++ audio_clock_info->cts_44khz = actual_pixel_clock_in_khz;
++ audio_clock_info->cts_48khz = actual_pixel_clock_in_khz;
++
++ audio_clock_info->n_32khz = 4096;
++ audio_clock_info->n_44khz = 6272;
++ audio_clock_info->n_48khz = 6144;
++
++ return true;
++}
++
++static const struct hw_ctx_audio_funcs funcs = {
++ .destroy = destroy,
++ .setup_audio_wall_dto =
++ setup_audio_wall_dto,
++ .setup_hdmi_audio =
++ setup_hdmi_audio,
++ .setup_dp_audio = setup_dp_audio,
++ .setup_vce_audio = setup_vce_audio,
++ .enable_azalia_audio =
++ enable_azalia_audio,
++ .disable_azalia_audio =
++ disable_azalia_audio,
++ .enable_dp_audio =
++ enable_dp_audio,
++ .disable_dp_audio =
++ disable_dp_audio,
++ .setup_azalia =
++ setup_azalia,
++ .disable_az_clock_gating =
++ disable_az_clock_gating,
++ .unmute_azalia_audio =
++ unmute_azalia_audio,
++ .mute_azalia_audio =
++ mute_azalia_audio,
++ .setup_channel_splitting_mapping =
++ setup_channel_splitting_mapping,
++ .get_channel_splitting_mapping =
++ get_channel_splitting_mapping,
++ .set_unsolicited_response_payload =
++ set_unsolicited_response_payload,
++ .hw_initialize =
++ hw_initialize,
++ .enable_gtc_embedding_with_group =
++ enable_gtc_embedding_with_group,
++ .disable_gtc_embedding =
++ disable_gtc_embedding,
++ .get_azalia_clock_info_hdmi =
++ get_azalia_clock_info_hdmi,
++ .get_azalia_clock_info_dp =
++ get_azalia_clock_info_dp,
++};
++/* --- object creator, destroy, construct, destruct --- */
++
++bool dal_audio_construct_hw_ctx_audio(
++ struct hw_ctx_audio *ctx)
++{
++ ctx->funcs = &funcs;
++
++ /* internal variables */
++
++ return true;
++}
++
++void dal_audio_destruct_hw_ctx_audio(
++ struct hw_ctx_audio *ctx)
++{
++ /* nothing to do */
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h b/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h
+new file mode 100644
+index 0000000..8ab2e58
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/audio/hw_ctx_audio.h
+@@ -0,0 +1,285 @@
++/*
++ * 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_HW_CTX_AUDIO_H__
++#define __DAL_HW_CTX_AUDIO_H__
++
++#include "include/audio_interface.h"
++#include "include/link_service_types.h"
++
++struct hw_ctx_audio;
++
++
++struct azalia_reg_offsets {
++ uint32_t azf0endpointx_azalia_f0_codec_endpoint_index;
++ uint32_t azf0endpointx_azalia_f0_codec_endpoint_data;
++};
++
++/***** hook functions *****/
++
++struct hw_ctx_audio_funcs {
++
++ /* functions for hw_ctx creation */
++ void (*destroy)(
++ struct hw_ctx_audio **ptr);
++
++ /***** from dal2 hwcontextaudio.hpp *****/
++
++ void (*setup_audio_wall_dto)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info);
++
++ /* MM register access read_register write_register */
++
++ /***** from dal2 hwcontextaudio_hal.hpp *****/
++
++ /* setup HDMI audio */
++ void (*setup_hdmi_audio)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ const struct audio_crtc_info *crtc_info);
++
++ /* setup DP audio */
++ void (*setup_dp_audio)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id);
++
++ /* setup VCE audio */
++ void (*setup_vce_audio)(
++ const struct hw_ctx_audio *hw_ctx);
++
++ /* enable Azalia audio */
++ void (*enable_azalia_audio)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id);
++
++ /* disable Azalia audio */
++ void (*disable_azalia_audio)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id);
++
++ /* enable DP audio */
++ void (*enable_dp_audio)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id);
++
++ /* disable DP audio */
++ void (*disable_dp_audio)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id);
++
++ /* setup Azalia HW block */
++ void (*setup_azalia)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info,
++ const struct audio_info *audio_info);
++
++ /* unmute audio */
++ void (*unmute_azalia_audio)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id);
++
++ /* mute audio */
++ void (*mute_azalia_audio)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id);
++
++ /* enable channel splitting mapping */
++ void (*setup_channel_splitting_mapping)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable);
++
++ /* get current channel spliting */
++ bool (*get_channel_splitting_mapping)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping);
++
++ /* set the payload value for the unsolicited response */
++ void (*set_unsolicited_response_payload)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum audio_payload payload);
++
++ /* initialize HW state */
++ void (*hw_initialize)(
++ const struct hw_ctx_audio *hw_ctx);
++
++ /* check_audio_bandwidth */
++
++ /* Assign GTC group and enable GTC value embedding */
++ void (*enable_gtc_embedding_with_group)(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t groupNum,
++ uint32_t audioLatency);
++
++ /* Disable GTC value embedding */
++ void (*disable_gtc_embedding)(
++ const struct hw_ctx_audio *hw_ctx);
++
++ /* Disable Azalia Clock Gating Feature */
++ void (*disable_az_clock_gating)(
++ const struct hw_ctx_audio *hw_ctx);
++
++ /* ~~~~ protected: ~~~~*/
++
++ /* calc_max_audio_packets_per_line */
++ /* speakers_to_channels */
++ /* is_audio_format_supported */
++ /* get_audio_clock_info */
++
++ /* search pixel clock value for Azalia HDMI Audio */
++ bool (*get_azalia_clock_info_hdmi)(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t crtc_pixel_clock_in_khz,
++ uint32_t actual_pixel_clock_in_khz,
++ struct azalia_clock_info *azalia_clock_info);
++
++ /* search pixel clock value for Azalia DP Audio */
++ bool (*get_azalia_clock_info_dp)(
++ const struct hw_ctx_audio *hw_ctx,
++ uint32_t requested_pixel_clock_in_khz,
++ const struct audio_pll_info *pll_info,
++ struct azalia_clock_info *azalia_clock_info);
++
++ void (*enable_afmt_clock)(
++ const struct hw_ctx_audio *hw_ctx,
++ enum engine_id engine_id,
++ bool enable);
++
++ /* @@@@ private: @@@@ */
++
++ /* check_audio_bandwidth_hdmi */
++ /* check_audio_bandwidth_dpsst */
++ /* check_audio_bandwidth_dpmst */
++
++};
++
++
++struct hw_ctx_audio {
++ const struct hw_ctx_audio_funcs *funcs;
++ struct dc_context *ctx;
++
++ /*audio_clock_infoTable[12];
++ *audio_clock_infoTable_36bpc[12];
++ *audio_clock_infoTable_48bpc[12];
++ *used by hw_ctx_audio.c file only. Will declare as static array
++ *azaliaclockinfoTable[12] -- not used
++ *BusNumberMask; BusNumberShift; DeviceNumberMask;
++ *not used by dce6 and after
++ */
++};
++
++
++
++/* --- object construct, destruct --- */
++
++/*
++ *called by derived audio object for specific ASIC. In case no derived object,
++ *these two functions do not need exposed.
++ */
++bool dal_audio_construct_hw_ctx_audio(
++ struct hw_ctx_audio *hw_ctx);
++
++void dal_audio_destruct_hw_ctx_audio(
++ struct hw_ctx_audio *hw_ctx);
++
++/*
++ *creator of audio HW context will be implemented by specific ASIC object only.
++ *Top base or interface object does not have implementation of creator.
++ */
++
++
++/* --- functions called by audio hw context itself --- */
++
++/* MM register access */
++/*read_register - dal_read_reg */
++/*write_register - dal_write_reg*/
++
++
++/*check whether specified sample rates can fit into a given timing */
++void dal_hw_ctx_audio_check_audio_bandwidth(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info,
++ uint32_t channel_count,
++ enum signal_type signal,
++ union audio_sample_rates *sample_rates);
++
++/*For HDMI, calculate if specified sample rates can fit into a given timing */
++void dal_audio_hw_ctx_check_audio_bandwidth_hdmi(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info,
++ uint32_t channel_count,
++ union audio_sample_rates *sample_rates);
++
++/*For DPSST, calculate if specified sample rates can fit into a given timing */
++void dal_audio_hw_ctx_check_audio_bandwidth_dpsst(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info,
++ uint32_t channel_count,
++ union audio_sample_rates *sample_rates);
++
++/*For DPMST, calculate if specified sample rates can fit into a given timing */
++void dal_audio_hw_ctx_check_audio_bandwidth_dpmst(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info,
++ uint32_t channel_count,
++ union audio_sample_rates *sample_rates);
++
++/* calculate max number of Audio packets per line */
++uint32_t dal_audio_hw_ctx_calc_max_audio_packets_per_line(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_crtc_info *crtc_info);
++
++/* translate speakers to channels */
++union audio_cea_channels dal_audio_hw_ctx_speakers_to_channels(
++ const struct hw_ctx_audio *hw_ctx,
++ struct audio_speaker_flags speaker_flags);
++
++/* check whether specified audio format supported */
++bool dal_audio_hw_ctx_is_audio_format_supported(
++ const struct hw_ctx_audio *hw_ctx,
++ const struct audio_info *audio_info,
++ enum audio_format_code audio_format_code,
++ uint32_t *format_index);
++
++/* search pixel clock value for HDMI */
++bool dal_audio_hw_ctx_get_audio_clock_info(
++ const struct hw_ctx_audio *hw_ctx,
++ enum dc_color_depth color_depth,
++ uint32_t crtc_pixel_clock_in_khz,
++ uint32_t actual_pixel_clock_in_khz,
++ struct audio_clock_info *audio_clock_info);
++
++
++#endif /* __DAL_HW_CTX_AUDIO_H__ */
++
+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 0000000..93e2371
+--- /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 fixpt31_32.o fixpt32_32.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 0000000..8c38206
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/basics/conversion.c
+@@ -0,0 +1,223 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#include "dal_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 0000000..24ff473
+--- /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/fixpt31_32.c b/drivers/gpu/drm/amd/dal/dc/basics/fixpt31_32.c
+new file mode 100644
+index 0000000..6ce75b3
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/basics/fixpt31_32.c
+@@ -0,0 +1,692 @@
++/*
++ * 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 "dal_services.h"
++#include "include/fixed31_32.h"
++
++static inline uint64_t abs_i64(
++ int64_t arg)
++{
++ if (arg > 0)
++ return (uint64_t)arg;
++ else
++ return (uint64_t)(-arg);
++}
++
++/*
++ * @brief
++ * result = dividend / divisor
++ * *remainder = dividend % divisor
++ */
++static inline uint64_t complete_integer_division_u64(
++ uint64_t dividend,
++ uint64_t divisor,
++ uint64_t *remainder)
++{
++ uint64_t result;
++
++ ASSERT(divisor);
++
++ result = div64_u64_rem(dividend, divisor, remainder);
++
++ return result;
++}
++
++#define BITS_PER_FRACTIONAL_PART \
++ 32
++
++#define FRACTIONAL_PART_MASK \
++ ((1ULL << BITS_PER_FRACTIONAL_PART) - 1)
++
++#define GET_INTEGER_PART(x) \
++ ((x) >> BITS_PER_FRACTIONAL_PART)
++
++#define GET_FRACTIONAL_PART(x) \
++ (FRACTIONAL_PART_MASK & (x))
++
++struct fixed31_32 dal_fixed31_32_from_fraction(
++ int64_t numerator,
++ int64_t denominator)
++{
++ struct fixed31_32 res;
++
++ bool arg1_negative = numerator < 0;
++ bool arg2_negative = denominator < 0;
++
++ uint64_t arg1_value = arg1_negative ? -numerator : numerator;
++ uint64_t arg2_value = arg2_negative ? -denominator : denominator;
++
++ uint64_t remainder;
++
++ /* determine integer part */
++
++ uint64_t res_value = complete_integer_division_u64(
++ arg1_value, arg2_value, &remainder);
++
++ ASSERT(res_value <= LONG_MAX);
++
++ /* determine fractional part */
++ {
++ uint32_t i = BITS_PER_FRACTIONAL_PART;
++
++ do {
++ remainder <<= 1;
++
++ res_value <<= 1;
++
++ if (remainder >= arg2_value) {
++ res_value |= 1;
++ remainder -= arg2_value;
++ }
++ } while (--i != 0);
++ }
++
++ /* round up LSB */
++ {
++ uint64_t summand = (remainder << 1) >= arg2_value;
++
++ ASSERT(res_value <= LLONG_MAX - summand);
++
++ res_value += summand;
++ }
++
++ res.value = (int64_t)res_value;
++
++ if (arg1_negative ^ arg2_negative)
++ res.value = -res.value;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_from_int(
++ int64_t arg)
++{
++ struct fixed31_32 res;
++
++ ASSERT((LONG_MIN <= arg) && (arg <= LONG_MAX));
++
++ res.value = arg << BITS_PER_FRACTIONAL_PART;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_neg(
++ struct fixed31_32 arg)
++{
++ struct fixed31_32 res;
++
++ res.value = -arg.value;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_abs(
++ struct fixed31_32 arg)
++{
++ if (arg.value < 0)
++ return dal_fixed31_32_neg(arg);
++ else
++ return arg;
++}
++
++bool dal_fixed31_32_lt(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ return arg1.value < arg2.value;
++}
++
++bool dal_fixed31_32_le(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ return arg1.value <= arg2.value;
++}
++
++bool dal_fixed31_32_eq(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ return arg1.value == arg2.value;
++}
++
++struct fixed31_32 dal_fixed31_32_min(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ if (arg1.value <= arg2.value)
++ return arg1;
++ else
++ return arg2;
++}
++
++struct fixed31_32 dal_fixed31_32_max(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ if (arg1.value <= arg2.value)
++ return arg2;
++ else
++ return arg1;
++}
++
++struct fixed31_32 dal_fixed31_32_clamp(
++ struct fixed31_32 arg,
++ struct fixed31_32 min_value,
++ struct fixed31_32 max_value)
++{
++ if (dal_fixed31_32_le(arg, min_value))
++ return min_value;
++ else if (dal_fixed31_32_le(max_value, arg))
++ return max_value;
++ else
++ return arg;
++}
++
++struct fixed31_32 dal_fixed31_32_shl(
++ struct fixed31_32 arg,
++ uint8_t shift)
++{
++ struct fixed31_32 res;
++
++ ASSERT(((arg.value >= 0) && (arg.value <= LLONG_MAX >> shift)) ||
++ ((arg.value < 0) && (arg.value >= LLONG_MIN >> shift)));
++
++ res.value = arg.value << shift;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_shr(
++ struct fixed31_32 arg,
++ uint8_t shift)
++{
++ struct fixed31_32 res;
++
++ ASSERT(shift < 64);
++
++ res.value = arg.value >> shift;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_add(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ struct fixed31_32 res;
++
++ ASSERT(((arg1.value >= 0) && (LLONG_MAX - arg1.value >= arg2.value)) ||
++ ((arg1.value < 0) && (LLONG_MIN - arg1.value <= arg2.value)));
++
++ res.value = arg1.value + arg2.value;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_sub_int(
++ struct fixed31_32 arg1,
++ int32_t arg2)
++{
++ return dal_fixed31_32_sub(
++ arg1,
++ dal_fixed31_32_from_int(arg2));
++}
++
++struct fixed31_32 dal_fixed31_32_sub(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ struct fixed31_32 res;
++
++ ASSERT(((arg2.value >= 0) && (LLONG_MIN + arg2.value <= arg1.value)) ||
++ ((arg2.value < 0) && (LLONG_MAX + arg2.value >= arg1.value)));
++
++ res.value = arg1.value - arg2.value;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_mul_int(
++ struct fixed31_32 arg1,
++ int32_t arg2)
++{
++ return dal_fixed31_32_mul(
++ arg1,
++ dal_fixed31_32_from_int(arg2));
++}
++
++struct fixed31_32 dal_fixed31_32_mul(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ struct fixed31_32 res;
++
++ bool arg1_negative = arg1.value < 0;
++ bool arg2_negative = arg2.value < 0;
++
++ uint64_t arg1_value = arg1_negative ? -arg1.value : arg1.value;
++ uint64_t arg2_value = arg2_negative ? -arg2.value : arg2.value;
++
++ uint64_t arg1_int = GET_INTEGER_PART(arg1_value);
++ uint64_t arg2_int = GET_INTEGER_PART(arg2_value);
++
++ uint64_t arg1_fra = GET_FRACTIONAL_PART(arg1_value);
++ uint64_t arg2_fra = GET_FRACTIONAL_PART(arg2_value);
++
++ uint64_t tmp;
++
++ res.value = arg1_int * arg2_int;
++
++ ASSERT(res.value <= LONG_MAX);
++
++ res.value <<= BITS_PER_FRACTIONAL_PART;
++
++ tmp = arg1_int * arg2_fra;
++
++ ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value));
++
++ res.value += tmp;
++
++ tmp = arg2_int * arg1_fra;
++
++ ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value));
++
++ res.value += tmp;
++
++ tmp = arg1_fra * arg2_fra;
++
++ tmp = (tmp >> BITS_PER_FRACTIONAL_PART) +
++ (tmp >= (uint64_t)dal_fixed31_32_half.value);
++
++ ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value));
++
++ res.value += tmp;
++
++ if (arg1_negative ^ arg2_negative)
++ res.value = -res.value;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_sqr(
++ struct fixed31_32 arg)
++{
++ struct fixed31_32 res;
++
++ uint64_t arg_value = abs_i64(arg.value);
++
++ uint64_t arg_int = GET_INTEGER_PART(arg_value);
++
++ uint64_t arg_fra = GET_FRACTIONAL_PART(arg_value);
++
++ uint64_t tmp;
++
++ res.value = arg_int * arg_int;
++
++ ASSERT(res.value <= LONG_MAX);
++
++ res.value <<= BITS_PER_FRACTIONAL_PART;
++
++ tmp = arg_int * arg_fra;
++
++ ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value));
++
++ res.value += tmp;
++
++ ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value));
++
++ res.value += tmp;
++
++ tmp = arg_fra * arg_fra;
++
++ tmp = (tmp >> BITS_PER_FRACTIONAL_PART) +
++ (tmp >= (uint64_t)dal_fixed31_32_half.value);
++
++ ASSERT(tmp <= (uint64_t)(LLONG_MAX - res.value));
++
++ res.value += tmp;
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_div_int(
++ struct fixed31_32 arg1,
++ int64_t arg2)
++{
++ return dal_fixed31_32_from_fraction(
++ arg1.value,
++ dal_fixed31_32_from_int(arg2).value);
++}
++
++struct fixed31_32 dal_fixed31_32_div(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ return dal_fixed31_32_from_fraction(
++ arg1.value,
++ arg2.value);
++}
++
++struct fixed31_32 dal_fixed31_32_recip(
++ struct fixed31_32 arg)
++{
++ /*
++ * @note
++ * Good idea to use Newton's method
++ */
++
++ ASSERT(arg.value);
++
++ return dal_fixed31_32_from_fraction(
++ dal_fixed31_32_one.value,
++ arg.value);
++}
++
++struct fixed31_32 dal_fixed31_32_sinc(
++ struct fixed31_32 arg)
++{
++ struct fixed31_32 square;
++
++ struct fixed31_32 res = dal_fixed31_32_one;
++
++ int32_t n = 27;
++
++ struct fixed31_32 arg_norm = arg;
++
++ if (dal_fixed31_32_le(
++ dal_fixed31_32_two_pi,
++ dal_fixed31_32_abs(arg))) {
++ arg_norm = dal_fixed31_32_sub(
++ arg_norm,
++ dal_fixed31_32_mul_int(
++ dal_fixed31_32_two_pi,
++ (int32_t)div64_s64(
++ arg_norm.value,
++ dal_fixed31_32_two_pi.value)));
++ }
++
++ square = dal_fixed31_32_sqr(arg_norm);
++
++ do {
++ res = dal_fixed31_32_sub(
++ dal_fixed31_32_one,
++ dal_fixed31_32_div_int(
++ dal_fixed31_32_mul(
++ square,
++ res),
++ n * (n - 1)));
++
++ n -= 2;
++ } while (n > 2);
++
++ if (arg.value != arg_norm.value)
++ res = dal_fixed31_32_div(
++ dal_fixed31_32_mul(res, arg_norm),
++ arg);
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_sin(
++ struct fixed31_32 arg)
++{
++ return dal_fixed31_32_mul(
++ arg,
++ dal_fixed31_32_sinc(arg));
++}
++
++struct fixed31_32 dal_fixed31_32_cos(
++ struct fixed31_32 arg)
++{
++ /* TODO implement argument normalization */
++
++ const struct fixed31_32 square = dal_fixed31_32_sqr(arg);
++
++ struct fixed31_32 res = dal_fixed31_32_one;
++
++ int32_t n = 26;
++
++ do {
++ res = dal_fixed31_32_sub(
++ dal_fixed31_32_one,
++ dal_fixed31_32_div_int(
++ dal_fixed31_32_mul(
++ square,
++ res),
++ n * (n - 1)));
++
++ n -= 2;
++ } while (n != 0);
++
++ return res;
++}
++
++/*
++ * @brief
++ * result = exp(arg),
++ * where abs(arg) < 1
++ *
++ * Calculated as Taylor series.
++ */
++static struct fixed31_32 fixed31_32_exp_from_taylor_series(
++ struct fixed31_32 arg)
++{
++ uint32_t n = 9;
++
++ struct fixed31_32 res = dal_fixed31_32_from_fraction(
++ n + 2,
++ n + 1);
++ /* TODO find correct res */
++
++ ASSERT(dal_fixed31_32_lt(arg, dal_fixed31_32_one));
++
++ do
++ res = dal_fixed31_32_add(
++ dal_fixed31_32_one,
++ dal_fixed31_32_div_int(
++ dal_fixed31_32_mul(
++ arg,
++ res),
++ n));
++ while (--n != 1);
++
++ return dal_fixed31_32_add(
++ dal_fixed31_32_one,
++ dal_fixed31_32_mul(
++ arg,
++ res));
++}
++
++struct fixed31_32 dal_fixed31_32_exp(
++ struct fixed31_32 arg)
++{
++ /*
++ * @brief
++ * Main equation is:
++ * exp(x) = exp(r + m * ln(2)) = (1 << m) * exp(r),
++ * where m = round(x / ln(2)), r = x - m * ln(2)
++ */
++
++ if (dal_fixed31_32_le(
++ dal_fixed31_32_ln2_div_2,
++ dal_fixed31_32_abs(arg))) {
++ int32_t m = dal_fixed31_32_round(
++ dal_fixed31_32_div(
++ arg,
++ dal_fixed31_32_ln2));
++
++ struct fixed31_32 r = dal_fixed31_32_sub(
++ arg,
++ dal_fixed31_32_mul_int(
++ dal_fixed31_32_ln2,
++ m));
++
++ ASSERT(m != 0);
++
++ ASSERT(dal_fixed31_32_lt(
++ dal_fixed31_32_abs(r),
++ dal_fixed31_32_one));
++
++ if (m > 0)
++ return dal_fixed31_32_shl(
++ fixed31_32_exp_from_taylor_series(r),
++ (uint8_t)m);
++ else
++ return dal_fixed31_32_div_int(
++ fixed31_32_exp_from_taylor_series(r),
++ 1LL << -m);
++ } else if (arg.value != 0)
++ return fixed31_32_exp_from_taylor_series(arg);
++ else
++ return dal_fixed31_32_one;
++}
++
++struct fixed31_32 dal_fixed31_32_log(
++ struct fixed31_32 arg)
++{
++ struct fixed31_32 res = dal_fixed31_32_neg(dal_fixed31_32_one);
++ /* TODO improve 1st estimation */
++
++ struct fixed31_32 error;
++
++ ASSERT(arg.value > 0);
++ /* TODO if arg is negative, return NaN */
++ /* TODO if arg is zero, return -INF */
++
++ do {
++ struct fixed31_32 res1 = dal_fixed31_32_add(
++ dal_fixed31_32_sub(
++ res,
++ dal_fixed31_32_one),
++ dal_fixed31_32_div(
++ arg,
++ dal_fixed31_32_exp(res)));
++
++ error = dal_fixed31_32_sub(
++ res,
++ res1);
++
++ res = res1;
++ /* TODO determine max_allowed_error based on quality of exp() */
++ } while (abs_i64(error.value) > 100ULL);
++
++ return res;
++}
++
++struct fixed31_32 dal_fixed31_32_pow(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2)
++{
++ return dal_fixed31_32_exp(
++ dal_fixed31_32_mul(
++ dal_fixed31_32_log(arg1),
++ arg2));
++}
++
++int32_t dal_fixed31_32_floor(
++ struct fixed31_32 arg)
++{
++ uint64_t arg_value = abs_i64(arg.value);
++
++ if (arg.value >= 0)
++ return (int32_t)GET_INTEGER_PART(arg_value);
++ else
++ return -(int32_t)GET_INTEGER_PART(arg_value);
++}
++
++int32_t dal_fixed31_32_round(
++ struct fixed31_32 arg)
++{
++ uint64_t arg_value = abs_i64(arg.value);
++
++ const int64_t summand = dal_fixed31_32_half.value;
++
++ ASSERT(LLONG_MAX - (int64_t)arg_value >= summand);
++
++ arg_value += summand;
++
++ if (arg.value >= 0)
++ return (int32_t)GET_INTEGER_PART(arg_value);
++ else
++ return -(int32_t)GET_INTEGER_PART(arg_value);
++}
++
++int32_t dal_fixed31_32_ceil(
++ struct fixed31_32 arg)
++{
++ uint64_t arg_value = abs_i64(arg.value);
++
++ const int64_t summand = dal_fixed31_32_one.value -
++ dal_fixed31_32_epsilon.value;
++
++ ASSERT(LLONG_MAX - (int64_t)arg_value >= summand);
++
++ arg_value += summand;
++
++ if (arg.value >= 0)
++ return (int32_t)GET_INTEGER_PART(arg_value);
++ else
++ return -(int32_t)GET_INTEGER_PART(arg_value);
++}
++
++/* this function is a generic helper to translate fixed point value to
++ * specified integer format that will consist of integer_bits integer part and
++ * fractional_bits fractional part. For example it is used in
++ * dal_fixed31_32_u2d19 to receive 2 bits integer part and 19 bits fractional
++ * part in 32 bits. It is used in hw programming (scaler)
++ */
++
++static inline uint32_t ux_dy(
++ int64_t value,
++ uint32_t integer_bits,
++ uint32_t fractional_bits)
++{
++ /* 1. create mask of integer part */
++ uint32_t result =
++ (1 << integer_bits) - 1;
++ /* 2. mask out fractional part */
++ uint32_t fractional_part = FRACTIONAL_PART_MASK & value;
++ /* 3. shrink fixed point integer part to be of integer_bits width*/
++ result &= GET_INTEGER_PART(value);
++ /* 4. make space for fractional part to be filled in after integer */
++ result <<= fractional_bits;
++ /* 5. shrink fixed point fractional part to of fractional_bits width*/
++ fractional_part >>= BITS_PER_FRACTIONAL_PART - fractional_bits;
++ /* 6. merge the result */
++ return result | fractional_part;
++}
++
++uint32_t dal_fixed31_32_u2d19(
++ struct fixed31_32 arg)
++{
++ return ux_dy(arg.value, 2, 19);
++}
++
++uint32_t dal_fixed31_32_u0d19(
++ struct fixed31_32 arg)
++{
++ return ux_dy(arg.value, 0, 19);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/basics/fixpt32_32.c b/drivers/gpu/drm/amd/dal/dc/basics/fixpt32_32.c
+new file mode 100644
+index 0000000..1140132
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/basics/fixpt32_32.c
+@@ -0,0 +1,223 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#include "dal_services.h"
++#include "include/fixed32_32.h"
++
++static uint64_t u64_div(uint64_t n, uint64_t d)
++{
++ uint32_t i = 0;
++ uint64_t r;
++ uint64_t q = div64_u64_rem(n, d, &r);
++
++ for (i = 0; i < 32; ++i) {
++ uint64_t sbit = q & (1ULL<<63);
++
++ r <<= 1;
++ r |= sbit ? 1 : 0;
++ q <<= 1;
++ if (r >= d) {
++ r -= d;
++ q |= 1;
++ }
++ }
++
++ if (2*r >= d)
++ q += 1;
++ return q;
++}
++
++struct fixed32_32 dal_fixed32_32_from_fraction(uint32_t n, uint32_t d)
++{
++ struct fixed32_32 fx;
++
++ fx.value = u64_div((uint64_t)n << 32, (uint64_t)d << 32);
++ return fx;
++}
++
++struct fixed32_32 dal_fixed32_32_from_int(uint32_t value)
++{
++ struct fixed32_32 fx;
++
++ fx.value = (uint64_t)value<<32;
++ return fx;
++}
++
++struct fixed32_32 dal_fixed32_32_add(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs)
++{
++ struct fixed32_32 fx = {lhs.value + rhs.value};
++
++ ASSERT(fx.value >= rhs.value);
++ return fx;
++}
++
++struct fixed32_32 dal_fixed32_32_add_int(struct fixed32_32 lhs, uint32_t rhs)
++{
++ struct fixed32_32 fx = {lhs.value + ((uint64_t)rhs << 32)};
++
++ ASSERT(fx.value >= (uint64_t)rhs << 32);
++ return fx;
++
++}
++struct fixed32_32 dal_fixed32_32_sub(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs)
++{
++ struct fixed32_32 fx;
++
++ ASSERT(lhs.value >= rhs.value);
++ fx.value = lhs.value - rhs.value;
++ return fx;
++}
++
++struct fixed32_32 dal_fixed32_32_sub_int(struct fixed32_32 lhs, uint32_t rhs)
++{
++ struct fixed32_32 fx;
++
++ ASSERT(lhs.value >= ((uint64_t)rhs<<32));
++ fx.value = lhs.value - ((uint64_t)rhs<<32);
++ return fx;
++}
++
++struct fixed32_32 dal_fixed32_32_mul(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs)
++{
++ struct fixed32_32 fx;
++ uint64_t lhs_int = lhs.value>>32;
++ uint64_t lhs_frac = (uint32_t)lhs.value;
++ uint64_t rhs_int = rhs.value>>32;
++ uint64_t rhs_frac = (uint32_t)rhs.value;
++ uint64_t ahbh = lhs_int * rhs_int;
++ uint64_t ahbl = lhs_int * rhs_frac;
++ uint64_t albh = lhs_frac * rhs_int;
++ uint64_t albl = lhs_frac * rhs_frac;
++
++ ASSERT((ahbh>>32) == 0);
++
++ fx.value = (ahbh<<32) + ahbl + albh + (albl>>32);
++ return fx;
++
++}
++
++struct fixed32_32 dal_fixed32_32_mul_int(struct fixed32_32 lhs, uint32_t rhs)
++{
++ struct fixed32_32 fx;
++ uint64_t lhsi = (lhs.value>>32) * (uint64_t)rhs;
++ uint64_t lhsf;
++
++ ASSERT((lhsi>>32) == 0);
++ lhsf = ((uint32_t)lhs.value) * (uint64_t)rhs;
++ ASSERT((lhsi<<32) + lhsf >= lhsf);
++ fx.value = (lhsi<<32) + lhsf;
++ return fx;
++}
++
++
++
++struct fixed32_32 dal_fixed32_32_div(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs)
++{
++ struct fixed32_32 fx;
++
++ fx.value = u64_div(lhs.value, rhs.value);
++ return fx;
++}
++
++struct fixed32_32 dal_fixed32_32_div_int(struct fixed32_32 lhs, uint32_t rhs)
++{
++ struct fixed32_32 fx;
++
++ fx.value = u64_div(lhs.value, (uint64_t)rhs << 32);
++ return fx;
++}
++
++struct fixed32_32 dal_fixed32_32_min(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs)
++{
++ return (lhs.value < rhs.value) ? lhs : rhs;
++}
++
++struct fixed32_32 dal_fixed32_32_max(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs)
++{
++ return (lhs.value > rhs.value) ? lhs : rhs;
++}
++
++bool dal_fixed32_32_gt(struct fixed32_32 lhs, struct fixed32_32 rhs)
++{
++ return lhs.value > rhs.value;
++}
++bool dal_fixed32_32_gt_int(struct fixed32_32 lhs, uint32_t rhs)
++{
++ return lhs.value > ((uint64_t)rhs<<32);
++}
++
++bool dal_fixed32_32_lt(struct fixed32_32 lhs, struct fixed32_32 rhs)
++{
++ return lhs.value < rhs.value;
++}
++
++bool dal_fixed32_32_le(struct fixed32_32 lhs, struct fixed32_32 rhs)
++{
++ return lhs.value <= rhs.value;
++}
++
++bool dal_fixed32_32_lt_int(struct fixed32_32 lhs, uint32_t rhs)
++{
++ return lhs.value < ((uint64_t)rhs<<32);
++}
++
++bool dal_fixed32_32_le_int(struct fixed32_32 lhs, uint32_t rhs)
++{
++ return lhs.value <= ((uint64_t)rhs<<32);
++}
++
++uint32_t dal_fixed32_32_ceil(struct fixed32_32 v)
++{
++ ASSERT((uint32_t)v.value ? (v.value >> 32) + 1 >= 1 : true);
++ return (v.value>>32) + ((uint32_t)v.value ? 1 : 0);
++}
++
++uint32_t dal_fixed32_32_floor(struct fixed32_32 v)
++{
++ return v.value>>32;
++}
++
++uint32_t dal_fixed32_32_round(struct fixed32_32 v)
++{
++ ASSERT(v.value + (1ULL<<31) >= (1ULL<<31));
++ return (v.value + (1ULL<<31))>>32;
++}
++
++bool dal_fixed32_32_eq(struct fixed32_32 lhs, struct fixed32_32 rhs)
++{
++ return lhs.value == rhs.value;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/basics/grph_object_id.c b/drivers/gpu/drm/amd/dal/dc/basics/grph_object_id.c
+new file mode 100644
+index 0000000..8276f9d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/basics/grph_object_id.c
+@@ -0,0 +1,135 @@
++/*
++ * 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 "dal_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)) {
++ dal_output_to_console(
++ "%s: Warning: comparing invalid object 'id1'!\n", __func__);
++ return false;
++ }
++
++ if (false == dal_graphics_object_id_is_valid(id2)) {
++ dal_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 0000000..50db743
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/basics/logger.c
+@@ -0,0 +1,947 @@
++/*
++ * 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 "dal_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_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_ALL_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 *)dc_service_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 *)dc_service_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) {
++ dc_service_free(logger->ctx, logger->log_buffer);
++ logger->log_buffer = NULL;
++ }
++
++ if (logger->log_enable_mask_minors) {
++ dc_service_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 = dc_service_alloc(ctx, sizeof(struct dal_logger));
++
++ if (!logger)
++ return NULL;
++ if (!construct(ctx, logger)) {
++ dc_service_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);
++ dc_service_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;
++
++ switch (entry->major) {
++ case LOG_MAJOR_ERROR:
++ dal_error("%s", entry->buf);
++ break;
++ default:
++ dal_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];
++
++ dal_output_to_console(
++ "---------------- FLUSHING LOG BUFFER ----------------\n");
++ while (i < logger->buffer_write_offset) {
++
++ if (logger->log_buffer[i] == '\0') {
++ dal_output_to_console("%s", string_start);
++ string_start = (char *)logger->log_buffer + i + 1;
++ }
++ i++;
++ }
++ dal_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'
++ */
++ dc_service_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;
++
++ dc_service_memmove(logger->log_buffer +
++ logger->buffer_write_offset,
++ entry->buf, space_before_wrap);
++ dc_service_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 */
++ dc_service_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 */
++ dc_service_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 = dal_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\n", 12);
++ }
++
++ 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 = dal_log_to_buffer(
++ buffer, DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE, msg, args);
++ append_entry(entry, buffer, size);
++
++ 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 = dc_service_alloc(
++ logger->ctx,
++ DAL_LOGGER_BUFFER_MAX_LOG_LINE_SIZE * sizeof(char));
++
++ entry->buf_offset = 0;
++ entry->max_buf_bytes =
++ DAL_LOGGER_BUFFER_MAX_LOG_LINE_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) {
++ dc_service_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 0000000..fba5ec3
+--- /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 0000000..a3086a0
+--- /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 "dal_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
++ = &reg_dump_stack.stack_locations[i];
++
++ if (stack_location->current_pid == dal_get_pid()
++ && stack_location->current_tgid == dal_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 */
++ dal_output_to_console("[REG_DUMP]: %s: stack is full!\n",
++ __func__);
++ } else {
++ current_location =
++ &reg_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 */
++ dal_output_to_console("[REG_DUMP]: %s: stack is empty!\n",
++ __func__);
++ } else {
++ --reg_dump_stack.stack_pointer;
++ current_location =
++ &reg_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;
++
++ dc_service_memset(free_stack_location, 0, sizeof(*free_stack_location));
++
++ free_stack_location->current_caller_func = caller_func;
++ free_stack_location->current_pid = dal_get_pid();
++ free_stack_location->current_tgid = dal_get_tgid();
++
++ dal_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) {
++ dal_output_to_console("[REG_DUMP]:%s - Stack is Empty!\n",
++ __func__);
++ return;
++ }
++
++ dal_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,
++ dal_get_pid(),
++ dal_get_tgid());
++
++ dc_service_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 0000000..f589091
+--- /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 "dc_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 0000000..2f932c0
+--- /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 "dal_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 = dc_service_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 = dc_service_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)
++ dc_service_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 = dc_service_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();
++ dc_service_free(ctx, vector);
++ return NULL;
++}
++
++struct vector *dal_vector_create(
++ struct dc_context *ctx,
++ uint32_t capacity,
++ uint32_t struct_size)
++{
++ struct vector *vector = dc_service_alloc(ctx, sizeof(struct vector));
++
++ if (vector == NULL)
++ return NULL;
++
++ if (dal_vector_construct(vector, ctx, capacity, struct_size))
++ return vector;
++
++
++ BREAK_TO_DEBUGGER();
++ dc_service_free(ctx, vector);
++ return NULL;
++}
++
++void dal_vector_destruct(
++ struct vector *vector)
++{
++ if (vector->container != NULL)
++ dc_service_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);
++ dc_service_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)
++ dc_service_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;
++ }
++ dc_service_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)
++ dc_service_memmove(
++ insert_address + vector->struct_size,
++ insert_address,
++ vector->struct_size * (vector->count - position));
++
++ dc_service_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 */
++ dc_service_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 = dc_service_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;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/Makefile b/drivers/gpu/drm/amd/dal/dc/bios/Makefile
+new file mode 100644
+index 0000000..75bb892
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/Makefile
+@@ -0,0 +1,27 @@
++#
++# Makefile for the 'bios' sub-component of DAL.
++# It provides the parsing and executing controls for atom bios image.
++
++BIOS = bios_parser.o bios_parser_helper.o command_table.o command_table_helper.o
++
++AMD_DAL_BIOS = $(addprefix $(AMDDALPATH)/dc/bios/,$(BIOS))
++
++AMD_DAL_FILES += $(AMD_DAL_BIOS)
++
++ifndef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++AMD_DAL_FILES := $(filter-out $(AMDDALPATH)/dc/bios/bios_parser_helper.o,$(AMD_DAL_FILES))
++endif
++$(warning AMD_DAL_FILES=$(AMD_DAL_FILES))
++
++
++###############################################################################
++# DCE 11x
++###############################################################################
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++
++ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce110/bios_parser_helper_dce110.o
++endif
++
++AMD_DAL_FILES += $(AMDDALPATH)/dc/bios/dce110/command_table_helper_dce110.o
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser.c b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser.c
+new file mode 100644
+index 0000000..7a2b247
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser.c
+@@ -0,0 +1,4758 @@
++/*
++ * 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 "dal_services.h"
++
++#include "atom.h"
++
++#include "include/adapter_service_interface.h"
++#include "include/grph_object_ctrl_defs.h"
++#include "include/bios_parser_interface.h"
++#include "include/i2caux_interface.h"
++#include "include/logger_interface.h"
++
++#include "command_table.h"
++#if defined(CONFIG_DRM_AMD_DAL_VBIOS_PRESENT)
++#include "bios_parser_helper.h"
++#endif
++#include "command_table_helper.h"
++#include "bios_parser.h"
++
++#define THREE_PERCENT_OF_10000 300
++
++#define LAST_RECORD_TYPE 0xff
++
++/* GUID to validate external display connection info table (aka OPM module) */
++static const uint8_t ext_display_connection_guid[NUMBER_OF_UCHAR_FOR_GUID] = {
++ 0x91, 0x6E, 0x57, 0x09,
++ 0x3F, 0x6D, 0xD2, 0x11,
++ 0x39, 0x8E, 0x00, 0xA0,
++ 0xC9, 0x69, 0x72, 0x3B};
++
++#define GET_IMAGE(type, offset) ((type *) get_image(bp, offset, sizeof(type)))
++#define DATA_TABLES(table) (bp->master_data_tbl->ListOfDataTables.table)
++
++static uint8_t *get_image(struct bios_parser *bp, uint32_t offset,
++ uint32_t size);
++static uint32_t get_record_size(uint8_t *record);
++static uint32_t get_edid_size(const ATOM_FAKE_EDID_PATCH_RECORD *edid);
++static enum object_type object_type_from_bios_object_id(
++ uint32_t bios_object_id);
++static struct graphics_object_id object_id_from_bios_object_id(
++ uint32_t bios_object_id);
++static enum object_enum_id enum_id_from_bios_object_id(uint32_t bios_object_id);
++static enum encoder_id encoder_id_from_bios_object_id(uint32_t bios_object_id);
++static enum connector_id connector_id_from_bios_object_id(
++ uint32_t bios_object_id);
++static uint32_t id_from_bios_object_id(enum object_type type,
++ uint32_t bios_object_id);
++static uint32_t gpu_id_from_bios_object_id(uint32_t bios_object_id);
++static enum generic_id generic_id_from_bios_object_id(uint32_t bios_object_id);
++static void get_atom_data_table_revision(
++ ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
++ struct atom_data_revision *tbl_revision);
++static uint32_t get_dst_number_from_object(struct bios_parser *bp,
++ ATOM_OBJECT *object);
++static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
++ uint16_t **id_list);
++static uint32_t get_dest_obj_list(struct bios_parser *bp,
++ ATOM_OBJECT *object, uint16_t **id_list);
++static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
++ struct graphics_object_id id);
++static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
++ ATOM_I2C_RECORD *record,
++ struct graphics_object_i2c_info *info);
++static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
++ ATOM_OBJECT *object);
++static struct device_id device_type_from_device_id(uint16_t device_id);
++static uint32_t signal_to_ss_id(enum as_signal_type signal);
++static uint32_t get_support_mask_for_device_id(struct device_id device_id);
++static ATOM_ENCODER_CAP_RECORD *get_encoder_cap_record(
++ struct bios_parser *bp,
++ ATOM_OBJECT *object);
++static void process_ext_display_connection_info(struct bios_parser *bp);
++
++#define BIOS_IMAGE_SIZE_OFFSET 2
++#define BIOS_IMAGE_SIZE_UNIT 512
++
++static bool bios_parser_construct(
++ struct bios_parser *bp,
++ struct bp_init_data *init,
++ struct adapter_service *as)
++{
++ uint16_t *rom_header_offset = NULL;
++ ATOM_ROM_HEADER *rom_header = NULL;
++ ATOM_OBJECT_HEADER *object_info_tbl;
++ enum dce_version dce_version;
++
++ if (!as)
++ return false;
++
++ if (!init)
++ return false;
++
++ if (!init->bios)
++ return false;
++
++ dce_version = dal_adapter_service_get_dce_version(as);
++ bp->ctx = init->ctx;
++ bp->as = as;
++ bp->bios = init->bios;
++ bp->bios_size = bp->bios[BIOS_IMAGE_SIZE_OFFSET] * BIOS_IMAGE_SIZE_UNIT;
++ bp->bios_local_image = NULL;
++ bp->lcd_scale = LCD_SCALE_UNKNOWN;
++
++ rom_header_offset =
++ GET_IMAGE(uint16_t, OFFSET_TO_POINTER_TO_ATOM_ROM_HEADER);
++
++ if (!rom_header_offset)
++ return false;
++
++ rom_header = GET_IMAGE(ATOM_ROM_HEADER, *rom_header_offset);
++
++ if (!rom_header)
++ return false;
++
++ bp->master_data_tbl =
++ GET_IMAGE(ATOM_MASTER_DATA_TABLE,
++ rom_header->usMasterDataTableOffset);
++
++ if (!bp->master_data_tbl)
++ return false;
++
++ bp->object_info_tbl_offset = DATA_TABLES(Object_Header);
++
++ if (!bp->object_info_tbl_offset)
++ return false;
++
++ object_info_tbl =
++ GET_IMAGE(ATOM_OBJECT_HEADER, bp->object_info_tbl_offset);
++
++ if (!object_info_tbl)
++ return false;
++
++ get_atom_data_table_revision(&object_info_tbl->sHeader,
++ &bp->object_info_tbl.revision);
++
++ if (bp->object_info_tbl.revision.major == 1
++ && bp->object_info_tbl.revision.minor >= 3) {
++ ATOM_OBJECT_HEADER_V3 *tbl_v3;
++
++ tbl_v3 = GET_IMAGE(ATOM_OBJECT_HEADER_V3,
++ bp->object_info_tbl_offset);
++ if (!tbl_v3)
++ return false;
++
++ bp->object_info_tbl.v1_3 = tbl_v3;
++ } else if (bp->object_info_tbl.revision.major == 1
++ && bp->object_info_tbl.revision.minor >= 1)
++ bp->object_info_tbl.v1_1 = object_info_tbl;
++ else
++ return false;
++
++#if defined(CONFIG_DRM_AMD_DAL_VBIOS_PRESENT)
++ bp->vbios_helper_data.active = 0;
++ bp->vbios_helper_data.requested = 0;
++ dal_bios_parser_init_bios_helper(bp, dce_version);
++#endif
++ dal_bios_parser_init_cmd_tbl(bp);
++ dal_bios_parser_init_cmd_tbl_helper(&bp->cmd_helper, dce_version);
++
++ return true;
++}
++
++struct bios_parser *dal_bios_parser_create(
++ struct bp_init_data *init, struct adapter_service *as)
++{
++ struct bios_parser *bp = NULL;
++
++ bp = dc_service_alloc(init->ctx, sizeof(struct bios_parser));
++ if (!bp)
++ return NULL;
++
++ if (bios_parser_construct(bp, init, as))
++ return bp;
++
++ dc_service_free(init->ctx, bp);
++ BREAK_TO_DEBUGGER();
++ return NULL;
++}
++
++static void destruct(struct bios_parser *bp)
++{
++ if (bp->bios_local_image)
++ dc_service_free(bp->ctx, bp->bios_local_image);
++}
++
++void dal_bios_parser_destroy(struct bios_parser **bp)
++{
++ if (!bp || !*bp) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ destruct(*bp);
++
++ dc_service_free((*bp)->ctx, *bp);
++ *bp = NULL;
++}
++
++void dal_bios_parser_power_down(struct bios_parser *bp)
++{
++#if defined(CONFIG_DRM_AMD_DAL_VBIOS_PRESENT)
++ dal_bios_parser_set_scratch_lcd_scale(bp, bp->lcd_scale);
++#endif
++}
++
++void dal_bios_parser_power_up(struct bios_parser *bp)
++{
++#if defined(CONFIG_DRM_AMD_DAL_VBIOS_PRESENT)
++ if (bp->lcd_scale == LCD_SCALE_UNKNOWN)
++ bp->lcd_scale = dal_bios_parser_get_scratch_lcd_scale(bp);
++#endif
++}
++
++static uint8_t get_number_of_objects(struct bios_parser *bp, uint32_t offset)
++{
++ ATOM_OBJECT_TABLE *table;
++
++ uint32_t object_table_offset = bp->object_info_tbl_offset + offset;
++
++ table = GET_IMAGE(ATOM_OBJECT_TABLE, object_table_offset);
++
++ if (!table)
++ return 0;
++ else
++ return table->ucNumberOfObjects;
++}
++
++uint8_t dal_bios_parser_get_encoders_number(struct bios_parser *bp)
++{
++ return get_number_of_objects(bp,
++ le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset));
++}
++
++uint8_t dal_bios_parser_get_connectors_number(struct bios_parser *bp)
++{
++ return get_number_of_objects(bp,
++ le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset));
++}
++
++uint32_t dal_bios_parser_get_oem_ddc_lines_number(struct bios_parser *bp)
++{
++ uint32_t number = 0;
++
++ if (DATA_TABLES(OemInfo) != 0) {
++ ATOM_OEM_INFO *info;
++
++ info = GET_IMAGE(ATOM_OEM_INFO,
++ DATA_TABLES(OemInfo));
++
++ if (le16_to_cpu(info->sHeader.usStructureSize)
++ > sizeof(ATOM_COMMON_TABLE_HEADER)) {
++
++ number = (le16_to_cpu(info->sHeader.usStructureSize)
++ - sizeof(ATOM_COMMON_TABLE_HEADER))
++ / sizeof(ATOM_I2C_ID_CONFIG_ACCESS);
++
++ }
++ }
++
++ return number;
++}
++
++struct graphics_object_id dal_bios_parser_get_encoder_id(struct bios_parser *bp,
++ uint32_t i)
++{
++ struct graphics_object_id object_id = dal_graphics_object_id_init(
++ 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
++
++ uint32_t encoder_table_offset = bp->object_info_tbl_offset
++ + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
++
++ ATOM_OBJECT_TABLE *tbl =
++ GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
++
++ if (tbl && tbl->ucNumberOfObjects > i) {
++ const uint16_t id = le16_to_cpu(tbl->asObjects[i].usObjectID);
++
++ object_id = object_id_from_bios_object_id(id);
++ }
++
++ return object_id;
++}
++
++struct graphics_object_id dal_bios_parser_get_connector_id(
++ struct bios_parser *bp,
++ uint8_t i)
++{
++ struct graphics_object_id object_id = dal_graphics_object_id_init(
++ 0, ENUM_ID_UNKNOWN, OBJECT_TYPE_UNKNOWN);
++
++ uint32_t connector_table_offset = bp->object_info_tbl_offset
++ + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
++
++ ATOM_OBJECT_TABLE *tbl =
++ GET_IMAGE(ATOM_OBJECT_TABLE, connector_table_offset);
++
++ if (tbl && tbl->ucNumberOfObjects > i) {
++ const uint16_t id = le16_to_cpu(tbl->asObjects[i].usObjectID);
++
++ object_id = object_id_from_bios_object_id(id);
++ }
++
++ return object_id;
++}
++
++uint32_t dal_bios_parser_get_src_number(struct bios_parser *bp,
++ struct graphics_object_id id)
++{
++ uint32_t offset;
++ uint8_t *number;
++ ATOM_OBJECT *object;
++
++ object = get_bios_object(bp, id);
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object id */
++ return 0;
++ }
++
++ offset = le16_to_cpu(object->usSrcDstTableOffset)
++ + bp->object_info_tbl_offset;
++
++ number = GET_IMAGE(uint8_t, offset);
++ if (!number)
++ return 0;
++
++ return *number;
++}
++
++uint32_t dal_bios_parser_get_dst_number(struct bios_parser *bp,
++ struct graphics_object_id id)
++{
++ ATOM_OBJECT *object = get_bios_object(bp, id);
++
++ return get_dst_number_from_object(bp, object);
++}
++
++enum bp_result dal_bios_parser_get_src_obj(struct bios_parser *bp,
++ struct graphics_object_id object_id, uint32_t index,
++ struct graphics_object_id *src_object_id)
++{
++ uint32_t number;
++ uint16_t *id;
++ ATOM_OBJECT *object;
++
++ if (!src_object_id)
++ return BP_RESULT_BADINPUT;
++
++ object = get_bios_object(bp, object_id);
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object id */
++ return BP_RESULT_BADINPUT;
++ }
++
++ number = get_src_obj_list(bp, object, &id);
++
++ if (number <= index)
++ return BP_RESULT_BADINPUT;
++
++ *src_object_id = object_id_from_bios_object_id(id[index]);
++
++ return BP_RESULT_OK;
++}
++
++enum bp_result dal_bios_parser_get_dst_obj(struct bios_parser *bp,
++ struct graphics_object_id object_id, uint32_t index,
++ struct graphics_object_id *dest_object_id)
++{
++ uint32_t number;
++ uint16_t *id;
++ ATOM_OBJECT *object;
++
++ if (!dest_object_id)
++ return BP_RESULT_BADINPUT;
++
++ object = get_bios_object(bp, object_id);
++
++ number = get_dest_obj_list(bp, object, &id);
++
++ if (number <= index)
++ return BP_RESULT_BADINPUT;
++
++ *dest_object_id = object_id_from_bios_object_id(id[index]);
++
++ return BP_RESULT_OK;
++}
++
++enum bp_result dal_bios_parser_get_oem_ddc_info(struct bios_parser *bp,
++ uint32_t index,
++ struct graphics_object_i2c_info *info)
++{
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ if (DATA_TABLES(OemInfo) != 0) {
++ ATOM_OEM_INFO *tbl;
++
++ tbl = GET_IMAGE(ATOM_OEM_INFO, DATA_TABLES(OemInfo));
++
++ if (le16_to_cpu(tbl->sHeader.usStructureSize)
++ > sizeof(ATOM_COMMON_TABLE_HEADER)) {
++ ATOM_I2C_RECORD record;
++ ATOM_I2C_ID_CONFIG_ACCESS *config;
++
++ dc_service_memset(&record, 0, sizeof(record));
++
++ config = &tbl->sucI2cId + index - 1;
++
++ record.sucI2cId.bfHW_Capable =
++ config->sbfAccess.bfHW_Capable;
++ record.sucI2cId.bfI2C_LineMux =
++ config->sbfAccess.bfI2C_LineMux;
++ record.sucI2cId.bfHW_EngineID =
++ config->sbfAccess.bfHW_EngineID;
++
++ return get_gpio_i2c_info(bp, &record, info);
++ }
++ }
++
++ return BP_RESULT_NORECORD;
++}
++
++enum bp_result dal_bios_parser_get_i2c_info(struct bios_parser *bp,
++ struct graphics_object_id id,
++ struct graphics_object_i2c_info *info)
++{
++ uint32_t offset;
++ ATOM_OBJECT *object;
++ ATOM_COMMON_RECORD_HEADER *header;
++ ATOM_I2C_RECORD *record;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ object = get_bios_object(bp, id);
++
++ if (!object)
++ return BP_RESULT_BADINPUT;
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!header)
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (LAST_RECORD_TYPE == header->ucRecordType ||
++ !header->ucRecordSize)
++ break;
++
++ if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
++ && sizeof(ATOM_I2C_RECORD) <= header->ucRecordSize) {
++ /* get the I2C info */
++ record = (ATOM_I2C_RECORD *) header;
++
++ if (get_gpio_i2c_info(bp, record, info) == BP_RESULT_OK)
++ return BP_RESULT_OK;
++ }
++
++ offset += header->ucRecordSize;
++ }
++
++ return BP_RESULT_NORECORD;
++}
++
++static enum bp_result get_voltage_ddc_info_v1(uint8_t *i2c_line,
++ ATOM_COMMON_TABLE_HEADER *header,
++ uint8_t *address)
++{
++ enum bp_result result = BP_RESULT_NORECORD;
++ ATOM_VOLTAGE_OBJECT_INFO *info =
++ (ATOM_VOLTAGE_OBJECT_INFO *) address;
++
++ uint8_t *voltage_current_object = (uint8_t *) &info->asVoltageObj[0];
++
++ while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
++ ATOM_VOLTAGE_OBJECT *object =
++ (ATOM_VOLTAGE_OBJECT *) voltage_current_object;
++
++ if ((object->ucVoltageType == SET_VOLTAGE_INIT_MODE) &&
++ (object->ucVoltageType &
++ VOLTAGE_CONTROLLED_BY_I2C_MASK)) {
++
++ *i2c_line = object->asControl.ucVoltageControlI2cLine
++ ^ 0x90;
++ result = BP_RESULT_OK;
++ break;
++ }
++
++ voltage_current_object += object->ucSize;
++ }
++ return result;
++}
++
++static enum bp_result get_voltage_ddc_info_v3(uint8_t *i2c_line,
++ uint32_t index,
++ ATOM_COMMON_TABLE_HEADER *header,
++ uint8_t *address)
++{
++ enum bp_result result = BP_RESULT_NORECORD;
++ ATOM_VOLTAGE_OBJECT_INFO_V3_1 *info =
++ (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *) address;
++
++ uint8_t *voltage_current_object =
++ (uint8_t *) (&(info->asVoltageObj[0]));
++
++ while ((address + le16_to_cpu(header->usStructureSize)) > voltage_current_object) {
++ ATOM_I2C_VOLTAGE_OBJECT_V3 *object =
++ (ATOM_I2C_VOLTAGE_OBJECT_V3 *) voltage_current_object;
++
++ if (object->sHeader.ucVoltageMode ==
++ ATOM_INIT_VOLTAGE_REGULATOR) {
++ if (object->sHeader.ucVoltageType == index) {
++ *i2c_line = object->ucVoltageControlI2cLine
++ ^ 0x90;
++ result = BP_RESULT_OK;
++ break;
++ }
++ }
++
++ voltage_current_object += le16_to_cpu(object->sHeader.usSize);
++ }
++ return result;
++}
++
++enum bp_result dal_bios_parser_get_voltage_ddc_info(struct bios_parser *bp,
++ uint32_t index,
++ struct graphics_object_i2c_info *info)
++{
++ uint8_t i2c_line = 0;
++ enum bp_result result = BP_RESULT_NORECORD;
++ uint8_t *voltage_info_address;
++ ATOM_COMMON_TABLE_HEADER *header;
++ struct atom_data_revision revision = {0};
++
++ if (!DATA_TABLES(VoltageObjectInfo))
++ return result;
++
++ voltage_info_address = get_image(bp,
++ DATA_TABLES(VoltageObjectInfo),
++ sizeof(ATOM_COMMON_TABLE_HEADER));
++
++ header = (ATOM_COMMON_TABLE_HEADER *) voltage_info_address;
++
++ get_atom_data_table_revision(header, &revision);
++
++ switch (revision.major) {
++ case 1:
++ case 2:
++ result = get_voltage_ddc_info_v1(&i2c_line, header,
++ voltage_info_address);
++ break;
++ case 3:
++ if (revision.minor != 1)
++ break;
++ result = get_voltage_ddc_info_v3(&i2c_line, index, header,
++ voltage_info_address);
++ break;
++ }
++
++ if (result == BP_RESULT_OK)
++ result = dal_bios_parser_get_thermal_ddc_info(bp,
++ i2c_line, info);
++
++
++ return result;
++}
++
++enum bp_result dal_bios_parser_get_thermal_ddc_info(
++ struct bios_parser *bp,
++ uint32_t i2c_channel_id,
++ struct graphics_object_i2c_info *info)
++{
++ ATOM_I2C_ID_CONFIG_ACCESS *config;
++ ATOM_I2C_RECORD record;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ config = (ATOM_I2C_ID_CONFIG_ACCESS *) &i2c_channel_id;
++
++ record.sucI2cId.bfHW_Capable = config->sbfAccess.bfHW_Capable;
++ record.sucI2cId.bfI2C_LineMux = config->sbfAccess.bfI2C_LineMux;
++ record.sucI2cId.bfHW_EngineID = config->sbfAccess.bfHW_EngineID;
++
++ return get_gpio_i2c_info(bp, &record, info);
++}
++
++enum bp_result dal_bios_parser_get_ddc_info_for_i2c_line(struct bios_parser *bp,
++ uint8_t i2c_line, struct graphics_object_i2c_info *info)
++{
++ uint32_t offset;
++ ATOM_OBJECT *object;
++ ATOM_OBJECT_TABLE *table;
++ uint32_t i;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
++
++ offset += bp->object_info_tbl_offset;
++
++ table = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
++
++ if (!table)
++ return BP_RESULT_BADBIOSTABLE;
++
++ for (i = 0; i < table->ucNumberOfObjects; i++) {
++ object = &table->asObjects[i];
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object id */
++ return BP_RESULT_BADINPUT;
++ }
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ ATOM_COMMON_RECORD_HEADER *header =
++ GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!header)
++ return BP_RESULT_BADBIOSTABLE;
++
++ offset += header->ucRecordSize;
++
++ if (LAST_RECORD_TYPE == header->ucRecordType ||
++ !header->ucRecordSize)
++ break;
++
++ if (ATOM_I2C_RECORD_TYPE == header->ucRecordType
++ && sizeof(ATOM_I2C_RECORD) <=
++ header->ucRecordSize) {
++ ATOM_I2C_RECORD *record =
++ (ATOM_I2C_RECORD *) header;
++
++ if (i2c_line != record->sucI2cId.bfI2C_LineMux)
++ continue;
++
++ /* get the I2C info */
++ if (get_gpio_i2c_info(bp, record, info) ==
++ BP_RESULT_OK)
++ return BP_RESULT_OK;
++ }
++ }
++ }
++
++ return BP_RESULT_NORECORD;
++}
++
++enum bp_result dal_bios_parser_get_hpd_info(struct bios_parser *bp,
++ struct graphics_object_id id,
++ struct graphics_object_hpd_info *info)
++{
++ ATOM_OBJECT *object;
++ ATOM_HPD_INT_RECORD *record = NULL;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ object = get_bios_object(bp, id);
++
++ if (!object)
++ return BP_RESULT_BADINPUT;
++
++ record = get_hpd_record(bp, object);
++
++ if (record != NULL) {
++ info->hpd_int_gpio_uid = record->ucHPDIntGPIOID;
++ info->hpd_active = record->ucPlugged_PinState;
++ return BP_RESULT_OK;
++ }
++
++ return BP_RESULT_NORECORD;
++}
++
++uint32_t dal_bios_parser_get_gpio_record(
++ struct bios_parser *bp,
++ struct graphics_object_id id,
++ struct bp_gpio_cntl_info *gpio_record,
++ uint32_t record_size)
++{
++ ATOM_COMMON_RECORD_HEADER *header = NULL;
++ ATOM_OBJECT_GPIO_CNTL_RECORD *record = NULL;
++ ATOM_OBJECT *object = get_bios_object(bp, id);
++ uint32_t offset;
++ uint32_t pins_number;
++ uint32_t i;
++
++ if (!object)
++ return 0;
++
++ /* Initialise offset */
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ /* Get record header */
++ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++ if (!header || header->ucRecordType == LAST_RECORD_TYPE ||
++ !header->ucRecordSize)
++ break;
++
++ /* If this is gpio control record - stop. We found the record */
++ if (header->ucRecordType == ATOM_OBJECT_GPIO_CNTL_RECORD_TYPE
++ && header->ucRecordSize
++ >= sizeof(ATOM_OBJECT_GPIO_CNTL_RECORD)) {
++ record = (ATOM_OBJECT_GPIO_CNTL_RECORD *) header;
++ break;
++ }
++
++ /* Advance to next record */
++ offset += header->ucRecordSize;
++ }
++
++ /* If we did not find a record - return */
++ if (!record)
++ return 0;
++
++ /* Extract gpio IDs from bios record (make sure we do not exceed passed
++ * array size) */
++ pins_number = (record->ucNumberOfPins < record_size ?
++ record->ucNumberOfPins : record_size);
++ for (i = 0; i < pins_number; i++) {
++ uint8_t output_state = ((record->asGpio[i].ucGPIO_PinState
++ & GPIO_PIN_OUTPUT_STATE_MASK)
++ >> GPIO_PIN_OUTPUT_STATE_SHIFT);
++ gpio_record[i].id = record->asGpio[i].ucGPIOID;
++
++ switch (output_state) {
++ case GPIO_PIN_STATE_ACTIVE_LOW:
++ gpio_record[i].state =
++ GPIO_PIN_OUTPUT_STATE_ACTIVE_LOW;
++ break;
++
++ case GPIO_PIN_STATE_ACTIVE_HIGH:
++ gpio_record[i].state =
++ GPIO_PIN_OUTPUT_STATE_ACTIVE_HIGH;
++ break;
++
++ default:
++ BREAK_TO_DEBUGGER(); /* Invalid Pin Output State */
++ break;
++ }
++ }
++
++ return pins_number;
++}
++
++enum bp_result dal_bios_parser_get_device_tag_record(
++ struct bios_parser *bp,
++ ATOM_OBJECT *object,
++ ATOM_CONNECTOR_DEVICE_TAG_RECORD **record)
++{
++ ATOM_COMMON_RECORD_HEADER *header;
++ uint32_t offset;
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!header)
++ return BP_RESULT_BADBIOSTABLE;
++
++ offset += header->ucRecordSize;
++
++ if (LAST_RECORD_TYPE == header->ucRecordType ||
++ !header->ucRecordSize)
++ break;
++
++ if (ATOM_CONNECTOR_DEVICE_TAG_RECORD_TYPE !=
++ header->ucRecordType)
++ continue;
++
++ if (sizeof(ATOM_CONNECTOR_DEVICE_TAG) > header->ucRecordSize)
++ continue;
++
++ *record = (ATOM_CONNECTOR_DEVICE_TAG_RECORD *) header;
++ return BP_RESULT_OK;
++ }
++
++ return BP_RESULT_NORECORD;
++}
++
++enum bp_result dal_bios_parser_get_device_tag(
++ struct bios_parser *bp,
++ struct graphics_object_id connector_object_id,
++ uint32_t device_tag_index,
++ struct connector_device_tag_info *info)
++{
++ ATOM_OBJECT *object;
++ ATOM_CONNECTOR_DEVICE_TAG_RECORD *record = NULL;
++ ATOM_CONNECTOR_DEVICE_TAG *device_tag;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ /* getBiosObject will return MXM object */
++ object = get_bios_object(bp, connector_object_id);
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object id */
++ return BP_RESULT_BADINPUT;
++ }
++
++ if (dal_bios_parser_get_device_tag_record(bp, object, &record)
++ != BP_RESULT_OK)
++ return BP_RESULT_NORECORD;
++
++ if (device_tag_index >= record->ucNumberOfDevice)
++ return BP_RESULT_NORECORD;
++
++ device_tag = &record->asDeviceTag[device_tag_index];
++
++ info->acpi_device = le32_to_cpu(device_tag->ulACPIDeviceEnum);
++ info->dev_id =
++ device_type_from_device_id(le16_to_cpu(device_tag->usDeviceID));
++
++ return BP_RESULT_OK;
++}
++
++static enum bp_result get_firmware_info_v1_4(
++ struct bios_parser *bp,
++ struct firmware_info *info);
++static enum bp_result get_firmware_info_v2_1(
++ struct bios_parser *bp,
++ struct firmware_info *info);
++static enum bp_result get_firmware_info_v2_2(
++ struct bios_parser *bp,
++ struct firmware_info *info);
++
++enum bp_result dal_bios_parser_get_firmware_info(
++ struct bios_parser *bp,
++ struct firmware_info *info)
++{
++ enum bp_result result = BP_RESULT_BADBIOSTABLE;
++ ATOM_COMMON_TABLE_HEADER *header;
++ struct atom_data_revision revision;
++
++ if (info && DATA_TABLES(FirmwareInfo)) {
++ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
++ DATA_TABLES(FirmwareInfo));
++ get_atom_data_table_revision(header, &revision);
++ switch (revision.major) {
++ case 1:
++ switch (revision.minor) {
++ case 4:
++ result = get_firmware_info_v1_4(bp, info);
++ break;
++ default:
++ break;
++ }
++ break;
++
++ case 2:
++ switch (revision.minor) {
++ case 1:
++ result = get_firmware_info_v2_1(bp, info);
++ break;
++ case 2:
++ result = get_firmware_info_v2_2(bp, info);
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++ }
++
++ return result;
++}
++
++static enum bp_result get_firmware_info_v1_4(
++ struct bios_parser *bp,
++ struct firmware_info *info)
++{
++ ATOM_FIRMWARE_INFO_V1_4 *firmware_info =
++ GET_IMAGE(ATOM_FIRMWARE_INFO_V1_4,
++ DATA_TABLES(FirmwareInfo));
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ if (!firmware_info)
++ return BP_RESULT_BADBIOSTABLE;
++
++ dc_service_memset(info, 0, sizeof(*info));
++
++ /* Pixel clock pll information. We need to convert from 10KHz units into
++ * KHz units */
++ info->pll_info.crystal_frequency =
++ le16_to_cpu(firmware_info->usReferenceClock) * 10;
++ info->pll_info.min_input_pxl_clk_pll_frequency =
++ le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
++ info->pll_info.max_input_pxl_clk_pll_frequency =
++ le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
++ info->pll_info.min_output_pxl_clk_pll_frequency =
++ le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
++ info->pll_info.max_output_pxl_clk_pll_frequency =
++ le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
++
++ if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
++ /* Since there is no information on the SS, report conservative
++ * value 3% for bandwidth calculation */
++ /* unit of 0.01% */
++ info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
++
++ if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
++ /* Since there is no information on the SS,report conservative
++ * value 3% for bandwidth calculation */
++ /* unit of 0.01% */
++ info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
++
++ return BP_RESULT_OK;
++}
++
++static enum bp_result get_ss_info_v3_1(
++ struct bios_parser *bp,
++ uint32_t id,
++ uint32_t index,
++ struct spread_spectrum_info *ss_info);
++
++static enum bp_result get_firmware_info_v2_1(
++ struct bios_parser *bp,
++ struct firmware_info *info)
++{
++ ATOM_FIRMWARE_INFO_V2_1 *firmwareInfo =
++ GET_IMAGE(ATOM_FIRMWARE_INFO_V2_1, DATA_TABLES(FirmwareInfo));
++ struct spread_spectrum_info internalSS;
++ uint32_t index;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ if (!firmwareInfo)
++ return BP_RESULT_BADBIOSTABLE;
++
++ dc_service_memset(info, 0, sizeof(*info));
++
++ /* Pixel clock pll information. We need to convert from 10KHz units into
++ * KHz units */
++ info->pll_info.crystal_frequency =
++ le16_to_cpu(firmwareInfo->usCoreReferenceClock) * 10;
++ info->pll_info.min_input_pxl_clk_pll_frequency =
++ le16_to_cpu(firmwareInfo->usMinPixelClockPLL_Input) * 10;
++ info->pll_info.max_input_pxl_clk_pll_frequency =
++ le16_to_cpu(firmwareInfo->usMaxPixelClockPLL_Input) * 10;
++ info->pll_info.min_output_pxl_clk_pll_frequency =
++ le32_to_cpu(firmwareInfo->ulMinPixelClockPLL_Output) * 10;
++ info->pll_info.max_output_pxl_clk_pll_frequency =
++ le32_to_cpu(firmwareInfo->ulMaxPixelClockPLL_Output) * 10;
++ info->default_display_engine_pll_frequency =
++ le32_to_cpu(firmwareInfo->ulDefaultDispEngineClkFreq) * 10;
++ info->external_clock_source_frequency_for_dp =
++ le16_to_cpu(firmwareInfo->usUniphyDPModeExtClkFreq) * 10;
++ info->min_allowed_bl_level = firmwareInfo->ucMinAllowedBL_Level;
++
++ /* There should be only one entry in the SS info table for Memory Clock
++ */
++ index = 0;
++ if (firmwareInfo->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
++ /* Since there is no information for external SS, report
++ * conservative value 3% for bandwidth calculation */
++ /* unit of 0.01% */
++ info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
++ else if (get_ss_info_v3_1(bp,
++ ASIC_INTERNAL_MEMORY_SS, index, &internalSS) == BP_RESULT_OK) {
++ if (internalSS.spread_spectrum_percentage) {
++ info->feature.memory_clk_ss_percentage =
++ internalSS.spread_spectrum_percentage;
++ if (internalSS.type.CENTER_MODE) {
++ /* if it is centermode, the exact SS Percentage
++ * will be round up of half of the percentage
++ * reported in the SS table */
++ ++info->feature.memory_clk_ss_percentage;
++ info->feature.memory_clk_ss_percentage /= 2;
++ }
++ }
++ }
++
++ /* There should be only one entry in the SS info table for Engine Clock
++ */
++ index = 1;
++ if (firmwareInfo->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
++ /* Since there is no information for external SS, report
++ * conservative value 3% for bandwidth calculation */
++ /* unit of 0.01% */
++ info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
++ else if (get_ss_info_v3_1(bp,
++ ASIC_INTERNAL_ENGINE_SS, index, &internalSS) == BP_RESULT_OK) {
++ if (internalSS.spread_spectrum_percentage) {
++ info->feature.engine_clk_ss_percentage =
++ internalSS.spread_spectrum_percentage;
++ if (internalSS.type.CENTER_MODE) {
++ /* if it is centermode, the exact SS Percentage
++ * will be round up of half of the percentage
++ * reported in the SS table */
++ ++info->feature.engine_clk_ss_percentage;
++ info->feature.engine_clk_ss_percentage /= 2;
++ }
++ }
++ }
++
++ return BP_RESULT_OK;
++}
++
++static enum bp_result get_firmware_info_v2_2(
++ struct bios_parser *bp,
++ struct firmware_info *info)
++{
++ ATOM_FIRMWARE_INFO_V2_2 *firmware_info;
++ struct spread_spectrum_info internal_ss;
++ uint32_t index;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ firmware_info = GET_IMAGE(ATOM_FIRMWARE_INFO_V2_2,
++ DATA_TABLES(FirmwareInfo));
++
++ if (!firmware_info)
++ return BP_RESULT_BADBIOSTABLE;
++
++ dc_service_memset(info, 0, sizeof(*info));
++
++ /* Pixel clock pll information. We need to convert from 10KHz units into
++ * KHz units */
++ info->pll_info.crystal_frequency =
++ le16_to_cpu(firmware_info->usCoreReferenceClock) * 10;
++ info->pll_info.min_input_pxl_clk_pll_frequency =
++ le16_to_cpu(firmware_info->usMinPixelClockPLL_Input) * 10;
++ info->pll_info.max_input_pxl_clk_pll_frequency =
++ le16_to_cpu(firmware_info->usMaxPixelClockPLL_Input) * 10;
++ info->pll_info.min_output_pxl_clk_pll_frequency =
++ le32_to_cpu(firmware_info->ulMinPixelClockPLL_Output) * 10;
++ info->pll_info.max_output_pxl_clk_pll_frequency =
++ le32_to_cpu(firmware_info->ulMaxPixelClockPLL_Output) * 10;
++ info->default_display_engine_pll_frequency =
++ le32_to_cpu(firmware_info->ulDefaultDispEngineClkFreq) * 10;
++ info->external_clock_source_frequency_for_dp =
++ le16_to_cpu(firmware_info->usUniphyDPModeExtClkFreq) * 10;
++
++ /* There should be only one entry in the SS info table for Memory Clock
++ */
++ index = 0;
++ if (firmware_info->usFirmwareCapability.sbfAccess.MemoryClockSS_Support)
++ /* Since there is no information for external SS, report
++ * conservative value 3% for bandwidth calculation */
++ /* unit of 0.01% */
++ info->feature.memory_clk_ss_percentage = THREE_PERCENT_OF_10000;
++ else if (get_ss_info_v3_1(bp,
++ ASIC_INTERNAL_MEMORY_SS, index, &internal_ss) == BP_RESULT_OK) {
++ if (internal_ss.spread_spectrum_percentage) {
++ info->feature.memory_clk_ss_percentage =
++ internal_ss.spread_spectrum_percentage;
++ if (internal_ss.type.CENTER_MODE) {
++ /* if it is centermode, the exact SS Percentage
++ * will be round up of half of the percentage
++ * reported in the SS table */
++ ++info->feature.memory_clk_ss_percentage;
++ info->feature.memory_clk_ss_percentage /= 2;
++ }
++ }
++ }
++
++ /* There should be only one entry in the SS info table for Engine Clock
++ */
++ index = 1;
++ if (firmware_info->usFirmwareCapability.sbfAccess.EngineClockSS_Support)
++ /* Since there is no information for external SS, report
++ * conservative value 3% for bandwidth calculation */
++ /* unit of 0.01% */
++ info->feature.engine_clk_ss_percentage = THREE_PERCENT_OF_10000;
++ else if (get_ss_info_v3_1(bp,
++ ASIC_INTERNAL_ENGINE_SS, index, &internal_ss) == BP_RESULT_OK) {
++ if (internal_ss.spread_spectrum_percentage) {
++ info->feature.engine_clk_ss_percentage =
++ internal_ss.spread_spectrum_percentage;
++ if (internal_ss.type.CENTER_MODE) {
++ /* if it is centermode, the exact SS Percentage
++ * will be round up of half of the percentage
++ * reported in the SS table */
++ ++info->feature.engine_clk_ss_percentage;
++ info->feature.engine_clk_ss_percentage /= 2;
++ }
++ }
++ }
++
++ /* Remote Display */
++ info->remote_display_config = firmware_info->ucRemoteDisplayConfig;
++
++ /* Is allowed minimum BL level */
++ info->min_allowed_bl_level = firmware_info->ucMinAllowedBL_Level;
++ /* Used starting from CI */
++ info->smu_gpu_pll_output_freq =
++ (uint32_t) (le32_to_cpu(firmware_info->ulGPUPLL_OutputFreq) * 10);
++
++ return BP_RESULT_OK;
++}
++
++static enum bp_result get_ss_info_v3_1(
++ struct bios_parser *bp,
++ uint32_t id,
++ uint32_t index,
++ struct spread_spectrum_info *ss_info)
++{
++ ATOM_ASIC_INTERNAL_SS_INFO_V3 *ss_table_header_include;
++ ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
++ uint32_t table_size;
++ uint32_t i;
++ uint32_t table_index = 0;
++
++ if (!ss_info)
++ return BP_RESULT_BADINPUT;
++
++ if (!DATA_TABLES(ASIC_InternalSS_Info))
++ return BP_RESULT_UNSUPPORTED;
++
++ ss_table_header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
++ DATA_TABLES(ASIC_InternalSS_Info));
++ table_size =
++ (le16_to_cpu(ss_table_header_include->sHeader.usStructureSize)
++ - sizeof(ATOM_COMMON_TABLE_HEADER))
++ / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
++
++ tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
++ &ss_table_header_include->asSpreadSpectrum[0];
++
++ dc_service_memset(ss_info, 0, sizeof(struct spread_spectrum_info));
++
++ for (i = 0; i < table_size; i++) {
++ if (tbl[i].ucClockIndication != (uint8_t) id)
++ continue;
++
++ if (table_index != index) {
++ table_index++;
++ continue;
++ }
++ /* VBIOS introduced new defines for Version 3, same values as
++ * before, so now use these new ones for Version 3.
++ * Shouldn't affect field VBIOS's V3 as define values are still
++ * same.
++ * #define SS_MODE_V3_CENTRE_SPREAD_MASK 0x01
++ * #define SS_MODE_V3_EXTERNAL_SS_MASK 0x02
++
++ * Old VBIOS defines:
++ * #define ATOM_SS_CENTRE_SPREAD_MODE_MASK 0x00000001
++ * #define ATOM_EXTERNAL_SS_MASK 0x00000002
++ */
++
++ if (SS_MODE_V3_EXTERNAL_SS_MASK & tbl[i].ucSpreadSpectrumMode)
++ ss_info->type.EXTERNAL = true;
++
++ if (SS_MODE_V3_CENTRE_SPREAD_MASK & tbl[i].ucSpreadSpectrumMode)
++ ss_info->type.CENTER_MODE = true;
++
++ /* Older VBIOS (in field) always provides SS percentage in 0.01%
++ * units set Divider to 100 */
++ ss_info->spread_percentage_divider = 100;
++
++ /* #define SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK 0x10 */
++ if (SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK
++ & tbl[i].ucSpreadSpectrumMode)
++ ss_info->spread_percentage_divider = 1000;
++
++ ss_info->type.STEP_AND_DELAY_INFO = false;
++ /* convert [10KHz] into [KHz] */
++ ss_info->target_clock_range =
++ le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
++ ss_info->spread_spectrum_percentage =
++ (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
++ ss_info->spread_spectrum_range =
++ (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
++
++ return BP_RESULT_OK;
++ }
++ return BP_RESULT_NORECORD;
++}
++
++enum bp_result dal_bios_parser_transmitter_control(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl)
++{
++ if (!bp->cmd_tbl.transmitter_control)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.transmitter_control(bp, cntl);
++}
++
++enum bp_result dal_bios_parser_encoder_control(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl)
++{
++ if (!bp->cmd_tbl.dig_encoder_control)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.dig_encoder_control(bp, cntl);
++}
++
++enum bp_result dal_bios_parser_adjust_pixel_clock(
++ struct bios_parser *bp,
++ struct bp_adjust_pixel_clock_parameters *bp_params)
++{
++ if (!bp->cmd_tbl.adjust_display_pll)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.adjust_display_pll(bp, bp_params);
++}
++
++enum bp_result dal_bios_parser_set_pixel_clock(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params)
++{
++ if (!bp->cmd_tbl.set_pixel_clock)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.set_pixel_clock(bp, bp_params);
++}
++
++enum bp_result dal_bios_parser_enable_spread_spectrum_on_ppll(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable)
++{
++ if (!bp->cmd_tbl.enable_spread_spectrum_on_ppll)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.enable_spread_spectrum_on_ppll(
++ bp, bp_params, enable);
++
++}
++
++enum bp_result dal_bios_parser_program_crtc_timing(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_timing_parameters *bp_params)
++{
++ if (!bp->cmd_tbl.set_crtc_timing)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.set_crtc_timing(bp, bp_params);
++}
++
++enum bp_result dal_bios_parser_program_display_engine_pll(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params)
++{
++
++ if (!bp->cmd_tbl.program_clock)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.program_clock(bp, bp_params);
++
++}
++
++enum signal_type dal_bios_parser_dac_load_detect(
++ struct bios_parser *bp,
++ struct graphics_object_id encoder,
++ struct graphics_object_id connector,
++ enum signal_type display_signal)
++{
++ if (!bp->cmd_tbl.dac_load_detection)
++ return SIGNAL_TYPE_NONE;
++
++ return bp->cmd_tbl.dac_load_detection(bp, encoder, connector,
++ display_signal);
++}
++
++enum bp_result dal_bios_parser_get_divider_for_target_display_clock(
++ struct bios_parser *bp,
++ struct bp_display_clock_parameters *bp_params)
++{
++ if (!bp->cmd_tbl.compute_memore_engine_pll)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.compute_memore_engine_pll(bp, bp_params);
++}
++
++enum bp_result dal_bios_parser_dvo_encoder_control(
++ struct bios_parser *bp,
++ struct bp_dvo_encoder_control *cntl)
++{
++ if (!bp->cmd_tbl.dvo_encoder_control)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.dvo_encoder_control(bp, cntl);
++}
++
++enum bp_result dal_bios_parser_enable_crtc(
++ struct bios_parser *bp,
++ enum controller_id id,
++ bool enable)
++{
++ if (!bp->cmd_tbl.enable_crtc)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.enable_crtc(bp, id, enable);
++}
++
++enum bp_result dal_bios_parser_blank_crtc(
++ struct bios_parser *bp,
++ struct bp_blank_crtc_parameters *bp_params,
++ bool blank)
++{
++ if (!bp->cmd_tbl.blank_crtc)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.blank_crtc(bp, bp_params, blank);
++}
++
++enum bp_result dal_bios_parser_crtc_source_select(
++ struct bios_parser *bp,
++ struct bp_crtc_source_select *bp_params)
++{
++ if (!bp->cmd_tbl.select_crtc_source)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.select_crtc_source(bp, bp_params);
++}
++
++enum bp_result dal_bios_parser_set_overscan(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_overscan_parameters *bp_params)
++{
++
++ if (!bp->cmd_tbl.set_crtc_overscan)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.set_crtc_overscan(bp, bp_params);
++}
++
++enum bp_result dal_bios_parser_enable_memory_requests(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ bool enable)
++{
++ if (!bp->cmd_tbl.enable_crtc_mem_req)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.enable_crtc_mem_req(bp, controller_id, enable);
++}
++
++enum bp_result dal_bios_parser_external_encoder_control(
++ struct bios_parser *bp,
++ struct bp_external_encoder_control *cntl)
++{
++ if (!bp->cmd_tbl.external_encoder_control)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.external_encoder_control(bp, cntl);
++}
++
++enum bp_result dal_bios_parser_enable_disp_power_gating(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ enum bp_pipe_control_action action)
++{
++ if (!bp->cmd_tbl.enable_disp_power_gating)
++ return BP_RESULT_FAILURE;
++
++ return bp->cmd_tbl.enable_disp_power_gating(bp, controller_id,
++ action);
++}
++
++bool dal_bios_parser_is_device_id_supported(
++ struct bios_parser *bp,
++ struct device_id id)
++{
++ uint32_t mask = get_support_mask_for_device_id(id);
++
++ return (le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport) & mask) != 0;
++}
++
++enum bp_result dal_bios_parser_crt_control(
++ struct bios_parser *bp,
++ enum engine_id engine_id,
++ bool enable,
++ uint32_t pixel_clock)
++{
++ uint8_t standard;
++
++ if (!bp->cmd_tbl.dac1_encoder_control &&
++ engine_id == ENGINE_ID_DACA)
++ return BP_RESULT_FAILURE;
++ if (!bp->cmd_tbl.dac2_encoder_control &&
++ engine_id == ENGINE_ID_DACB)
++ return BP_RESULT_FAILURE;
++ /* validate params */
++ switch (engine_id) {
++ case ENGINE_ID_DACA:
++ case ENGINE_ID_DACB:
++ break;
++ default:
++ /* unsupported engine */
++ return BP_RESULT_FAILURE;
++ }
++
++ standard = ATOM_DAC1_PS2; /* == ATOM_DAC2_PS2 */
++
++ if (enable) {
++ if (engine_id == ENGINE_ID_DACA) {
++ bp->cmd_tbl.dac1_encoder_control(bp, enable,
++ pixel_clock, standard);
++ if (bp->cmd_tbl.dac1_output_control != NULL)
++ bp->cmd_tbl.dac1_output_control(bp, enable);
++ } else {
++ bp->cmd_tbl.dac2_encoder_control(bp, enable,
++ pixel_clock, standard);
++ if (bp->cmd_tbl.dac2_output_control != NULL)
++ bp->cmd_tbl.dac2_output_control(bp, enable);
++ }
++ } else {
++ if (engine_id == ENGINE_ID_DACA) {
++ if (bp->cmd_tbl.dac1_output_control != NULL)
++ bp->cmd_tbl.dac1_output_control(bp, enable);
++ bp->cmd_tbl.dac1_encoder_control(bp, enable,
++ pixel_clock, standard);
++ } else {
++ if (bp->cmd_tbl.dac2_output_control != NULL)
++ bp->cmd_tbl.dac2_output_control(bp, enable);
++ bp->cmd_tbl.dac2_encoder_control(bp, enable,
++ pixel_clock, standard);
++ }
++ }
++
++ return BP_RESULT_OK;
++}
++
++static ATOM_HPD_INT_RECORD *get_hpd_record(struct bios_parser *bp,
++ ATOM_OBJECT *object)
++{
++ ATOM_COMMON_RECORD_HEADER *header;
++ uint32_t offset;
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object */
++ return NULL;
++ }
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!header)
++ return NULL;
++
++ if (LAST_RECORD_TYPE == header->ucRecordType ||
++ !header->ucRecordSize)
++ break;
++
++ if (ATOM_HPD_INT_RECORD_TYPE == header->ucRecordType
++ && sizeof(ATOM_HPD_INT_RECORD) <= header->ucRecordSize)
++ return (ATOM_HPD_INT_RECORD *) header;
++
++ offset += header->ucRecordSize;
++ }
++
++ return NULL;
++}
++
++/**
++ * Get I2C information of input object id
++ *
++ * search all records to find the ATOM_I2C_RECORD_TYPE record IR
++ */
++static ATOM_I2C_RECORD *get_i2c_record(
++ struct bios_parser *bp,
++ ATOM_OBJECT *object)
++{
++ uint32_t offset;
++ ATOM_COMMON_RECORD_HEADER *record_header;
++
++ if (!object) {
++ BREAK_TO_DEBUGGER();
++ /* Invalid object */
++ return NULL;
++ }
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ record_header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!record_header)
++ return NULL;
++
++ if (LAST_RECORD_TYPE == record_header->ucRecordType ||
++ 0 == record_header->ucRecordSize)
++ break;
++
++ if (ATOM_I2C_RECORD_TYPE == record_header->ucRecordType &&
++ sizeof(ATOM_I2C_RECORD) <=
++ record_header->ucRecordSize) {
++ return (ATOM_I2C_RECORD *)record_header;
++ }
++
++ offset += record_header->ucRecordSize;
++ }
++
++ return NULL;
++}
++
++
++static enum bp_result get_ss_info_from_ss_info_table(
++ struct bios_parser *bp,
++ uint32_t id,
++ struct spread_spectrum_info *ss_info);
++static enum bp_result get_ss_info_from_tbl(
++ struct bios_parser *bp,
++ uint32_t id,
++ struct spread_spectrum_info *ss_info);
++/**
++ * dal_bios_parser_get_spread_spectrum_info
++ * Get spread spectrum information from the ASIC_InternalSS_Info(ver 2.1 or
++ * ver 3.1) or SS_Info table from the VBIOS. Currently ASIC_InternalSS_Info
++ * ver 2.1 can co-exist with SS_Info table. Expect ASIC_InternalSS_Info ver 3.1,
++ * there is only one entry for each signal /ss id. However, there is
++ * no planning of supporting multiple spread Sprectum entry for EverGreen
++ * @param [in] this
++ * @param [in] signal, ASSignalType to be converted to info index
++ * @param [in] index, number of entries that match the converted info index
++ * @param [out] ss_info, sprectrum information structure,
++ * @return Bios parser result code
++ */
++enum bp_result dal_bios_parser_get_spread_spectrum_info(
++ struct bios_parser *bp,
++ enum as_signal_type signal,
++ uint32_t index,
++ struct spread_spectrum_info *ss_info)
++{
++ enum bp_result result = BP_RESULT_UNSUPPORTED;
++ uint32_t clk_id_ss = 0;
++ ATOM_COMMON_TABLE_HEADER *header;
++ struct atom_data_revision tbl_revision;
++
++ if (!ss_info) /* check for bad input */
++ return BP_RESULT_BADINPUT;
++ /* signal translation */
++ clk_id_ss = signal_to_ss_id(signal);
++
++ if (!DATA_TABLES(ASIC_InternalSS_Info))
++ if (!index)
++ return get_ss_info_from_ss_info_table(bp, clk_id_ss,
++ ss_info);
++
++ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
++ DATA_TABLES(ASIC_InternalSS_Info));
++ get_atom_data_table_revision(header, &tbl_revision);
++
++ switch (tbl_revision.major) {
++ case 2:
++ switch (tbl_revision.minor) {
++ case 1:
++ /* there can not be more then one entry for Internal
++ * SS Info table version 2.1 */
++ if (!index)
++ return get_ss_info_from_tbl(bp, clk_id_ss,
++ ss_info);
++ break;
++ default:
++ break;
++ }
++ break;
++
++ case 3:
++ switch (tbl_revision.minor) {
++ case 1:
++ return get_ss_info_v3_1(bp, clk_id_ss, index, ss_info);
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++ /* there can not be more then one entry for SS Info table */
++ return result;
++}
++
++static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
++ struct bios_parser *bp,
++ uint32_t id,
++ struct spread_spectrum_info *info);
++
++/**
++ * get_ss_info_from_table
++ * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
++ * SS_Info table from the VBIOS
++ * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
++ * SS_Info.
++ *
++ * @param this
++ * @param id, spread sprectrum info index
++ * @param pSSinfo, sprectrum information structure,
++ * @return Bios parser result code
++ */
++static enum bp_result get_ss_info_from_tbl(
++ struct bios_parser *bp,
++ uint32_t id,
++ struct spread_spectrum_info *ss_info)
++{
++ if (!ss_info) /* check for bad input, if ss_info is not NULL */
++ return BP_RESULT_BADINPUT;
++ /* for SS_Info table only support DP and LVDS */
++ if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
++ return get_ss_info_from_ss_info_table(bp, id, ss_info);
++ else
++ return get_ss_info_from_internal_ss_info_tbl_V2_1(bp, id,
++ ss_info);
++}
++
++/**
++ * get_ss_info_from_internal_ss_info_tbl_V2_1
++ * Get spread sprectrum information from the ASIC_InternalSS_Info table Ver 2.1
++ * from the VBIOS
++ * There will not be multiple entry for Ver 2.1
++ *
++ * @param id, spread sprectrum info index
++ * @param pSSinfo, sprectrum information structure,
++ * @return Bios parser result code
++ */
++static enum bp_result get_ss_info_from_internal_ss_info_tbl_V2_1(
++ struct bios_parser *bp,
++ uint32_t id,
++ struct spread_spectrum_info *info)
++{
++ enum bp_result result = BP_RESULT_UNSUPPORTED;
++ ATOM_ASIC_INTERNAL_SS_INFO_V2 *header;
++ ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
++ uint32_t tbl_size, i;
++
++ if (!DATA_TABLES(ASIC_InternalSS_Info))
++ return result;
++
++ header = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
++ DATA_TABLES(ASIC_InternalSS_Info));
++
++ dc_service_memset(info, 0, sizeof(struct spread_spectrum_info));
++
++ tbl_size = (le16_to_cpu(header->sHeader.usStructureSize)
++ - sizeof(ATOM_COMMON_TABLE_HEADER))
++ / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
++
++ tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
++ &(header->asSpreadSpectrum[0]);
++ for (i = 0; i < tbl_size; i++) {
++ result = BP_RESULT_NORECORD;
++
++ if (tbl[i].ucClockIndication != (uint8_t)id)
++ continue;
++
++ if (ATOM_EXTERNAL_SS_MASK
++ & tbl[i].ucSpreadSpectrumMode) {
++ info->type.EXTERNAL = true;
++ }
++ if (ATOM_SS_CENTRE_SPREAD_MODE_MASK
++ & tbl[i].ucSpreadSpectrumMode) {
++ info->type.CENTER_MODE = true;
++ }
++ info->type.STEP_AND_DELAY_INFO = false;
++ /* convert [10KHz] into [KHz] */
++ info->target_clock_range =
++ le32_to_cpu(tbl[i].ulTargetClockRange) * 10;
++ info->spread_spectrum_percentage =
++ (uint32_t)le16_to_cpu(tbl[i].usSpreadSpectrumPercentage);
++ info->spread_spectrum_range =
++ (uint32_t)(le16_to_cpu(tbl[i].usSpreadRateIn10Hz) * 10);
++ result = BP_RESULT_OK;
++ break;
++ }
++
++ return result;
++
++}
++
++/**
++ * get_ss_info_from_ss_info_table
++ * Get spread sprectrum information from the SS_Info table from the VBIOS
++ * if the pointer to info is NULL, indicate the caller what to know the number
++ * of entries that matches the id
++ * for, the SS_Info table, there should not be more than 1 entry match.
++ *
++ * @param [in] id, spread sprectrum id
++ * @param [out] pSSinfo, sprectrum information structure,
++ * @return Bios parser result code
++ */
++static enum bp_result get_ss_info_from_ss_info_table(
++ struct bios_parser *bp,
++ uint32_t id,
++ struct spread_spectrum_info *ss_info)
++{
++ enum bp_result result = BP_RESULT_UNSUPPORTED;
++ ATOM_SPREAD_SPECTRUM_INFO *tbl;
++ ATOM_COMMON_TABLE_HEADER *header;
++ uint32_t table_size;
++ uint32_t i;
++ uint32_t id_local = SS_ID_UNKNOWN;
++ struct atom_data_revision revision;
++
++ /* exist of the SS_Info table */
++ /* check for bad input, pSSinfo can not be NULL */
++ if (!DATA_TABLES(SS_Info) || !ss_info)
++ return result;
++
++ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(SS_Info));
++ get_atom_data_table_revision(header, &revision);
++
++ tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO, DATA_TABLES(SS_Info));
++
++ if (1 != revision.major || 2 > revision.minor)
++ return result;
++
++ /* have to convert from Internal_SS format to SS_Info format */
++ switch (id) {
++ case ASIC_INTERNAL_SS_ON_DP:
++ id_local = SS_ID_DP1;
++ break;
++ case ASIC_INTERNAL_SS_ON_LVDS:
++ {
++ struct embedded_panel_info panel_info;
++
++ if (dal_bios_parser_get_embedded_panel_info(bp, &panel_info)
++ == BP_RESULT_OK)
++ id_local = panel_info.ss_id;
++ break;
++ }
++ default:
++ break;
++ }
++
++ if (id_local == SS_ID_UNKNOWN)
++ return result;
++
++ table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
++ sizeof(ATOM_COMMON_TABLE_HEADER)) /
++ sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
++
++ for (i = 0; i < table_size; i++) {
++ if (id_local != (uint32_t)tbl->asSS_Info[i].ucSS_Id)
++ continue;
++
++ dc_service_memset(ss_info, 0, sizeof(struct spread_spectrum_info));
++
++ if (ATOM_EXTERNAL_SS_MASK &
++ tbl->asSS_Info[i].ucSpreadSpectrumType)
++ ss_info->type.EXTERNAL = true;
++
++ if (ATOM_SS_CENTRE_SPREAD_MODE_MASK &
++ tbl->asSS_Info[i].ucSpreadSpectrumType)
++ ss_info->type.CENTER_MODE = true;
++
++ ss_info->type.STEP_AND_DELAY_INFO = true;
++ ss_info->spread_spectrum_percentage =
++ (uint32_t)le16_to_cpu(tbl->asSS_Info[i].usSpreadSpectrumPercentage);
++ ss_info->step_and_delay_info.step = tbl->asSS_Info[i].ucSS_Step;
++ ss_info->step_and_delay_info.delay =
++ tbl->asSS_Info[i].ucSS_Delay;
++ ss_info->step_and_delay_info.recommended_ref_div =
++ tbl->asSS_Info[i].ucRecommendedRef_Div;
++ ss_info->spread_spectrum_range =
++ (uint32_t)tbl->asSS_Info[i].ucSS_Range * 10000;
++
++ /* there will be only one entry for each display type in SS_info
++ * table */
++ result = BP_RESULT_OK;
++ break;
++ }
++
++ return result;
++}
++static enum bp_result get_embedded_panel_info_v1_2(
++ struct bios_parser *bp,
++ struct embedded_panel_info *info);
++static enum bp_result get_embedded_panel_info_v1_3(
++ struct bios_parser *bp,
++ struct embedded_panel_info *info);
++
++enum bp_result dal_bios_parser_get_embedded_panel_info(
++ struct bios_parser *bp,
++ struct embedded_panel_info *info)
++{
++ ATOM_COMMON_TABLE_HEADER *hdr;
++
++ if (!DATA_TABLES(LCD_Info))
++ return BP_RESULT_FAILURE;
++
++ hdr = GET_IMAGE(ATOM_COMMON_TABLE_HEADER, DATA_TABLES(LCD_Info));
++
++ if (!hdr)
++ return BP_RESULT_BADBIOSTABLE;
++
++ switch (hdr->ucTableFormatRevision) {
++ case 1:
++ switch (hdr->ucTableContentRevision) {
++ case 0:
++ case 1:
++ case 2:
++ return get_embedded_panel_info_v1_2(bp, info);
++ case 3:
++ return get_embedded_panel_info_v1_3(bp, info);
++ default:
++ break;
++ }
++ default:
++ break;
++ }
++
++ return BP_RESULT_FAILURE;
++}
++
++static enum bp_result get_embedded_panel_info_v1_2(
++ struct bios_parser *bp,
++ struct embedded_panel_info *info)
++{
++ ATOM_LVDS_INFO_V12 *lvds;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ if (!DATA_TABLES(LVDS_Info))
++ return BP_RESULT_UNSUPPORTED;
++
++ lvds =
++ GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
++
++ if (!lvds)
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (1 != lvds->sHeader.ucTableFormatRevision
++ || 2 > lvds->sHeader.ucTableContentRevision)
++ return BP_RESULT_UNSUPPORTED;
++
++ dc_service_memset(info, 0, sizeof(struct embedded_panel_info));
++
++ /* We need to convert from 10KHz units into KHz units*/
++ info->lcd_timing.pixel_clk =
++ le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
++ /* usHActive does not include borders, according to VBIOS team*/
++ info->lcd_timing.horizontal_addressable =
++ le16_to_cpu(lvds->sLCDTiming.usHActive);
++ /* usHBlanking_Time includes borders, so we should really be subtracting
++ * borders duing this translation, but LVDS generally*/
++ /* doesn't have borders, so we should be okay leaving this as is for
++ * now. May need to revisit if we ever have LVDS with borders*/
++ info->lcd_timing.horizontal_blanking_time =
++ le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
++ /* usVActive does not include borders, according to VBIOS team*/
++ info->lcd_timing.vertical_addressable =
++ le16_to_cpu(lvds->sLCDTiming.usVActive);
++ /* usVBlanking_Time includes borders, so we should really be subtracting
++ * borders duing this translation, but LVDS generally*/
++ /* doesn't have borders, so we should be okay leaving this as is for
++ * now. May need to revisit if we ever have LVDS with borders*/
++ info->lcd_timing.vertical_blanking_time =
++ le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
++ info->lcd_timing.horizontal_sync_offset =
++ le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
++ info->lcd_timing.horizontal_sync_width =
++ le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
++ info->lcd_timing.vertical_sync_offset =
++ le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
++ info->lcd_timing.vertical_sync_width =
++ le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
++ info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
++ info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
++ info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
++ info->lcd_timing.misc_info.H_SYNC_POLARITY =
++ ~(uint32_t)
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
++ info->lcd_timing.misc_info.V_SYNC_POLARITY =
++ ~(uint32_t)
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
++ info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
++ info->lcd_timing.misc_info.H_REPLICATION_BY2 =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
++ info->lcd_timing.misc_info.V_REPLICATION_BY2 =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
++ info->lcd_timing.misc_info.COMPOSITE_SYNC =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
++ info->lcd_timing.misc_info.INTERLACE =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
++ info->lcd_timing.misc_info.DOUBLE_CLOCK =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
++ info->ss_id = lvds->ucSS_Id;
++
++ {
++ uint8_t rr = le16_to_cpu(lvds->usSupportedRefreshRate);
++ /* Get minimum supported refresh rate*/
++ if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
++ info->supported_rr.REFRESH_RATE_30HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
++ info->supported_rr.REFRESH_RATE_40HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
++ info->supported_rr.REFRESH_RATE_48HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
++ info->supported_rr.REFRESH_RATE_50HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
++ info->supported_rr.REFRESH_RATE_60HZ = 1;
++ }
++
++ /*Drr panel support can be reported by VBIOS*/
++ if (LCDPANEL_CAP_DRR_SUPPORTED
++ & lvds->ucLCDPanel_SpecialHandlingCap)
++ info->drr_enabled = 1;
++
++ if (ATOM_PANEL_MISC_DUAL & lvds->ucLVDS_Misc)
++ info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
++
++ if (ATOM_PANEL_MISC_888RGB & lvds->ucLVDS_Misc)
++ info->lcd_timing.misc_info.RGB888 = true;
++
++ info->lcd_timing.misc_info.GREY_LEVEL =
++ (uint32_t) (ATOM_PANEL_MISC_GREY_LEVEL &
++ lvds->ucLVDS_Misc) >> ATOM_PANEL_MISC_GREY_LEVEL_SHIFT;
++
++ if (ATOM_PANEL_MISC_SPATIAL & lvds->ucLVDS_Misc)
++ info->lcd_timing.misc_info.SPATIAL = true;
++
++ if (ATOM_PANEL_MISC_TEMPORAL & lvds->ucLVDS_Misc)
++ info->lcd_timing.misc_info.TEMPORAL = true;
++
++ if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc)
++ info->lcd_timing.misc_info.API_ENABLED = true;
++
++ return BP_RESULT_OK;
++}
++
++static enum bp_result get_embedded_panel_info_v1_3(
++ struct bios_parser *bp,
++ struct embedded_panel_info *info)
++{
++ ATOM_LCD_INFO_V13 *lvds;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ if (!DATA_TABLES(LCD_Info))
++ return BP_RESULT_UNSUPPORTED;
++
++ lvds = GET_IMAGE(ATOM_LCD_INFO_V13, DATA_TABLES(LCD_Info));
++
++ if (!lvds)
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (!((1 == lvds->sHeader.ucTableFormatRevision)
++ && (3 <= lvds->sHeader.ucTableContentRevision)))
++ return BP_RESULT_UNSUPPORTED;
++
++ dc_service_memset(info, 0, sizeof(struct embedded_panel_info));
++
++ /* We need to convert from 10KHz units into KHz units */
++ info->lcd_timing.pixel_clk =
++ le16_to_cpu(lvds->sLCDTiming.usPixClk) * 10;
++ /* usHActive does not include borders, according to VBIOS team */
++ info->lcd_timing.horizontal_addressable =
++ le16_to_cpu(lvds->sLCDTiming.usHActive);
++ /* usHBlanking_Time includes borders, so we should really be subtracting
++ * borders duing this translation, but LVDS generally*/
++ /* doesn't have borders, so we should be okay leaving this as is for
++ * now. May need to revisit if we ever have LVDS with borders*/
++ info->lcd_timing.horizontal_blanking_time =
++ le16_to_cpu(lvds->sLCDTiming.usHBlanking_Time);
++ /* usVActive does not include borders, according to VBIOS team*/
++ info->lcd_timing.vertical_addressable =
++ le16_to_cpu(lvds->sLCDTiming.usVActive);
++ /* usVBlanking_Time includes borders, so we should really be subtracting
++ * borders duing this translation, but LVDS generally*/
++ /* doesn't have borders, so we should be okay leaving this as is for
++ * now. May need to revisit if we ever have LVDS with borders*/
++ info->lcd_timing.vertical_blanking_time =
++ le16_to_cpu(lvds->sLCDTiming.usVBlanking_Time);
++ info->lcd_timing.horizontal_sync_offset =
++ le16_to_cpu(lvds->sLCDTiming.usHSyncOffset);
++ info->lcd_timing.horizontal_sync_width =
++ le16_to_cpu(lvds->sLCDTiming.usHSyncWidth);
++ info->lcd_timing.vertical_sync_offset =
++ le16_to_cpu(lvds->sLCDTiming.usVSyncOffset);
++ info->lcd_timing.vertical_sync_width =
++ le16_to_cpu(lvds->sLCDTiming.usVSyncWidth);
++ info->lcd_timing.horizontal_border = lvds->sLCDTiming.ucHBorder;
++ info->lcd_timing.vertical_border = lvds->sLCDTiming.ucVBorder;
++ info->lcd_timing.misc_info.HORIZONTAL_CUT_OFF =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HorizontalCutOff;
++ info->lcd_timing.misc_info.H_SYNC_POLARITY =
++ ~(uint32_t)
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.HSyncPolarity;
++ info->lcd_timing.misc_info.V_SYNC_POLARITY =
++ ~(uint32_t)
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VSyncPolarity;
++ info->lcd_timing.misc_info.VERTICAL_CUT_OFF =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.VerticalCutOff;
++ info->lcd_timing.misc_info.H_REPLICATION_BY2 =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.H_ReplicationBy2;
++ info->lcd_timing.misc_info.V_REPLICATION_BY2 =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.V_ReplicationBy2;
++ info->lcd_timing.misc_info.COMPOSITE_SYNC =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.CompositeSync;
++ info->lcd_timing.misc_info.INTERLACE =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.Interlace;
++ info->lcd_timing.misc_info.DOUBLE_CLOCK =
++ lvds->sLCDTiming.susModeMiscInfo.sbfAccess.DoubleClock;
++ info->ss_id = lvds->ucSS_Id;
++
++ /* Drr panel support can be reported by VBIOS*/
++ if (LCDPANEL_CAP_V13_DRR_SUPPORTED
++ & lvds->ucLCDPanel_SpecialHandlingCap)
++ info->drr_enabled = 1;
++
++ /* Get supported refresh rate*/
++ if (info->drr_enabled == 1) {
++ uint8_t min_rr =
++ lvds->sRefreshRateSupport.ucMinRefreshRateForDRR;
++ uint8_t rr = lvds->sRefreshRateSupport.ucSupportedRefreshRate;
++
++ if (min_rr != 0) {
++ if (SUPPORTED_LCD_REFRESHRATE_30Hz & min_rr)
++ info->supported_rr.REFRESH_RATE_30HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_40Hz & min_rr)
++ info->supported_rr.REFRESH_RATE_40HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_48Hz & min_rr)
++ info->supported_rr.REFRESH_RATE_48HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_50Hz & min_rr)
++ info->supported_rr.REFRESH_RATE_50HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_60Hz & min_rr)
++ info->supported_rr.REFRESH_RATE_60HZ = 1;
++ } else {
++ if (SUPPORTED_LCD_REFRESHRATE_30Hz & rr)
++ info->supported_rr.REFRESH_RATE_30HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_40Hz & rr)
++ info->supported_rr.REFRESH_RATE_40HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_48Hz & rr)
++ info->supported_rr.REFRESH_RATE_48HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_50Hz & rr)
++ info->supported_rr.REFRESH_RATE_50HZ = 1;
++ else if (SUPPORTED_LCD_REFRESHRATE_60Hz & rr)
++ info->supported_rr.REFRESH_RATE_60HZ = 1;
++ }
++ }
++
++ if (ATOM_PANEL_MISC_V13_DUAL & lvds->ucLCD_Misc)
++ info->lcd_timing.misc_info.DOUBLE_CLOCK = true;
++
++ if (ATOM_PANEL_MISC_V13_8BIT_PER_COLOR & lvds->ucLCD_Misc)
++ info->lcd_timing.misc_info.RGB888 = true;
++
++ info->lcd_timing.misc_info.GREY_LEVEL =
++ (uint32_t) (ATOM_PANEL_MISC_V13_GREY_LEVEL &
++ lvds->ucLCD_Misc) >> ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT;
++
++ return BP_RESULT_OK;
++}
++
++/**
++ * dal_bios_parser_get_encoder_cap_info
++ *
++ * @brief
++ * Get encoder capability information of input object id
++ *
++ * @param object_id, Object id
++ * @param object_id, encoder cap information structure
++ *
++ * @return Bios parser result code
++ *
++ */
++enum bp_result dal_bios_parser_get_encoder_cap_info(
++ struct bios_parser *bp,
++ struct graphics_object_id object_id,
++ struct bp_encoder_cap_info *info)
++{
++ ATOM_OBJECT *object;
++ ATOM_ENCODER_CAP_RECORD *record = NULL;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ object = get_bios_object(bp, object_id);
++
++ if (!object)
++ return BP_RESULT_BADINPUT;
++
++ record = get_encoder_cap_record(bp, object);
++ if (!record)
++ return BP_RESULT_NORECORD;
++
++ info->DP_HBR2_CAP = record->usHBR2Cap;
++ info->DP_HBR2_EN = record->usHBR2En;
++ return BP_RESULT_OK;
++}
++
++/**
++ * get_encoder_cap_record
++ *
++ * @brief
++ * Get encoder cap record for the object
++ *
++ * @param object, ATOM object
++ *
++ * @return atom encoder cap record
++ *
++ * @note
++ * search all records to find the ATOM_ENCODER_CAP_RECORD record
++ */
++static ATOM_ENCODER_CAP_RECORD *get_encoder_cap_record(
++ struct bios_parser *bp,
++ ATOM_OBJECT *object)
++{
++ ATOM_COMMON_RECORD_HEADER *header;
++ uint32_t offset;
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object */
++ return NULL;
++ }
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!header)
++ return NULL;
++
++ offset += header->ucRecordSize;
++
++ if (LAST_RECORD_TYPE == header->ucRecordType ||
++ !header->ucRecordSize)
++ break;
++
++ if (ATOM_ENCODER_CAP_RECORD_TYPE != header->ucRecordType)
++ continue;
++
++ if (sizeof(ATOM_ENCODER_CAP_RECORD) <= header->ucRecordSize)
++ return (ATOM_ENCODER_CAP_RECORD *)header;
++ }
++
++ return NULL;
++}
++
++/**
++ * dal_bios_parser_get_din_connector_info
++ * @brief
++ * Get GPIO record for the DIN connector, this GPIO tells whether there is a
++ * CV dumb dongle
++ * attached to the DIN connector to perform load detection for the the
++ * appropriate signal
++ *
++ * @param id - DIN connector object id
++ * @param info - GPIO record infor
++ * @return Bios parser result code
++ */
++enum bp_result dal_bios_parser_get_din_connector_info(
++ struct bios_parser *bp,
++ struct graphics_object_id id,
++ struct din_connector_info *info)
++{
++ ATOM_COMMON_RECORD_HEADER *header;
++ ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD *record = NULL;
++ ATOM_OBJECT *object;
++ uint32_t offset;
++ enum bp_result result = BP_RESULT_NORECORD;
++
++ /* no output buffer provided */
++ if (!info) {
++ BREAK_TO_DEBUGGER(); /* Invalid output buffer */
++ return BP_RESULT_BADINPUT;
++ }
++
++ object = get_bios_object(bp, id);
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object id */;
++ return BP_RESULT_BADINPUT;
++ }
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!header) {
++ result = BP_RESULT_BADBIOSTABLE;
++ break;
++ }
++
++ offset += header->ucRecordSize;
++
++ /* get out of the loop if no more records */
++ if (LAST_RECORD_TYPE == header->ucRecordType ||
++ !header->ucRecordSize)
++ break;
++
++ if (ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD_TYPE !=
++ header->ucRecordType)
++ continue;
++
++ if (sizeof(ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD)
++ > header->ucRecordSize)
++ continue;
++
++ record = (ATOM_CONNECTOR_CVTV_SHARE_DIN_RECORD *)header;
++ result = BP_RESULT_OK;
++ break;
++ }
++
++ /* return if the record not found */
++ if (result != BP_RESULT_OK)
++ return result;
++
++ info->gpio_id = record->ucGPIOID;
++ info->gpio_tv_active_state = (record->ucTVActiveState != 0);
++
++ return result;
++}
++
++static uint32_t get_ss_entry_number(
++ struct bios_parser *bp,
++ uint32_t id);
++static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
++ struct bios_parser *bp,
++ uint32_t id);
++static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
++ struct bios_parser *bp,
++ uint32_t id);
++static uint32_t get_ss_entry_number_from_ss_info_tbl(
++ struct bios_parser *bp,
++ uint32_t id);
++
++/**
++ * BiosParserObject::GetNumberofSpreadSpectrumEntry
++ * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table from
++ * the VBIOS that match the SSid (to be converted from signal)
++ *
++ * @param[in] signal, ASSignalType to be converted to SSid
++ * @return number of SS Entry that match the signal
++ */
++uint32_t dal_bios_parser_get_ss_entry_number(
++ struct bios_parser *bp,
++ enum as_signal_type signal)
++{
++ uint32_t ss_id = 0;
++ ATOM_COMMON_TABLE_HEADER *header;
++ struct atom_data_revision revision;
++
++ ss_id = signal_to_ss_id(signal);
++
++ if (!DATA_TABLES(ASIC_InternalSS_Info))
++ return get_ss_entry_number_from_ss_info_tbl(bp, ss_id);
++
++ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
++ DATA_TABLES(ASIC_InternalSS_Info));
++ get_atom_data_table_revision(header, &revision);
++
++ switch (revision.major) {
++ case 2:
++ switch (revision.minor) {
++ case 1:
++ return get_ss_entry_number(bp, ss_id);
++ default:
++ break;
++ }
++ break;
++ case 3:
++ switch (revision.minor) {
++ case 1:
++ return
++ get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
++ bp, ss_id);
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++
++/**
++ * get_ss_entry_number_from_ss_info_tbl
++ * Get Number of spread spectrum entry from the SS_Info table from the VBIOS.
++ *
++ * @note There can only be one entry for each id for SS_Info Table
++ *
++ * @param [in] id, spread spectrum id
++ * @return number of SS Entry that match the id
++ */
++static uint32_t get_ss_entry_number_from_ss_info_tbl(
++ struct bios_parser *bp,
++ uint32_t id)
++{
++ ATOM_SPREAD_SPECTRUM_INFO *tbl;
++ ATOM_COMMON_TABLE_HEADER *header;
++ uint32_t table_size;
++ uint32_t i;
++ uint32_t number = 0;
++ uint32_t id_local = SS_ID_UNKNOWN;
++ struct atom_data_revision revision;
++
++ /* SS_Info table exist */
++ if (!DATA_TABLES(SS_Info))
++ return number;
++
++ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
++ DATA_TABLES(SS_Info));
++ get_atom_data_table_revision(header, &revision);
++
++ tbl = GET_IMAGE(ATOM_SPREAD_SPECTRUM_INFO,
++ DATA_TABLES(SS_Info));
++
++ if (1 != revision.major || 2 > revision.minor)
++ return number;
++
++ /* have to convert from Internal_SS format to SS_Info format */
++ switch (id) {
++ case ASIC_INTERNAL_SS_ON_DP:
++ id_local = SS_ID_DP1;
++ break;
++ case ASIC_INTERNAL_SS_ON_LVDS: {
++ struct embedded_panel_info panel_info;
++
++ if (dal_bios_parser_get_embedded_panel_info(bp, &panel_info)
++ == BP_RESULT_OK)
++ id_local = panel_info.ss_id;
++ break;
++ }
++ default:
++ break;
++ }
++
++ if (id_local == SS_ID_UNKNOWN)
++ return number;
++
++ table_size = (le16_to_cpu(tbl->sHeader.usStructureSize) -
++ sizeof(ATOM_COMMON_TABLE_HEADER)) /
++ sizeof(ATOM_SPREAD_SPECTRUM_ASSIGNMENT);
++
++ for (i = 0; i < table_size; i++)
++ if (id_local == (uint32_t)tbl->asSS_Info[i].ucSS_Id) {
++ number = 1;
++ break;
++ }
++
++ return number;
++}
++
++
++/**
++ * get_ss_entry_number
++ * Get spread sprectrum information from the ASIC_InternalSS_Info Ver 2.1 or
++ * SS_Info table from the VBIOS
++ * There can not be more than 1 entry for ASIC_InternalSS_Info Ver 2.1 or
++ * SS_Info.
++ *
++ * @param id, spread sprectrum info index
++ * @return Bios parser result code
++ */
++static uint32_t get_ss_entry_number(struct bios_parser *bp, uint32_t id)
++{
++ if (id == ASIC_INTERNAL_SS_ON_DP || id == ASIC_INTERNAL_SS_ON_LVDS)
++ return get_ss_entry_number_from_ss_info_tbl(bp, id);
++
++ return get_ss_entry_number_from_internal_ss_info_tbl_v2_1(bp, id);
++}
++
++/**
++ * get_ss_entry_number_from_internal_ss_info_tbl_v2_1
++ * Get NUmber of spread sprectrum entry from the ASIC_InternalSS_Info table
++ * Ver 2.1 from the VBIOS
++ * There will not be multiple entry for Ver 2.1
++ *
++ * @param id, spread sprectrum info index
++ * @return number of SS Entry that match the id
++ */
++static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_v2_1(
++ struct bios_parser *bp,
++ uint32_t id)
++{
++ ATOM_ASIC_INTERNAL_SS_INFO_V2 *header_include;
++ ATOM_ASIC_SS_ASSIGNMENT_V2 *tbl;
++ uint32_t size;
++ uint32_t i;
++
++ if (!DATA_TABLES(ASIC_InternalSS_Info))
++ return 0;
++
++ header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V2,
++ DATA_TABLES(ASIC_InternalSS_Info));
++
++ size = (le16_to_cpu(header_include->sHeader.usStructureSize)
++ - sizeof(ATOM_COMMON_TABLE_HEADER))
++ / sizeof(ATOM_ASIC_SS_ASSIGNMENT_V2);
++
++ tbl = (ATOM_ASIC_SS_ASSIGNMENT_V2 *)
++ &header_include->asSpreadSpectrum[0];
++ for (i = 0; i < size; i++)
++ if (tbl[i].ucClockIndication == (uint8_t)id)
++ return 1;
++
++ return 0;
++}
++/**
++ * get_ss_entry_number_from_internal_ss_info_table_V3_1
++ * Get Number of SpreadSpectrum Entry from the ASIC_InternalSS_Info table of
++ * the VBIOS that matches id
++ *
++ * @param[in] id, spread sprectrum id
++ * @return number of SS Entry that match the id
++ */
++static uint32_t get_ss_entry_number_from_internal_ss_info_tbl_V3_1(
++ struct bios_parser *bp,
++ uint32_t id)
++{
++ uint32_t number = 0;
++ ATOM_ASIC_INTERNAL_SS_INFO_V3 *header_include;
++ ATOM_ASIC_SS_ASSIGNMENT_V3 *tbl;
++ uint32_t size;
++ uint32_t i;
++
++ if (!DATA_TABLES(ASIC_InternalSS_Info))
++ return number;
++
++ header_include = GET_IMAGE(ATOM_ASIC_INTERNAL_SS_INFO_V3,
++ DATA_TABLES(ASIC_InternalSS_Info));
++ size = (le16_to_cpu(header_include->sHeader.usStructureSize) -
++ sizeof(ATOM_COMMON_TABLE_HEADER)) /
++ sizeof(ATOM_ASIC_SS_ASSIGNMENT_V3);
++
++ tbl = (ATOM_ASIC_SS_ASSIGNMENT_V3 *)
++ &header_include->asSpreadSpectrum[0];
++
++ for (i = 0; i < size; i++)
++ if (tbl[i].ucClockIndication == (uint8_t)id)
++ number++;
++
++ return number;
++}
++
++static ATOM_FAKE_EDID_PATCH_RECORD *get_faked_edid_record(
++ struct bios_parser *bp)
++{
++ uint32_t size;
++ uint8_t *record;
++ ATOM_LVDS_INFO_V12 *info;
++
++ if (!DATA_TABLES(LVDS_Info))
++ return NULL;
++
++ info = GET_IMAGE(ATOM_LVDS_INFO_V12, DATA_TABLES(LVDS_Info));
++
++ if (!info)
++ return NULL;
++
++ if (1 != info->sHeader.ucTableFormatRevision
++ || 2 > info->sHeader.ucTableContentRevision)
++ return NULL;
++
++ if (!le16_to_cpu(info->usExtInfoTableOffset))
++ return NULL;
++
++ record = GET_IMAGE(uint8_t, DATA_TABLES(LVDS_Info)
++ + le16_to_cpu(info->usExtInfoTableOffset));
++
++ if (!record)
++ return NULL;
++
++ for (;;) {
++ if (ATOM_RECORD_END_TYPE == *record)
++ return NULL;
++
++ if (LCD_FAKE_EDID_PATCH_RECORD_TYPE == *record)
++ break;
++
++ size = get_record_size(record);
++
++ if (!size)
++ return NULL;
++
++ record += size;
++ }
++
++ return (ATOM_FAKE_EDID_PATCH_RECORD *)record;
++}
++
++enum bp_result dal_bios_parser_get_faked_edid_len(
++ struct bios_parser *bp,
++ uint32_t *len)
++{
++ ATOM_FAKE_EDID_PATCH_RECORD *edid_record = get_faked_edid_record(bp);
++
++ if (!edid_record)
++ return BP_RESULT_NORECORD;
++
++ *len = get_edid_size(edid_record);
++
++ return BP_RESULT_OK;
++}
++
++enum bp_result dal_bios_parser_get_faked_edid_buf(
++ struct bios_parser *bp,
++ uint8_t *buff,
++ uint32_t len)
++{
++ ATOM_FAKE_EDID_PATCH_RECORD *edid_record = get_faked_edid_record(bp);
++ uint32_t edid_size;
++
++ if (!edid_record)
++ return BP_RESULT_NORECORD;
++
++ edid_size = get_edid_size(edid_record);
++
++ if (len < edid_size)
++ return BP_RESULT_BADINPUT; /* buffer not big enough to fill */
++
++ dc_service_memmove(buff, &edid_record->ucFakeEDIDString, edid_size);
++
++ return BP_RESULT_OK;
++}
++
++/**
++ * dal_bios_parser_get_gpio_pin_info
++ * Get GpioPin information of input gpio id
++ *
++ * @param gpio_id, GPIO ID
++ * @param info, GpioPin information structure
++ * @return Bios parser result code
++ * @note
++ * to get the GPIO PIN INFO, we need:
++ * 1. get the GPIO_ID from other object table, see GetHPDInfo()
++ * 2. in DATA_TABLE.GPIO_Pin_LUT, search all records, to get the registerA
++ * offset/mask
++ */
++enum bp_result dal_bios_parser_get_gpio_pin_info(
++ struct bios_parser *bp,
++ uint32_t gpio_id,
++ struct gpio_pin_info *info)
++{
++ ATOM_GPIO_PIN_LUT *header;
++ uint32_t count = 0;
++ uint32_t i = 0;
++
++ if (!DATA_TABLES(GPIO_Pin_LUT))
++ return BP_RESULT_BADBIOSTABLE;
++
++ header = GET_IMAGE(ATOM_GPIO_PIN_LUT, DATA_TABLES(GPIO_Pin_LUT));
++ if (!header)
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_PIN_LUT)
++ > le16_to_cpu(header->sHeader.usStructureSize))
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (1 != header->sHeader.ucTableContentRevision)
++ return BP_RESULT_UNSUPPORTED;
++
++ count = (le16_to_cpu(header->sHeader.usStructureSize)
++ - sizeof(ATOM_COMMON_TABLE_HEADER))
++ / sizeof(ATOM_GPIO_PIN_ASSIGNMENT);
++ for (i = 0; i < count; ++i) {
++ if (header->asGPIO_Pin[i].ucGPIO_ID != gpio_id)
++ continue;
++
++ info->offset =
++ (uint32_t) le16_to_cpu(header->asGPIO_Pin[i].usGpioPin_AIndex);
++ info->offset_y = info->offset + 2;
++ info->offset_en = info->offset + 1;
++ info->offset_mask = info->offset - 1;
++
++ info->mask = (uint32_t) (1 <<
++ header->asGPIO_Pin[i].ucGpioPinBitShift);
++ info->mask_y = info->mask + 2;
++ info->mask_en = info->mask + 1;
++ info->mask_mask = info->mask - 1;
++
++ return BP_RESULT_OK;
++ }
++
++ return BP_RESULT_NORECORD;
++}
++
++/**
++ * BiosParserObject::EnumEmbeddedPanelPatchMode
++ * Get embedded panel patch mode
++ *
++ * @param index, mode index
++ * @param info, embedded panel patch mode structure
++ * @return Bios parser result code
++ */
++enum bp_result dal_bios_parser_enum_embedded_panel_patch_mode(
++ struct bios_parser *bp,
++ uint32_t index,
++ struct embedded_panel_patch_mode *mode)
++{
++ uint32_t record_size;
++ uint32_t record_index;
++ uint8_t *record;
++ ATOM_LVDS_INFO_V12 *info;
++ ATOM_PATCH_RECORD_MODE *mode_record;
++ ATOM_MASTER_LIST_OF_DATA_TABLES *list_of_tables;
++
++ if (!mode)
++ return BP_RESULT_BADINPUT;
++
++ list_of_tables = &bp->master_data_tbl->ListOfDataTables;
++ if (!list_of_tables->LVDS_Info)
++ return BP_RESULT_UNSUPPORTED;
++
++ info = GET_IMAGE(ATOM_LVDS_INFO_V12, list_of_tables->LVDS_Info);
++
++ if (!info)
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (1 != info->sHeader.ucTableFormatRevision
++ || 2 > info->sHeader.ucTableContentRevision)
++ return BP_RESULT_UNSUPPORTED;
++
++ if (!le16_to_cpu(info->usExtInfoTableOffset))
++ return BP_RESULT_UNSUPPORTED;
++
++ record = GET_IMAGE(uint8_t, list_of_tables->LVDS_Info +
++ le16_to_cpu(info->usExtInfoTableOffset));
++
++ if (!record)
++ return BP_RESULT_BADBIOSTABLE;
++
++ for (record_index = 0;;) {
++ if (ATOM_RECORD_END_TYPE == *record)
++ return BP_RESULT_NORECORD;
++
++ if (LCD_MODE_PATCH_RECORD_MODE_TYPE == *record) {
++ if (record_index == index)
++ break;
++ record_index++;
++ }
++
++ record_size = get_record_size(record);
++
++ if (!record_size)
++ return BP_RESULT_NORECORD;
++
++ record += record_size;
++ }
++
++ mode_record = (ATOM_PATCH_RECORD_MODE *) record;
++
++ mode->width = le16_to_cpu(mode_record->usHDisp);
++ mode->height = le16_to_cpu(mode_record->usVDisp);
++
++ return BP_RESULT_OK;
++}
++
++static enum bp_result get_gpio_i2c_info(struct bios_parser *bp,
++ ATOM_I2C_RECORD *record,
++ struct graphics_object_i2c_info *info)
++{
++ ATOM_GPIO_I2C_INFO *header;
++ uint32_t count = 0;
++
++ if (!info)
++ return BP_RESULT_BADINPUT;
++
++ /* get the GPIO_I2C info */
++ if (!DATA_TABLES(GPIO_I2C_Info))
++ return BP_RESULT_BADBIOSTABLE;
++
++ header = GET_IMAGE(ATOM_GPIO_I2C_INFO, DATA_TABLES(GPIO_I2C_Info));
++ if (!header)
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (sizeof(ATOM_COMMON_TABLE_HEADER) + sizeof(ATOM_GPIO_I2C_ASSIGMENT)
++ > le16_to_cpu(header->sHeader.usStructureSize))
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (1 != header->sHeader.ucTableContentRevision)
++ return BP_RESULT_UNSUPPORTED;
++
++ /* get data count */
++ count = (le16_to_cpu(header->sHeader.usStructureSize)
++ - sizeof(ATOM_COMMON_TABLE_HEADER))
++ / sizeof(ATOM_GPIO_I2C_ASSIGMENT);
++ if (count < record->sucI2cId.bfI2C_LineMux)
++ return BP_RESULT_BADBIOSTABLE;
++
++ /* get the GPIO_I2C_INFO */
++ info->i2c_hw_assist = record->sucI2cId.bfHW_Capable;
++ info->i2c_line = record->sucI2cId.bfI2C_LineMux;
++ info->i2c_engine_id = record->sucI2cId.bfHW_EngineID;
++ info->i2c_slave_address = record->ucI2CAddr;
++
++ info->gpio_info.clk_mask_register_index =
++ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkMaskRegisterIndex);
++ info->gpio_info.clk_en_register_index =
++ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkEnRegisterIndex);
++ info->gpio_info.clk_y_register_index =
++ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkY_RegisterIndex);
++ info->gpio_info.clk_a_register_index =
++ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usClkA_RegisterIndex);
++ info->gpio_info.data_mask_register_index =
++ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataMaskRegisterIndex);
++ info->gpio_info.data_en_register_index =
++ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataEnRegisterIndex);
++ info->gpio_info.data_y_register_index =
++ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataY_RegisterIndex);
++ info->gpio_info.data_a_register_index =
++ le16_to_cpu(header->asGPIO_Info[info->i2c_line].usDataA_RegisterIndex);
++
++ info->gpio_info.clk_mask_shift =
++ header->asGPIO_Info[info->i2c_line].ucClkMaskShift;
++ info->gpio_info.clk_en_shift =
++ header->asGPIO_Info[info->i2c_line].ucClkEnShift;
++ info->gpio_info.clk_y_shift =
++ header->asGPIO_Info[info->i2c_line].ucClkY_Shift;
++ info->gpio_info.clk_a_shift =
++ header->asGPIO_Info[info->i2c_line].ucClkA_Shift;
++ info->gpio_info.data_mask_shift =
++ header->asGPIO_Info[info->i2c_line].ucDataMaskShift;
++ info->gpio_info.data_en_shift =
++ header->asGPIO_Info[info->i2c_line].ucDataEnShift;
++ info->gpio_info.data_y_shift =
++ header->asGPIO_Info[info->i2c_line].ucDataY_Shift;
++ info->gpio_info.data_a_shift =
++ header->asGPIO_Info[info->i2c_line].ucDataA_Shift;
++
++ return BP_RESULT_OK;
++}
++
++static ATOM_OBJECT *get_bios_object(struct bios_parser *bp,
++ struct graphics_object_id id)
++{
++ uint32_t offset;
++ ATOM_OBJECT_TABLE *tbl;
++ uint32_t i;
++
++ switch (id.type) {
++ case OBJECT_TYPE_ENCODER:
++ offset = le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
++ break;
++
++ case OBJECT_TYPE_CONNECTOR:
++ offset = le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
++ break;
++
++ case OBJECT_TYPE_ROUTER:
++ offset = le16_to_cpu(bp->object_info_tbl.v1_1->usRouterObjectTableOffset);
++ break;
++
++ case OBJECT_TYPE_GENERIC:
++ if (bp->object_info_tbl.revision.minor < 3)
++ return NULL;
++ offset = le16_to_cpu(bp->object_info_tbl.v1_3->usMiscObjectTableOffset);
++ break;
++
++ default:
++ return NULL;
++ }
++
++ offset += bp->object_info_tbl_offset;
++
++ tbl = GET_IMAGE(ATOM_OBJECT_TABLE, offset);
++ if (!tbl)
++ return NULL;
++
++ for (i = 0; i < tbl->ucNumberOfObjects; i++)
++ if (dal_graphics_object_id_is_equal(id,
++ object_id_from_bios_object_id(
++ le16_to_cpu(tbl->asObjects[i].usObjectID))))
++ return &tbl->asObjects[i];
++
++ return NULL;
++}
++
++static uint32_t get_dest_obj_list(struct bios_parser *bp,
++ ATOM_OBJECT *object, uint16_t **id_list)
++{
++ uint32_t offset;
++ uint8_t *number;
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object id */
++ return 0;
++ }
++
++ offset = le16_to_cpu(object->usSrcDstTableOffset)
++ + bp->object_info_tbl_offset;
++
++ number = GET_IMAGE(uint8_t, offset);
++ if (!number)
++ return 0;
++
++ offset += sizeof(uint8_t);
++ offset += sizeof(uint16_t) * (*number);
++
++ number = GET_IMAGE(uint8_t, offset);
++ if ((!number) || (!*number))
++ return 0;
++
++ offset += sizeof(uint8_t);
++ *id_list = (uint16_t *)get_image(bp, offset,
++ *number * sizeof(uint16_t));
++
++ if (!*id_list)
++ return 0;
++
++ return *number;
++}
++
++static uint32_t get_src_obj_list(struct bios_parser *bp, ATOM_OBJECT *object,
++ uint16_t **id_list)
++{
++ uint32_t offset;
++ uint8_t *number;
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid object id */
++ return 0;
++ }
++
++ offset = le16_to_cpu(object->usSrcDstTableOffset)
++ + bp->object_info_tbl_offset;
++
++ number = GET_IMAGE(uint8_t, offset);
++ if (!number)
++ return 0;
++
++ offset += sizeof(uint8_t);
++ *id_list = (uint16_t *)get_image(bp, offset,
++ *number * sizeof(uint16_t));
++
++ if (!*id_list)
++ return 0;
++
++ return *number;
++}
++
++static uint32_t get_dst_number_from_object(struct bios_parser *bp,
++ ATOM_OBJECT *object)
++{
++ uint32_t offset;
++ uint8_t *number;
++
++ if (!object) {
++ BREAK_TO_DEBUGGER(); /* Invalid encoder object id*/
++ return 0;
++ }
++
++ offset = le16_to_cpu(object->usSrcDstTableOffset)
++ + bp->object_info_tbl_offset;
++
++ number = GET_IMAGE(uint8_t, offset);
++ if (!number)
++ return 0;
++
++ offset += sizeof(uint8_t);
++ offset += sizeof(uint16_t) * (*number);
++
++ number = GET_IMAGE(uint8_t, offset);
++
++ if (!number)
++ return 0;
++
++ return *number;
++}
++
++static uint8_t *get_image(struct bios_parser *bp,
++ uint32_t offset,
++ uint32_t size)
++{
++ if (bp->bios && offset + size < bp->bios_size)
++ return bp->bios + offset;
++ else
++ return NULL;
++}
++
++static uint32_t get_record_size(uint8_t *record)
++{
++ switch (*record) {
++ case LCD_MODE_PATCH_RECORD_MODE_TYPE:
++ return sizeof(ATOM_PATCH_RECORD_MODE);
++
++ case LCD_RTS_RECORD_TYPE:
++ return sizeof(ATOM_LCD_RTS_RECORD);
++
++ case LCD_CAP_RECORD_TYPE:
++ return sizeof(ATOM_LCD_MODE_CONTROL_CAP);
++
++ case LCD_FAKE_EDID_PATCH_RECORD_TYPE: {
++ ATOM_FAKE_EDID_PATCH_RECORD *fake_record =
++ (ATOM_FAKE_EDID_PATCH_RECORD *) record;
++ uint32_t edid_size = get_edid_size(fake_record);
++
++ return sizeof(ATOM_FAKE_EDID_PATCH_RECORD) + edid_size
++ - sizeof(fake_record->ucFakeEDIDString);
++ }
++
++ case LCD_PANEL_RESOLUTION_RECORD_TYPE:
++ return sizeof(ATOM_PANEL_RESOLUTION_PATCH_RECORD);
++
++ default:
++ return 0;
++ }
++}
++
++static uint32_t get_edid_size(const ATOM_FAKE_EDID_PATCH_RECORD *edid)
++{
++ uint32_t length = edid->ucFakeEDIDLength;
++
++ if (length < 128)
++ length = length * 128;
++
++ return length;
++}
++
++static struct graphics_object_id object_id_from_bios_object_id(
++ uint32_t bios_object_id)
++{
++ enum object_type type;
++ enum object_enum_id enum_id;
++ struct graphics_object_id go_id = { 0 };
++
++ type = object_type_from_bios_object_id(bios_object_id);
++
++ if (OBJECT_TYPE_UNKNOWN == type)
++ return go_id;
++
++ enum_id = enum_id_from_bios_object_id(bios_object_id);
++
++ if (ENUM_ID_UNKNOWN == enum_id)
++ return go_id;
++
++ go_id = dal_graphics_object_id_init(
++ id_from_bios_object_id(type, bios_object_id), enum_id, type);
++
++ return go_id;
++}
++
++static enum object_type object_type_from_bios_object_id(uint32_t bios_object_id)
++{
++ uint32_t bios_object_type = (bios_object_id & OBJECT_TYPE_MASK)
++ >> OBJECT_TYPE_SHIFT;
++ enum object_type object_type;
++
++ switch (bios_object_type) {
++ case GRAPH_OBJECT_TYPE_GPU:
++ object_type = OBJECT_TYPE_GPU;
++ break;
++ case GRAPH_OBJECT_TYPE_ENCODER:
++ object_type = OBJECT_TYPE_ENCODER;
++ break;
++ case GRAPH_OBJECT_TYPE_CONNECTOR:
++ object_type = OBJECT_TYPE_CONNECTOR;
++ break;
++ case GRAPH_OBJECT_TYPE_ROUTER:
++ object_type = OBJECT_TYPE_ROUTER;
++ break;
++ case GRAPH_OBJECT_TYPE_GENERIC:
++ object_type = OBJECT_TYPE_GENERIC;
++ break;
++ default:
++ object_type = OBJECT_TYPE_UNKNOWN;
++ break;
++ }
++
++ return object_type;
++}
++
++static enum object_enum_id enum_id_from_bios_object_id(uint32_t bios_object_id)
++{
++ uint32_t bios_enum_id =
++ (bios_object_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT;
++ enum object_enum_id id;
++
++ switch (bios_enum_id) {
++ case GRAPH_OBJECT_ENUM_ID1:
++ id = ENUM_ID_1;
++ break;
++ case GRAPH_OBJECT_ENUM_ID2:
++ id = ENUM_ID_2;
++ break;
++ case GRAPH_OBJECT_ENUM_ID3:
++ id = ENUM_ID_3;
++ break;
++ case GRAPH_OBJECT_ENUM_ID4:
++ id = ENUM_ID_4;
++ break;
++ case GRAPH_OBJECT_ENUM_ID5:
++ id = ENUM_ID_5;
++ break;
++ case GRAPH_OBJECT_ENUM_ID6:
++ id = ENUM_ID_6;
++ break;
++ case GRAPH_OBJECT_ENUM_ID7:
++ id = ENUM_ID_7;
++ break;
++ default:
++ id = ENUM_ID_UNKNOWN;
++ break;
++ }
++
++ return id;
++}
++
++static uint32_t id_from_bios_object_id(enum object_type type,
++ uint32_t bios_object_id)
++{
++ switch (type) {
++ case OBJECT_TYPE_GPU:
++ return gpu_id_from_bios_object_id(bios_object_id);
++ case OBJECT_TYPE_ENCODER:
++ return (uint32_t)encoder_id_from_bios_object_id(bios_object_id);
++ case OBJECT_TYPE_CONNECTOR:
++ return (uint32_t)connector_id_from_bios_object_id(
++ bios_object_id);
++ case OBJECT_TYPE_GENERIC:
++ return generic_id_from_bios_object_id(bios_object_id);
++ default:
++ return 0;
++ }
++}
++
++static enum connector_id connector_id_from_bios_object_id(
++ uint32_t bios_object_id)
++{
++ uint32_t bios_connector_id = gpu_id_from_bios_object_id(bios_object_id);
++
++ enum connector_id id;
++
++ switch (bios_connector_id) {
++ case CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_I:
++ id = CONNECTOR_ID_SINGLE_LINK_DVII;
++ break;
++ case CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_I:
++ id = CONNECTOR_ID_DUAL_LINK_DVII;
++ break;
++ case CONNECTOR_OBJECT_ID_SINGLE_LINK_DVI_D:
++ id = CONNECTOR_ID_SINGLE_LINK_DVID;
++ break;
++ case CONNECTOR_OBJECT_ID_DUAL_LINK_DVI_D:
++ id = CONNECTOR_ID_DUAL_LINK_DVID;
++ break;
++ case CONNECTOR_OBJECT_ID_VGA:
++ id = CONNECTOR_ID_VGA;
++ break;
++ case CONNECTOR_OBJECT_ID_HDMI_TYPE_A:
++ id = CONNECTOR_ID_HDMI_TYPE_A;
++ break;
++ case CONNECTOR_OBJECT_ID_LVDS:
++ id = CONNECTOR_ID_LVDS;
++ break;
++ case CONNECTOR_OBJECT_ID_PCIE_CONNECTOR:
++ id = CONNECTOR_ID_PCIE;
++ break;
++ case CONNECTOR_OBJECT_ID_HARDCODE_DVI:
++ id = CONNECTOR_ID_HARDCODE_DVI;
++ break;
++ case CONNECTOR_OBJECT_ID_DISPLAYPORT:
++ id = CONNECTOR_ID_DISPLAY_PORT;
++ break;
++ case CONNECTOR_OBJECT_ID_eDP:
++ id = CONNECTOR_ID_EDP;
++ break;
++ case CONNECTOR_OBJECT_ID_MXM:
++ id = CONNECTOR_ID_MXM;
++ break;
++ default:
++ id = CONNECTOR_ID_UNKNOWN;
++ break;
++ }
++
++ return id;
++}
++
++static enum encoder_id encoder_id_from_bios_object_id(uint32_t bios_object_id)
++{
++ uint32_t bios_encoder_id = gpu_id_from_bios_object_id(bios_object_id);
++ enum encoder_id id;
++
++ switch (bios_encoder_id) {
++ case ENCODER_OBJECT_ID_INTERNAL_LVDS:
++ id = ENCODER_ID_INTERNAL_LVDS;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_TMDS1:
++ id = ENCODER_ID_INTERNAL_TMDS1;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_TMDS2:
++ id = ENCODER_ID_INTERNAL_TMDS2;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_DAC1:
++ id = ENCODER_ID_INTERNAL_DAC1;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_DAC2:
++ id = ENCODER_ID_INTERNAL_DAC2;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_SDVOA:
++ id = ENCODER_ID_INTERNAL_SDVOA;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_SDVOB:
++ id = ENCODER_ID_INTERNAL_SDVOB;
++ break;
++ case ENCODER_OBJECT_ID_SI170B:
++ id = ENCODER_ID_EXTERNAL_SI170B;
++ break;
++ case ENCODER_OBJECT_ID_CH7303:
++ id = ENCODER_ID_EXTERNAL_CH7303;
++ break;
++ case ENCODER_OBJECT_ID_CH7301:
++ id = ENCODER_ID_EXTERNAL_CH7301;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_DVO1:
++ id = ENCODER_ID_INTERNAL_DVO1;
++ break;
++ case ENCODER_OBJECT_ID_EXTERNAL_SDVOA:
++ id = ENCODER_ID_EXTERNAL_SDVOA;
++ break;
++ case ENCODER_OBJECT_ID_EXTERNAL_SDVOB:
++ id = ENCODER_ID_EXTERNAL_SDVOB;
++ break;
++ case ENCODER_OBJECT_ID_TITFP513:
++ id = ENCODER_ID_EXTERNAL_TITFP513;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_LVTM1:
++ id = ENCODER_ID_INTERNAL_LVTM1;
++ break;
++ case ENCODER_OBJECT_ID_VT1623:
++ id = ENCODER_ID_EXTERNAL_VT1623;
++ break;
++ case ENCODER_OBJECT_ID_HDMI_SI1930:
++ id = ENCODER_ID_EXTERNAL_SI1930;
++ break;
++ case ENCODER_OBJECT_ID_HDMI_INTERNAL:
++ id = ENCODER_ID_INTERNAL_HDMI;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1:
++ id = ENCODER_ID_INTERNAL_KLDSCP_TMDS1;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1:
++ id = ENCODER_ID_INTERNAL_KLDSCP_DVO1;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1:
++ id = ENCODER_ID_INTERNAL_KLDSCP_DAC1;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2:
++ id = ENCODER_ID_INTERNAL_KLDSCP_DAC2;
++ break;
++ case ENCODER_OBJECT_ID_SI178:
++ id = ENCODER_ID_EXTERNAL_SI178;
++ break;
++ case ENCODER_OBJECT_ID_MVPU_FPGA:
++ id = ENCODER_ID_EXTERNAL_MVPU_FPGA;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_DDI:
++ id = ENCODER_ID_INTERNAL_DDI;
++ break;
++ case ENCODER_OBJECT_ID_VT1625:
++ id = ENCODER_ID_EXTERNAL_VT1625;
++ break;
++ case ENCODER_OBJECT_ID_HDMI_SI1932:
++ id = ENCODER_ID_EXTERNAL_SI1932;
++ break;
++ case ENCODER_OBJECT_ID_DP_AN9801:
++ id = ENCODER_ID_EXTERNAL_AN9801;
++ break;
++ case ENCODER_OBJECT_ID_DP_DP501:
++ id = ENCODER_ID_EXTERNAL_DP501;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY:
++ id = ENCODER_ID_INTERNAL_UNIPHY;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
++ id = ENCODER_ID_INTERNAL_KLDSCP_LVTMA;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY1:
++ id = ENCODER_ID_INTERNAL_UNIPHY1;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY2:
++ id = ENCODER_ID_INTERNAL_UNIPHY2;
++ break;
++ case ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO:
++ id = ENCODER_ID_EXTERNAL_GENERIC_DVO;
++ break;
++ case ENCODER_OBJECT_ID_ALMOND: /* ENCODER_OBJECT_ID_NUTMEG */
++ id = ENCODER_ID_EXTERNAL_NUTMEG;
++ break;
++ case ENCODER_OBJECT_ID_TRAVIS:
++ id = ENCODER_ID_EXTERNAL_TRAVIS;
++ break;
++ case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
++ id = ENCODER_ID_INTERNAL_UNIPHY3;
++ break;
++ default:
++ id = ENCODER_ID_UNKNOWN;
++ break;
++ }
++
++ return id;
++}
++
++uint32_t gpu_id_from_bios_object_id(uint32_t bios_object_id)
++{
++ return (bios_object_id & OBJECT_ID_MASK) >> OBJECT_ID_SHIFT;
++}
++
++enum generic_id generic_id_from_bios_object_id(uint32_t bios_object_id)
++{
++ uint32_t bios_generic_id = gpu_id_from_bios_object_id(bios_object_id);
++
++ enum generic_id id;
++
++ switch (bios_generic_id) {
++ case GENERIC_OBJECT_ID_MXM_OPM:
++ id = GENERIC_ID_MXM_OPM;
++ break;
++ case GENERIC_OBJECT_ID_GLSYNC:
++ id = GENERIC_ID_GLSYNC;
++ break;
++ case GENERIC_OBJECT_ID_STEREO_PIN:
++ id = GENERIC_ID_STEREO;
++ break;
++ default:
++ id = GENERIC_ID_UNKNOWN;
++ break;
++ }
++
++ return id;
++}
++
++static struct device_id device_type_from_device_id(uint16_t device_id)
++{
++
++ struct device_id result_device_id;
++
++ switch (device_id) {
++ case ATOM_DEVICE_LCD1_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_LCD;
++ result_device_id.enum_id = 1;
++ break;
++
++ case ATOM_DEVICE_LCD2_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_LCD;
++ result_device_id.enum_id = 2;
++ break;
++
++ case ATOM_DEVICE_CRT1_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_CRT;
++ result_device_id.enum_id = 1;
++ break;
++
++ case ATOM_DEVICE_CRT2_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_CRT;
++ result_device_id.enum_id = 2;
++ break;
++
++ case ATOM_DEVICE_DFP1_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_DFP;
++ result_device_id.enum_id = 1;
++ break;
++
++ case ATOM_DEVICE_DFP2_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_DFP;
++ result_device_id.enum_id = 2;
++ break;
++
++ case ATOM_DEVICE_DFP3_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_DFP;
++ result_device_id.enum_id = 3;
++ break;
++
++ case ATOM_DEVICE_DFP4_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_DFP;
++ result_device_id.enum_id = 4;
++ break;
++
++ case ATOM_DEVICE_DFP5_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_DFP;
++ result_device_id.enum_id = 5;
++ break;
++
++ case ATOM_DEVICE_DFP6_SUPPORT:
++ result_device_id.device_type = DEVICE_TYPE_DFP;
++ result_device_id.enum_id = 6;
++ break;
++
++ default:
++ BREAK_TO_DEBUGGER(); /* Invalid device Id */
++ result_device_id.device_type = DEVICE_TYPE_UNKNOWN;
++ result_device_id.enum_id = 0;
++ }
++ return result_device_id;
++}
++
++static void get_atom_data_table_revision(
++ ATOM_COMMON_TABLE_HEADER *atom_data_tbl,
++ struct atom_data_revision *tbl_revision)
++{
++ if (!tbl_revision)
++ return;
++
++ /* initialize the revision to 0 which is invalid revision */
++ tbl_revision->major = 0;
++ tbl_revision->minor = 0;
++
++ if (!atom_data_tbl)
++ return;
++
++ tbl_revision->major =
++ (uint32_t) GET_DATA_TABLE_MAJOR_REVISION(atom_data_tbl);
++ tbl_revision->minor =
++ (uint32_t) GET_DATA_TABLE_MINOR_REVISION(atom_data_tbl);
++}
++
++static uint32_t signal_to_ss_id(enum as_signal_type signal)
++{
++ uint32_t clk_id_ss = 0;
++
++ switch (signal) {
++ case AS_SIGNAL_TYPE_DVI:
++ clk_id_ss = ASIC_INTERNAL_SS_ON_TMDS;
++ break;
++ case AS_SIGNAL_TYPE_HDMI:
++ clk_id_ss = ASIC_INTERNAL_SS_ON_HDMI;
++ break;
++ case AS_SIGNAL_TYPE_LVDS:
++ clk_id_ss = ASIC_INTERNAL_SS_ON_LVDS;
++ break;
++ case AS_SIGNAL_TYPE_DISPLAY_PORT:
++ clk_id_ss = ASIC_INTERNAL_SS_ON_DP;
++ break;
++ case AS_SIGNAL_TYPE_GPU_PLL:
++ clk_id_ss = ASIC_INTERNAL_GPUPLL_SS;
++ break;
++ default:
++ break;
++ }
++ return clk_id_ss;
++}
++
++static uint32_t get_support_mask_for_device_id(struct device_id device_id)
++{
++ enum dal_device_type device_type = device_id.device_type;
++ uint32_t enum_id = device_id.enum_id;
++
++ switch (device_type) {
++ case DEVICE_TYPE_LCD:
++ switch (enum_id) {
++ case 1:
++ return ATOM_DEVICE_LCD1_SUPPORT;
++ case 2:
++ return ATOM_DEVICE_LCD2_SUPPORT;
++ default:
++ break;
++ }
++ break;
++ case DEVICE_TYPE_CRT:
++ switch (enum_id) {
++ case 1:
++ return ATOM_DEVICE_CRT1_SUPPORT;
++ case 2:
++ return ATOM_DEVICE_CRT2_SUPPORT;
++ default:
++ break;
++ }
++ break;
++ case DEVICE_TYPE_DFP:
++ switch (enum_id) {
++ case 1:
++ return ATOM_DEVICE_DFP1_SUPPORT;
++ case 2:
++ return ATOM_DEVICE_DFP2_SUPPORT;
++ case 3:
++ return ATOM_DEVICE_DFP3_SUPPORT;
++ case 4:
++ return ATOM_DEVICE_DFP4_SUPPORT;
++ case 5:
++ return ATOM_DEVICE_DFP5_SUPPORT;
++ case 6:
++ return ATOM_DEVICE_DFP6_SUPPORT;
++ default:
++ break;
++ }
++ break;
++ case DEVICE_TYPE_CV:
++ switch (enum_id) {
++ case 1:
++ return ATOM_DEVICE_CV_SUPPORT;
++ default:
++ break;
++ }
++ break;
++ case DEVICE_TYPE_TV:
++ switch (enum_id) {
++ case 1:
++ return ATOM_DEVICE_TV1_SUPPORT;
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ };
++
++ /* Unidentified device ID, return empty support mask. */
++ return 0;
++}
++
++/**
++* HwContext interface for writing MM registers
++*/
++
++static bool i2c_read(
++ struct bios_parser *bp,
++ struct graphics_object_i2c_info *i2c_info,
++ uint8_t *buffer,
++ uint32_t length)
++{
++ struct ddc *ddc;
++ uint8_t offset[2] = { 0, 0 };
++ bool result = false;
++ struct i2c_command cmd;
++
++ ddc = dal_adapter_service_obtain_ddc_from_i2c_info(bp->as, i2c_info);
++
++ if (!ddc)
++ return result;
++
++ /*Using SW engine */
++ cmd.engine = I2C_COMMAND_ENGINE_SW;
++ cmd.speed = dal_adapter_service_get_sw_i2c_speed(bp->as);
++
++ {
++ struct i2c_payload payloads[] = {
++ {
++ .address = i2c_info->i2c_slave_address >> 1,
++ .data = offset,
++ .length = sizeof(offset),
++ .write = true
++ },
++ {
++ .address = i2c_info->i2c_slave_address >> 1,
++ .data = buffer,
++ .length = length,
++ .write = false
++ }
++ };
++
++ cmd.payloads = payloads;
++ cmd.number_of_payloads = ARRAY_SIZE(payloads);
++
++ result = dal_i2caux_submit_i2c_command(
++ dal_adapter_service_get_i2caux(bp->as),
++ ddc,
++ &cmd);
++ }
++
++ dal_adapter_service_release_ddc(bp->as, ddc);
++
++ return result;
++}
++
++/**
++ * Read external display connection info table through i2c.
++ * validate the GUID and checksum.
++ *
++ * @return enum bp_result whether all data was sucessfully read
++ */
++static enum bp_result get_ext_display_connection_info(
++ struct bios_parser *bp,
++ ATOM_OBJECT *opm_object,
++ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *ext_display_connection_info_tbl)
++{
++ bool config_tbl_present = false;
++ ATOM_I2C_RECORD *i2c_record = NULL;
++ uint32_t i = 0;
++
++ if (opm_object == NULL)
++ return BP_RESULT_BADINPUT;
++
++ i2c_record = get_i2c_record(bp, opm_object);
++
++ if (i2c_record != NULL) {
++ ATOM_GPIO_I2C_INFO *gpio_i2c_header;
++ struct graphics_object_i2c_info i2c_info;
++
++ gpio_i2c_header = GET_IMAGE(ATOM_GPIO_I2C_INFO,
++ bp->master_data_tbl->ListOfDataTables.GPIO_I2C_Info);
++
++ if (NULL == gpio_i2c_header)
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (get_gpio_i2c_info(bp, i2c_record, &i2c_info) !=
++ BP_RESULT_OK)
++ return BP_RESULT_BADBIOSTABLE;
++
++ if (i2c_read(
++ bp,
++ &i2c_info,
++ (uint8_t *)ext_display_connection_info_tbl,
++ sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO))) {
++ config_tbl_present = true;
++ }
++ }
++
++ /* Validate GUID */
++ if (config_tbl_present)
++ for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; i++) {
++ if (ext_display_connection_info_tbl->ucGuid[i]
++ != ext_display_connection_guid[i]) {
++ config_tbl_present = false;
++ break;
++ }
++ }
++
++ /* Validate checksum */
++ if (config_tbl_present) {
++ uint8_t check_sum = 0;
++ uint8_t *buf =
++ (uint8_t *)ext_display_connection_info_tbl;
++
++ for (i = 0; i < sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO);
++ i++) {
++ check_sum += buf[i];
++ }
++
++ if (check_sum != 0)
++ config_tbl_present = false;
++ }
++
++ if (config_tbl_present)
++ return BP_RESULT_OK;
++ else
++ return BP_RESULT_FAILURE;
++}
++
++/*
++ * Gets the first device ID in the same group as the given ID for enumerating.
++ * For instance, if any DFP device ID is passed, returns the device ID for DFP1.
++ *
++ * The first device ID in the same group as the passed device ID, or 0 if no
++ * matching device group found.
++ */
++static uint32_t enum_first_device_id(uint32_t dev_id)
++{
++ /* Return the first in the group that this ID belongs to. */
++ if (dev_id & ATOM_DEVICE_CRT_SUPPORT)
++ return ATOM_DEVICE_CRT1_SUPPORT;
++ else if (dev_id & ATOM_DEVICE_DFP_SUPPORT)
++ return ATOM_DEVICE_DFP1_SUPPORT;
++ else if (dev_id & ATOM_DEVICE_LCD_SUPPORT)
++ return ATOM_DEVICE_LCD1_SUPPORT;
++ else if (dev_id & ATOM_DEVICE_TV_SUPPORT)
++ return ATOM_DEVICE_TV1_SUPPORT;
++ else if (dev_id & ATOM_DEVICE_CV_SUPPORT)
++ return ATOM_DEVICE_CV_SUPPORT;
++
++ /* No group found for this device ID. */
++
++ dal_error("%s: incorrect input %d\n", __func__, dev_id);
++ /* No matching support flag for given device ID */
++ return 0;
++}
++
++/*
++ * Gets the next device ID in the group for a given device ID.
++ *
++ * The current device ID being enumerated on.
++ *
++ * The next device ID in the group, or 0 if no device exists.
++ */
++static uint32_t enum_next_dev_id(uint32_t dev_id)
++{
++ /* Get next device ID in the group. */
++ switch (dev_id) {
++ case ATOM_DEVICE_CRT1_SUPPORT:
++ return ATOM_DEVICE_CRT2_SUPPORT;
++ case ATOM_DEVICE_LCD1_SUPPORT:
++ return ATOM_DEVICE_LCD2_SUPPORT;
++ case ATOM_DEVICE_DFP1_SUPPORT:
++ return ATOM_DEVICE_DFP2_SUPPORT;
++ case ATOM_DEVICE_DFP2_SUPPORT:
++ return ATOM_DEVICE_DFP3_SUPPORT;
++ case ATOM_DEVICE_DFP3_SUPPORT:
++ return ATOM_DEVICE_DFP4_SUPPORT;
++ case ATOM_DEVICE_DFP4_SUPPORT:
++ return ATOM_DEVICE_DFP5_SUPPORT;
++ case ATOM_DEVICE_DFP5_SUPPORT:
++ return ATOM_DEVICE_DFP6_SUPPORT;
++ }
++
++ /* Done enumerating through devices. */
++ return 0;
++}
++
++/*
++ * Returns the new device tag record for patched BIOS object.
++ *
++ * [IN] pExtDisplayPath - External display path to copy device tag from.
++ * [IN] deviceSupport - Bit vector for device ID support flags.
++ * [OUT] pDeviceTag - Device tag structure to fill with patched data.
++ *
++ * True if a compatible device ID was found, false otherwise.
++ */
++static bool get_patched_device_tag(
++ struct bios_parser *bp,
++ EXT_DISPLAY_PATH *ext_display_path,
++ uint32_t device_support,
++ ATOM_CONNECTOR_DEVICE_TAG *device_tag)
++{
++ uint32_t dev_id;
++ /* Use fallback behaviour if not supported. */
++ if (!bp->remap_device_tags) {
++ device_tag->ulACPIDeviceEnum =
++ cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
++ device_tag->usDeviceID =
++ cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceTag));
++ return true;
++ }
++
++ /* Find the first unused in the same group. */
++ dev_id = enum_first_device_id(le16_to_cpu(ext_display_path->usDeviceTag));
++ while (dev_id != 0) {
++ /* Assign this device ID if supported. */
++ if ((device_support & dev_id) != 0) {
++ device_tag->ulACPIDeviceEnum =
++ cpu_to_le32((uint32_t) le16_to_cpu(ext_display_path->usDeviceACPIEnum));
++ device_tag->usDeviceID = cpu_to_le16((USHORT) dev_id);
++ return true;
++ }
++
++ dev_id = enum_next_dev_id(dev_id);
++ }
++
++ /* No compatible device ID found. */
++ return false;
++}
++
++/*
++ * Adds a device tag to a BIOS object's device tag record if there is
++ * matching device ID supported.
++ *
++ * pObject - Pointer to the BIOS object to add the device tag to.
++ * pExtDisplayPath - Display path to retrieve base device ID from.
++ * pDeviceSupport - Pointer to bit vector for supported device IDs.
++ */
++static void add_device_tag_from_ext_display_path(
++ struct bios_parser *bp,
++ ATOM_OBJECT *object,
++ EXT_DISPLAY_PATH *ext_display_path,
++ uint32_t *device_support)
++{
++ /* Get device tag record for object. */
++ ATOM_CONNECTOR_DEVICE_TAG *device_tag = NULL;
++ ATOM_CONNECTOR_DEVICE_TAG_RECORD *device_tag_record = NULL;
++ enum bp_result result =
++ dal_bios_parser_get_device_tag_record(
++ bp, object, &device_tag_record);
++
++ if ((le16_to_cpu(ext_display_path->usDeviceTag) != CONNECTOR_OBJECT_ID_NONE)
++ && (result == BP_RESULT_OK)) {
++ uint8_t index;
++
++ if ((device_tag_record->ucNumberOfDevice == 1) &&
++ (le16_to_cpu(device_tag_record->asDeviceTag[0].usDeviceID) == 0)) {
++ /*Workaround bug in current VBIOS releases where
++ * ucNumberOfDevice = 1 but there is no actual device
++ * tag data. This w/a is temporary until the updated
++ * VBIOS is distributed. */
++ device_tag_record->ucNumberOfDevice =
++ device_tag_record->ucNumberOfDevice - 1;
++ }
++
++ /* Attempt to find a matching device ID. */
++ index = device_tag_record->ucNumberOfDevice;
++ device_tag = &device_tag_record->asDeviceTag[index];
++ if (get_patched_device_tag(
++ bp,
++ ext_display_path,
++ *device_support,
++ device_tag)) {
++ /* Update cached device support to remove assigned ID.
++ */
++ *device_support &= ~le16_to_cpu(device_tag->usDeviceID);
++ device_tag_record->ucNumberOfDevice++;
++ }
++ }
++}
++
++/*
++ * Read out a single EXT_DISPLAY_PATH from the external display connection info
++ * table. The specific entry in the table is determined by the enum_id passed
++ * in.
++ *
++ * EXT_DISPLAY_PATH describing a single Configuration table entry
++ */
++
++#define INVALID_CONNECTOR 0xffff
++
++static EXT_DISPLAY_PATH *get_ext_display_path_entry(
++ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO *config_table,
++ uint32_t bios_object_id)
++{
++ EXT_DISPLAY_PATH *ext_display_path;
++ uint32_t ext_display_path_index =
++ ((bios_object_id & ENUM_ID_MASK) >> ENUM_ID_SHIFT) - 1;
++
++ if (ext_display_path_index >= MAX_NUMBER_OF_EXT_DISPLAY_PATH)
++ return NULL;
++
++ ext_display_path = &config_table->sPath[ext_display_path_index];
++
++ if (le16_to_cpu(ext_display_path->usDeviceConnector) == INVALID_CONNECTOR)
++ ext_display_path->usDeviceConnector = cpu_to_le16(0);
++
++ return ext_display_path;
++}
++
++/*
++ * Get AUX/DDC information of input object id
++ *
++ * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
++ * IR
++ */
++static ATOM_CONNECTOR_AUXDDC_LUT_RECORD *get_ext_connector_aux_ddc_lut_record(
++ struct bios_parser *bp,
++ ATOM_OBJECT *object)
++{
++ uint32_t offset;
++ ATOM_COMMON_RECORD_HEADER *header;
++
++ if (!object) {
++ BREAK_TO_DEBUGGER();
++ /* Invalid object */
++ return NULL;
++ }
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!header)
++ return NULL;
++
++ if (LAST_RECORD_TYPE == header->ucRecordType ||
++ 0 == header->ucRecordSize)
++ break;
++
++ if (ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE ==
++ header->ucRecordType &&
++ sizeof(ATOM_CONNECTOR_AUXDDC_LUT_RECORD) <=
++ header->ucRecordSize)
++ return (ATOM_CONNECTOR_AUXDDC_LUT_RECORD *)(header);
++
++ offset += header->ucRecordSize;
++ }
++
++ return NULL;
++}
++
++/*
++ * Get AUX/DDC information of input object id
++ *
++ * search all records to find the ATOM_CONNECTOR_AUXDDC_LUT_RECORD_TYPE record
++ * IR
++ */
++static ATOM_CONNECTOR_HPDPIN_LUT_RECORD *get_ext_connector_hpd_pin_lut_record(
++ struct bios_parser *bp,
++ ATOM_OBJECT *object)
++{
++ uint32_t offset;
++ ATOM_COMMON_RECORD_HEADER *header;
++
++ if (!object) {
++ BREAK_TO_DEBUGGER();
++ /* Invalid object */
++ return NULL;
++ }
++
++ offset = le16_to_cpu(object->usRecordOffset)
++ + bp->object_info_tbl_offset;
++
++ for (;;) {
++ header = GET_IMAGE(ATOM_COMMON_RECORD_HEADER, offset);
++
++ if (!header)
++ return NULL;
++
++ if (LAST_RECORD_TYPE == header->ucRecordType ||
++ 0 == header->ucRecordSize)
++ break;
++
++ if (ATOM_CONNECTOR_HPDPIN_LUT_RECORD_TYPE ==
++ header->ucRecordType &&
++ sizeof(ATOM_CONNECTOR_HPDPIN_LUT_RECORD) <=
++ header->ucRecordSize)
++ return (ATOM_CONNECTOR_HPDPIN_LUT_RECORD *)header;
++
++ offset += header->ucRecordSize;
++ }
++
++ return NULL;
++}
++
++/*
++ * Check whether we need to patch the VBIOS connector info table with
++ * data from an external display connection info table. This is
++ * necessary to support MXM boards with an OPM (output personality
++ * module). With these designs, the VBIOS connector info table
++ * specifies an MXM_CONNECTOR with a unique ID. The driver retrieves
++ * the external connection info table through i2c and then looks up the
++ * connector ID to find the real connector type (e.g. DFP1).
++ *
++ */
++static enum bp_result patch_bios_image_from_ext_display_connection_info(
++ struct bios_parser *bp)
++{
++ ATOM_OBJECT_TABLE *connector_tbl;
++ uint32_t connector_tbl_offset;
++ struct graphics_object_id object_id;
++ ATOM_OBJECT *object;
++ ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO ext_display_connection_info_tbl;
++ EXT_DISPLAY_PATH *ext_display_path;
++ ATOM_CONNECTOR_AUXDDC_LUT_RECORD *aux_ddc_lut_record = NULL;
++ ATOM_I2C_RECORD *i2c_record = NULL;
++ ATOM_CONNECTOR_HPDPIN_LUT_RECORD *hpd_pin_lut_record = NULL;
++ ATOM_HPD_INT_RECORD *hpd_record = NULL;
++ ATOM_OBJECT_TABLE *encoder_table;
++ uint32_t encoder_table_offset;
++ ATOM_OBJECT *opm_object = NULL;
++ uint32_t i = 0;
++ struct graphics_object_id opm_object_id =
++ dal_graphics_object_id_init(
++ GENERIC_ID_MXM_OPM,
++ ENUM_ID_1,
++ OBJECT_TYPE_GENERIC);
++ ATOM_CONNECTOR_DEVICE_TAG_RECORD *dev_tag_record;
++ uint32_t cached_device_support =
++ le16_to_cpu(bp->object_info_tbl.v1_1->usDeviceSupport);
++
++ uint32_t dst_number;
++ uint16_t *dst_object_id_list;
++
++ opm_object = get_bios_object(bp, opm_object_id);
++ if (!opm_object)
++ return BP_RESULT_UNSUPPORTED;
++
++ dc_service_memset(&ext_display_connection_info_tbl, 0,
++ sizeof(ATOM_EXTERNAL_DISPLAY_CONNECTION_INFO));
++
++ connector_tbl_offset = bp->object_info_tbl_offset
++ + le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
++ connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
++
++ /* Read Connector info table from EEPROM through i2c */
++ if (get_ext_display_connection_info(
++ bp,
++ opm_object,
++ &ext_display_connection_info_tbl) != BP_RESULT_OK) {
++ if (bp->headless_no_opm) {
++ /* Failed to read OPM, remove all non-CF connectors. */
++ for (i = 0; i < connector_tbl->ucNumberOfObjects; ++i) {
++ object = &connector_tbl->asObjects[i];
++ object_id = object_id_from_bios_object_id(
++ le16_to_cpu(object->usObjectID));
++ if (OBJECT_TYPE_CONNECTOR == object_id.type)
++ object->usObjectID = cpu_to_le16(0);
++ }
++
++ return BP_RESULT_OK;
++ }
++
++ dal_logger_write(bp->ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_BIOS_CMD_TABLE,
++ "%s: Failed to read Connection Info Table", __func__);
++ return BP_RESULT_UNSUPPORTED;
++ }
++
++ /* Get pointer to AUX/DDC and HPD LUTs */
++ aux_ddc_lut_record =
++ get_ext_connector_aux_ddc_lut_record(bp, opm_object);
++ hpd_pin_lut_record =
++ get_ext_connector_hpd_pin_lut_record(bp, opm_object);
++
++ if ((aux_ddc_lut_record == NULL) || (hpd_pin_lut_record == NULL))
++ return BP_RESULT_UNSUPPORTED;
++
++ /* Cache support bits for currently unmapped device types. */
++ if (bp->remap_device_tags) {
++ for (i = 0; i < connector_tbl->ucNumberOfObjects; ++i) {
++ uint32_t j;
++ /* Remove support for all non-MXM connectors. */
++ object = &connector_tbl->asObjects[i];
++ object_id = object_id_from_bios_object_id(
++ le16_to_cpu(object->usObjectID));
++ if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
++ (CONNECTOR_ID_MXM == object_id.id))
++ continue;
++
++ /* Remove support for all device tags. */
++ if (dal_bios_parser_get_device_tag_record(
++ bp, object, &dev_tag_record) != BP_RESULT_OK)
++ continue;
++
++ for (j = 0; j < dev_tag_record->ucNumberOfDevice; ++j) {
++ ATOM_CONNECTOR_DEVICE_TAG *device_tag =
++ &dev_tag_record->asDeviceTag[j];
++ cached_device_support &=
++ ~le16_to_cpu(device_tag->usDeviceID);
++ }
++ }
++ }
++
++ /* Find all MXM connector objects and patch them with connector info
++ * from the external display connection info table. */
++ for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
++ uint32_t j;
++
++ object = &connector_tbl->asObjects[i];
++ object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
++ if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
++ (CONNECTOR_ID_MXM != object_id.id))
++ continue;
++
++ /* Get the correct connection info table entry based on the enum
++ * id. */
++ ext_display_path = get_ext_display_path_entry(
++ &ext_display_connection_info_tbl,
++ le16_to_cpu(object->usObjectID));
++ if (!ext_display_path)
++ return BP_RESULT_FAILURE;
++
++ /* Patch device connector ID */
++ object->usObjectID =
++ cpu_to_le16(le16_to_cpu(ext_display_path->usDeviceConnector));
++
++ /* Patch device tag, ulACPIDeviceEnum. */
++ add_device_tag_from_ext_display_path(
++ bp,
++ object,
++ ext_display_path,
++ &cached_device_support);
++
++ /* Patch HPD info */
++ if (ext_display_path->ucExtHPDPINLutIndex <
++ MAX_NUMBER_OF_EXT_HPDPIN_LUT_ENTRIES) {
++ hpd_record = get_hpd_record(bp, object);
++ if (hpd_record) {
++ uint8_t index =
++ ext_display_path->ucExtHPDPINLutIndex;
++ hpd_record->ucHPDIntGPIOID =
++ hpd_pin_lut_record->ucHPDPINMap[index];
++ } else {
++ BREAK_TO_DEBUGGER();
++ /* Invalid hpd record */
++ return BP_RESULT_FAILURE;
++ }
++ }
++
++ /* Patch I2C/AUX info */
++ if (ext_display_path->ucExtHPDPINLutIndex <
++ MAX_NUMBER_OF_EXT_AUXDDC_LUT_ENTRIES) {
++ i2c_record = get_i2c_record(bp, object);
++ if (i2c_record) {
++ uint8_t index =
++ ext_display_path->ucExtAUXDDCLutIndex;
++ i2c_record->sucI2cId =
++ aux_ddc_lut_record->ucAUXDDCMap[index];
++ } else {
++ BREAK_TO_DEBUGGER();
++ /* Invalid I2C record */
++ return BP_RESULT_FAILURE;
++ }
++ }
++
++ /* Merge with other MXM connectors that map to the same physical
++ * connector. */
++ for (j = i + 1;
++ j < connector_tbl->ucNumberOfObjects; j++) {
++ ATOM_OBJECT *next_object;
++ struct graphics_object_id next_object_id;
++ EXT_DISPLAY_PATH *next_ext_display_path;
++
++ next_object = &connector_tbl->asObjects[j];
++ next_object_id = object_id_from_bios_object_id(
++ le16_to_cpu(next_object->usObjectID));
++
++ if ((OBJECT_TYPE_CONNECTOR != next_object_id.type) &&
++ (CONNECTOR_ID_MXM == next_object_id.id))
++ continue;
++
++ next_ext_display_path = get_ext_display_path_entry(
++ &ext_display_connection_info_tbl,
++ le16_to_cpu(next_object->usObjectID));
++
++ if (next_ext_display_path == NULL)
++ return BP_RESULT_FAILURE;
++
++ /* Merge if using same connector. */
++ if ((le16_to_cpu(next_ext_display_path->usDeviceConnector) ==
++ le16_to_cpu(ext_display_path->usDeviceConnector)) &&
++ (le16_to_cpu(ext_display_path->usDeviceConnector) != 0)) {
++ /* Clear duplicate connector from table. */
++ next_object->usObjectID = cpu_to_le16(0);
++ add_device_tag_from_ext_display_path(
++ bp,
++ object,
++ ext_display_path,
++ &cached_device_support);
++ }
++ }
++ }
++
++ /* Find all encoders which have an MXM object as their destination.
++ * Replace the MXM object with the real connector Id from the external
++ * display connection info table */
++
++ encoder_table_offset = bp->object_info_tbl_offset
++ + le16_to_cpu(bp->object_info_tbl.v1_1->usEncoderObjectTableOffset);
++ encoder_table = GET_IMAGE(ATOM_OBJECT_TABLE, encoder_table_offset);
++
++ for (i = 0; i < encoder_table->ucNumberOfObjects; i++) {
++ uint32_t j;
++
++ object = &encoder_table->asObjects[i];
++
++ dst_number = get_dest_obj_list(bp, object, &dst_object_id_list);
++
++ for (j = 0; j < dst_number; j++) {
++ object_id = object_id_from_bios_object_id(
++ dst_object_id_list[j]);
++
++ if ((OBJECT_TYPE_CONNECTOR != object_id.type) ||
++ (CONNECTOR_ID_MXM != object_id.id))
++ continue;
++
++ /* Get the correct connection info table entry based on
++ * the enum id. */
++ ext_display_path =
++ get_ext_display_path_entry(
++ &ext_display_connection_info_tbl,
++ dst_object_id_list[j]);
++
++ if (ext_display_path == NULL)
++ return BP_RESULT_FAILURE;
++
++ dst_object_id_list[j] =
++ le16_to_cpu(ext_display_path->usDeviceConnector);
++ }
++ }
++
++ return BP_RESULT_OK;
++}
++
++/*
++ * Check whether we need to patch the VBIOS connector info table with
++ * data from an external display connection info table. This is
++ * necessary to support MXM boards with an OPM (output personality
++ * module). With these designs, the VBIOS connector info table
++ * specifies an MXM_CONNECTOR with a unique ID. The driver retrieves
++ * the external connection info table through i2c and then looks up the
++ * connector ID to find the real connector type (e.g. DFP1).
++ *
++ */
++
++static void process_ext_display_connection_info(struct bios_parser *bp)
++{
++ ATOM_OBJECT_TABLE *connector_tbl;
++ uint32_t connector_tbl_offset;
++ struct graphics_object_id object_id;
++ ATOM_OBJECT *object;
++ bool mxm_connector_found = false;
++ bool null_entry_found = false;
++ uint32_t i = 0;
++
++ connector_tbl_offset = bp->object_info_tbl_offset +
++ le16_to_cpu(bp->object_info_tbl.v1_1->usConnectorObjectTableOffset);
++ connector_tbl = GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
++
++ /* Look for MXM connectors to determine whether we need patch the VBIOS
++ * connector info table. Look for null entries to determine whether we
++ * need to compact connector table. */
++ for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
++ object = &connector_tbl->asObjects[i];
++ object_id = object_id_from_bios_object_id(le16_to_cpu(object->usObjectID));
++
++ if ((OBJECT_TYPE_CONNECTOR == object_id.type) &&
++ (CONNECTOR_ID_MXM == object_id.id)) {
++ /* Once we found MXM connector - we can break */
++ mxm_connector_found = true;
++ break;
++ } else if (OBJECT_TYPE_CONNECTOR != object_id.type) {
++ /* We need to continue looping - to check if MXM
++ * connector present */
++ null_entry_found = true;
++ }
++ }
++
++ /* Patch BIOS image */
++ if (mxm_connector_found || null_entry_found) {
++ uint32_t connectors_num = 0;
++ uint8_t *original_bios;
++ /* Step 1: Replace bios image with the new copy which will be
++ * patched */
++ bp->bios_local_image = dc_service_alloc(bp->ctx, bp->bios_size);
++ if (bp->bios_local_image == NULL) {
++ BREAK_TO_DEBUGGER();
++ /* Failed to alloc bp->bios_local_image */
++ return;
++ }
++
++ dc_service_memmove(bp->bios_local_image, bp->bios, bp->bios_size);
++ original_bios = bp->bios;
++ bp->bios = bp->bios_local_image;
++ connector_tbl =
++ GET_IMAGE(ATOM_OBJECT_TABLE, connector_tbl_offset);
++
++ /* Step 2: (only if MXM connector found) Patch BIOS image with
++ * info from external module */
++ if (mxm_connector_found &&
++ patch_bios_image_from_ext_display_connection_info(bp) !=
++ BP_RESULT_OK) {
++ /* Patching the bios image has failed. We will copy
++ * again original image provided and afterwards
++ * only remove null entries */
++ dc_service_memmove(
++ bp->bios_local_image,
++ original_bios,
++ bp->bios_size);
++ }
++
++ /* Step 3: Compact connector table (remove null entries, valid
++ * entries moved to beginning) */
++ for (i = 0; i < connector_tbl->ucNumberOfObjects; i++) {
++ object = &connector_tbl->asObjects[i];
++ object_id = object_id_from_bios_object_id(
++ le16_to_cpu(object->usObjectID));
++
++ if (OBJECT_TYPE_CONNECTOR != object_id.type)
++ continue;
++
++ if (i != connectors_num) {
++ dc_service_memmove(
++ &connector_tbl->
++ asObjects[connectors_num],
++ object,
++ sizeof(ATOM_OBJECT));
++ }
++ ++connectors_num;
++ }
++ connector_tbl->ucNumberOfObjects = (uint8_t)connectors_num;
++ }
++}
++
++void dal_bios_parser_post_init(struct bios_parser *bp)
++{
++ process_ext_display_connection_info(bp);
++}
++
++bool dal_bios_parser_is_accelerated_mode(
++ struct bios_parser *bp)
++{
++#ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++ return bp->bios_helper->is_accelerated_mode(
++ bp->ctx);
++#else
++ dal_logger_write(bp->ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_BIOS_CMD_TABLE,
++ "%s: VBIOS is not supported", __func__);
++ return false;
++#endif
++}
++
++/**
++* dal_bios_parser_set_scratch_connected
++*
++* @brief
++* update VBIOS scratch register about connected displays
++*
++* @param
++* bool - update scratch register or just prepare info to be updated
++* bool - connection state
++* const ConnectorDeviceTagInfo* - pointer to device type and enum ID
++*/
++void dal_bios_parser_set_scratch_connected(
++ struct bios_parser *bp,
++ struct graphics_object_id connector_id,
++ bool connected,
++ const struct connector_device_tag_info *device_tag)
++{
++#ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++ bp->bios_helper->set_scratch_connected(
++ bp->ctx,
++ connector_id, connected, device_tag);
++#else
++ dal_logger_write(bp->ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_BIOS_CMD_TABLE,
++ "%s: VBIOS is not supported", __func__);
++#endif
++}
++
++/**
++* dal_bios_parser_set_scratch_critical_state
++*
++* @brief
++* update critical state bit in VBIOS scratch register
++*
++* @param
++* bool - to set or reset state
++*/
++void dal_bios_parser_set_scratch_critical_state(
++ struct bios_parser *bp,
++ bool state)
++{
++#ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++ bp->bios_helper->set_scratch_critical_state(
++ bp->ctx, state);
++#else
++ dal_logger_write(bp->ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_BIOS_CMD_TABLE,
++ "%s: VBIOS is not supported", __func__);
++#endif
++}
++
++void dal_bios_parser_set_scratch_acc_mode_change(
++ struct bios_parser *bp)
++{
++#ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++ bp->bios_helper->set_scratch_acc_mode_change(
++ bp->ctx);
++#else
++ dal_logger_write(bp->ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_BIOS_CMD_TABLE,
++ "%s: VBIOS is not supported", __func__);
++#endif
++}
++
++/**
++* dal_bios_parser_prepare_scratch_active_and_requested
++*
++* @brief
++* update VBIOS scratch registers about active and requested displays
++*
++* @param
++* enum controller_id - controller Id
++* enum signal_type signal - signal type used on display
++* const struct connector_device_tag_info * - pointer to display type and
++* enum Id
++*/
++void dal_bios_parser_prepare_scratch_active_and_requested(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ enum signal_type signal,
++ const struct connector_device_tag_info *device_tag)
++{
++#ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++ bp->bios_helper->prepare_scratch_active_and_requested(
++ bp->ctx,
++ &bp->vbios_helper_data,
++ controller_id,
++ signal,
++ device_tag);
++#else
++ dal_logger_write(bp->ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_BIOS_CMD_TABLE,
++ "%s: VBIOS is not supported", __func__);
++#endif
++}
++
++void dal_bios_parser_set_scratch_active_and_requested(
++ struct bios_parser *bp)
++{
++#ifdef CONFIG_DRM_AMD_DAL_VBIOS_PRESENT
++ bp->bios_helper->set_scratch_active_and_requested(
++ bp->ctx,
++ &bp->vbios_helper_data);
++#else
++ dal_logger_write(bp->ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_BIOS_CMD_TABLE,
++ "%s: VBIOS is not supported", __func__);
++#endif
++}
++
++/*
++ * get_integrated_info_v8
++ *
++ * @brief
++ * Get V8 integrated BIOS information
++ *
++ * @param
++ * bios_parser *bp - [in]BIOS parser handler to get master data table
++ * integrated_info *info - [out] store and output integrated info
++ *
++ * @return
++ * enum bp_result - BP_RESULT_OK if information is available,
++ * BP_RESULT_BADBIOSTABLE otherwise.
++ */
++static enum bp_result get_integrated_info_v8(
++ struct bios_parser *bp,
++ struct integrated_info *info)
++{
++ enum bp_result result = BP_RESULT_BADBIOSTABLE;
++ ATOM_INTEGRATED_SYSTEM_INFO_V1_8 *info_v8;
++ uint32_t i;
++
++ info_v8 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_8,
++ bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
++
++ if (info_v8 != NULL) {
++ info->boot_up_engine_clock =
++ le32_to_cpu(info_v8->ulBootUpEngineClock) * 10;
++ info->dentist_vco_freq =
++ le32_to_cpu(info_v8->ulDentistVCOFreq) * 10;
++ info->boot_up_uma_clock =
++ le32_to_cpu(info_v8->ulBootUpUMAClock) * 10;
++
++ for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
++ /* Convert [10KHz] into [KHz] */
++ info->disp_clk_voltage[i].max_supported_clk =
++ le32_to_cpu(info_v8->sDISPCLK_Voltage[i].
++ ulMaximumSupportedCLK) * 10;
++ info->disp_clk_voltage[i].voltage_index =
++ le32_to_cpu(info_v8->sDISPCLK_Voltage[i].ulVoltageIndex);
++ }
++
++ info->boot_up_req_display_vector =
++ le32_to_cpu(info_v8->ulBootUpReqDisplayVector);
++ info->gpu_cap_info =
++ le32_to_cpu(info_v8->ulGPUCapInfo);
++
++ /*
++ * system_config: Bit[0] = 0 : PCIE power gating disabled
++ * = 1 : PCIE power gating enabled
++ * Bit[1] = 0 : DDR-PLL shut down disabled
++ * = 1 : DDR-PLL shut down enabled
++ * Bit[2] = 0 : DDR-PLL power down disabled
++ * = 1 : DDR-PLL power down enabled
++ */
++ info->system_config = le32_to_cpu(info_v8->ulSystemConfig);
++ info->cpu_cap_info = le32_to_cpu(info_v8->ulCPUCapInfo);
++ info->boot_up_nb_voltage =
++ le16_to_cpu(info_v8->usBootUpNBVoltage);
++ info->ext_disp_conn_info_offset =
++ le16_to_cpu(info_v8->usExtDispConnInfoOffset);
++ info->memory_type = info_v8->ucMemoryType;
++ info->ma_channel_number = info_v8->ucUMAChannelNumber;
++ info->gmc_restore_reset_time =
++ le32_to_cpu(info_v8->ulGMCRestoreResetTime);
++
++ info->minimum_n_clk =
++ le32_to_cpu(info_v8->ulNbpStateNClkFreq[0]);
++ for (i = 1; i < 4; ++i)
++ info->minimum_n_clk =
++ info->minimum_n_clk < le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]) ?
++ info->minimum_n_clk : le32_to_cpu(info_v8->ulNbpStateNClkFreq[i]);
++
++ info->idle_n_clk = le32_to_cpu(info_v8->ulIdleNClk);
++ info->ddr_dll_power_up_time =
++ le32_to_cpu(info_v8->ulDDR_DLL_PowerUpTime);
++ info->ddr_pll_power_up_time =
++ le32_to_cpu(info_v8->ulDDR_PLL_PowerUpTime);
++ info->pcie_clk_ss_type = le16_to_cpu(info_v8->usPCIEClkSSType);
++ info->lvds_ss_percentage =
++ le16_to_cpu(info_v8->usLvdsSSPercentage);
++ info->lvds_sspread_rate_in_10hz =
++ le16_to_cpu(info_v8->usLvdsSSpreadRateIn10Hz);
++ info->hdmi_ss_percentage =
++ le16_to_cpu(info_v8->usHDMISSPercentage);
++ info->hdmi_sspread_rate_in_10hz =
++ le16_to_cpu(info_v8->usHDMISSpreadRateIn10Hz);
++ info->dvi_ss_percentage =
++ le16_to_cpu(info_v8->usDVISSPercentage);
++ info->dvi_sspread_rate_in_10_hz =
++ le16_to_cpu(info_v8->usDVISSpreadRateIn10Hz);
++
++ info->max_lvds_pclk_freq_in_single_link =
++ le16_to_cpu(info_v8->usMaxLVDSPclkFreqInSingleLink);
++ info->lvds_misc = info_v8->ucLvdsMisc;
++ info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
++ info_v8->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
++ info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
++ info_v8->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
++ info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
++ info_v8->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
++ info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
++ info_v8->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
++ info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
++ info_v8->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
++ info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
++ info_v8->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
++ info->lvds_off_to_on_delay_in_4ms =
++ info_v8->ucLVDSOffToOnDelay_in4Ms;
++ info->lvds_bit_depth_control_val =
++ le32_to_cpu(info_v8->ulLCDBitDepthControlVal);
++
++ for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
++ /* Convert [10KHz] into [KHz] */
++ info->avail_s_clk[i].supported_s_clk =
++ le32_to_cpu(info_v8->sAvail_SCLK[i].ulSupportedSCLK) * 10;
++ info->avail_s_clk[i].voltage_index =
++ le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageIndex);
++ info->avail_s_clk[i].voltage_id =
++ le16_to_cpu(info_v8->sAvail_SCLK[i].usVoltageID);
++ }
++
++ for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
++ info->ext_disp_conn_info.gu_id[i] =
++ info_v8->sExtDispConnInfo.ucGuid[i];
++ }
++
++ for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
++ info->ext_disp_conn_info.path[i].device_connector_id =
++ object_id_from_bios_object_id(
++ le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceConnector));
++
++ info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
++ object_id_from_bios_object_id(
++ le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
++
++ info->ext_disp_conn_info.path[i].device_tag =
++ le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceTag);
++ info->ext_disp_conn_info.path[i].device_acpi_enum =
++ le16_to_cpu(info_v8->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
++ info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
++ info_v8->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
++ info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
++ info_v8->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
++ info->ext_disp_conn_info.path[i].channel_mapping.raw =
++ info_v8->sExtDispConnInfo.sPath[i].ucChannelMapping;
++ }
++ info->ext_disp_conn_info.checksum =
++ info_v8->sExtDispConnInfo.ucChecksum;
++
++ result = BP_RESULT_OK;
++ }
++
++ return result;
++}
++
++/*
++ * get_integrated_info_v8
++ *
++ * @brief
++ * Get V8 integrated BIOS information
++ *
++ * @param
++ * bios_parser *bp - [in]BIOS parser handler to get master data table
++ * integrated_info *info - [out] store and output integrated info
++ *
++ * @return
++ * enum bp_result - BP_RESULT_OK if information is available,
++ * BP_RESULT_BADBIOSTABLE otherwise.
++ */
++static enum bp_result get_integrated_info_v9(
++ struct bios_parser *bp,
++ struct integrated_info *info)
++{
++ enum bp_result result = BP_RESULT_BADBIOSTABLE;
++ ATOM_INTEGRATED_SYSTEM_INFO_V1_9 *info_v9;
++ uint32_t i;
++
++ info_v9 = GET_IMAGE(ATOM_INTEGRATED_SYSTEM_INFO_V1_9,
++ bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
++
++ if (info_v9 != NULL) {
++ info->boot_up_engine_clock =
++ le32_to_cpu(info_v9->ulBootUpEngineClock) * 10;
++ info->dentist_vco_freq =
++ le32_to_cpu(info_v9->ulDentistVCOFreq) * 10;
++ info->boot_up_uma_clock =
++ le32_to_cpu(info_v9->ulBootUpUMAClock) * 10;
++
++ for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
++ /* Convert [10KHz] into [KHz] */
++ info->disp_clk_voltage[i].max_supported_clk =
++ le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulMaximumSupportedCLK) * 10;
++ info->disp_clk_voltage[i].voltage_index =
++ le32_to_cpu(info_v9->sDISPCLK_Voltage[i].ulVoltageIndex);
++ }
++
++ info->boot_up_req_display_vector =
++ le32_to_cpu(info_v9->ulBootUpReqDisplayVector);
++ info->gpu_cap_info = le32_to_cpu(info_v9->ulGPUCapInfo);
++
++ /*
++ * system_config: Bit[0] = 0 : PCIE power gating disabled
++ * = 1 : PCIE power gating enabled
++ * Bit[1] = 0 : DDR-PLL shut down disabled
++ * = 1 : DDR-PLL shut down enabled
++ * Bit[2] = 0 : DDR-PLL power down disabled
++ * = 1 : DDR-PLL power down enabled
++ */
++ info->system_config = le32_to_cpu(info_v9->ulSystemConfig);
++ info->cpu_cap_info = le32_to_cpu(info_v9->ulCPUCapInfo);
++ info->boot_up_nb_voltage =
++ le16_to_cpu(info_v9->usBootUpNBVoltage);
++ info->ext_disp_conn_info_offset =
++ le16_to_cpu(info_v9->usExtDispConnInfoOffset);
++ info->memory_type = info_v9->ucMemoryType;
++ info->ma_channel_number = info_v9->ucUMAChannelNumber;
++ info->gmc_restore_reset_time =
++ le32_to_cpu(info_v9->ulGMCRestoreResetTime);
++
++ info->minimum_n_clk =
++ le32_to_cpu(info_v9->ulNbpStateNClkFreq[0]);
++ for (i = 1; i < 4; ++i)
++ info->minimum_n_clk =
++ info->minimum_n_clk < le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]) ?
++ info->minimum_n_clk : le32_to_cpu(info_v9->ulNbpStateNClkFreq[i]);
++
++ info->idle_n_clk = le32_to_cpu(info_v9->ulIdleNClk);
++ info->ddr_dll_power_up_time =
++ le32_to_cpu(info_v9->ulDDR_DLL_PowerUpTime);
++ info->ddr_pll_power_up_time =
++ le32_to_cpu(info_v9->ulDDR_PLL_PowerUpTime);
++ info->pcie_clk_ss_type = le16_to_cpu(info_v9->usPCIEClkSSType);
++ info->lvds_ss_percentage =
++ le16_to_cpu(info_v9->usLvdsSSPercentage);
++ info->lvds_sspread_rate_in_10hz =
++ le16_to_cpu(info_v9->usLvdsSSpreadRateIn10Hz);
++ info->hdmi_ss_percentage =
++ le16_to_cpu(info_v9->usHDMISSPercentage);
++ info->hdmi_sspread_rate_in_10hz =
++ le16_to_cpu(info_v9->usHDMISSpreadRateIn10Hz);
++ info->dvi_ss_percentage =
++ le16_to_cpu(info_v9->usDVISSPercentage);
++ info->dvi_sspread_rate_in_10_hz =
++ le16_to_cpu(info_v9->usDVISSpreadRateIn10Hz);
++
++ info->max_lvds_pclk_freq_in_single_link =
++ le16_to_cpu(info_v9->usMaxLVDSPclkFreqInSingleLink);
++ info->lvds_misc = info_v9->ucLvdsMisc;
++ info->lvds_pwr_on_seq_dig_on_to_de_in_4ms =
++ info_v9->ucLVDSPwrOnSeqDIGONtoDE_in4Ms;
++ info->lvds_pwr_on_seq_de_to_vary_bl_in_4ms =
++ info_v9->ucLVDSPwrOnSeqDEtoVARY_BL_in4Ms;
++ info->lvds_pwr_on_seq_vary_bl_to_blon_in_4ms =
++ info_v9->ucLVDSPwrOnSeqVARY_BLtoBLON_in4Ms;
++ info->lvds_pwr_off_seq_vary_bl_to_de_in4ms =
++ info_v9->ucLVDSPwrOffSeqVARY_BLtoDE_in4Ms;
++ info->lvds_pwr_off_seq_de_to_dig_on_in4ms =
++ info_v9->ucLVDSPwrOffSeqDEtoDIGON_in4Ms;
++ info->lvds_pwr_off_seq_blon_to_vary_bl_in_4ms =
++ info_v9->ucLVDSPwrOffSeqBLONtoVARY_BL_in4Ms;
++ info->lvds_off_to_on_delay_in_4ms =
++ info_v9->ucLVDSOffToOnDelay_in4Ms;
++ info->lvds_bit_depth_control_val =
++ le32_to_cpu(info_v9->ulLCDBitDepthControlVal);
++
++ for (i = 0; i < NUMBER_OF_AVAILABLE_SCLK; ++i) {
++ /* Convert [10KHz] into [KHz] */
++ info->avail_s_clk[i].supported_s_clk =
++ le32_to_cpu(info_v9->sAvail_SCLK[i].ulSupportedSCLK) * 10;
++ info->avail_s_clk[i].voltage_index =
++ le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageIndex);
++ info->avail_s_clk[i].voltage_id =
++ le16_to_cpu(info_v9->sAvail_SCLK[i].usVoltageID);
++ }
++
++ for (i = 0; i < NUMBER_OF_UCHAR_FOR_GUID; ++i) {
++ info->ext_disp_conn_info.gu_id[i] =
++ info_v9->sExtDispConnInfo.ucGuid[i];
++ }
++
++ for (i = 0; i < MAX_NUMBER_OF_EXT_DISPLAY_PATH; ++i) {
++ info->ext_disp_conn_info.path[i].device_connector_id =
++ object_id_from_bios_object_id(
++ le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceConnector));
++
++ info->ext_disp_conn_info.path[i].ext_encoder_obj_id =
++ object_id_from_bios_object_id(
++ le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usExtEncoderObjId));
++
++ info->ext_disp_conn_info.path[i].device_tag =
++ le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceTag);
++ info->ext_disp_conn_info.path[i].device_acpi_enum =
++ le16_to_cpu(info_v9->sExtDispConnInfo.sPath[i].usDeviceACPIEnum);
++ info->ext_disp_conn_info.path[i].ext_aux_ddc_lut_index =
++ info_v9->sExtDispConnInfo.sPath[i].ucExtAUXDDCLutIndex;
++ info->ext_disp_conn_info.path[i].ext_hpd_pin_lut_index =
++ info_v9->sExtDispConnInfo.sPath[i].ucExtHPDPINLutIndex;
++ info->ext_disp_conn_info.path[i].channel_mapping.raw =
++ info_v9->sExtDispConnInfo.sPath[i].ucChannelMapping;
++ }
++ info->ext_disp_conn_info.checksum =
++ info_v9->sExtDispConnInfo.ucChecksum;
++
++ result = BP_RESULT_OK;
++ }
++
++ return result;
++}
++
++/*
++ * construct_integrated_info
++ *
++ * @brief
++ * Get integrated BIOS information based on table revision
++ *
++ * @param
++ * bios_parser *bp - [in]BIOS parser handler to get master data table
++ * integrated_info *info - [out] store and output integrated info
++ *
++ * @return
++ * enum bp_result - BP_RESULT_OK if information is available,
++ * BP_RESULT_BADBIOSTABLE otherwise.
++ */
++static enum bp_result construct_integrated_info(
++ struct bios_parser *bp,
++ struct integrated_info *info)
++{
++ enum bp_result result = BP_RESULT_BADBIOSTABLE;
++
++ ATOM_COMMON_TABLE_HEADER *header;
++ struct atom_data_revision revision;
++
++ if (info != NULL &&
++ bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo) {
++ header = GET_IMAGE(ATOM_COMMON_TABLE_HEADER,
++ bp->master_data_tbl->ListOfDataTables.IntegratedSystemInfo);
++
++ get_atom_data_table_revision(header, &revision);
++
++ /* Don't need to check major revision as they are all 1 */
++ switch (revision.minor) {
++ case 8:
++ result = get_integrated_info_v8(bp, info);
++ break;
++ case 9:
++ result = get_integrated_info_v9(bp, info);
++ break;
++ default:
++ return result;
++
++ }
++ }
++
++ /* Sort voltage table from low to high*/
++ if (result == BP_RESULT_OK) {
++ struct clock_voltage_caps temp = {0, 0};
++ uint32_t i;
++ uint32_t j;
++
++ for (i = 1; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
++ for (j = i; j > 0; --j) {
++ if (
++ info->disp_clk_voltage[j].max_supported_clk <
++ info->disp_clk_voltage[j-1].max_supported_clk) {
++ /* swap j and j - 1*/
++ temp = info->disp_clk_voltage[j-1];
++ info->disp_clk_voltage[j-1] =
++ info->disp_clk_voltage[j];
++ info->disp_clk_voltage[j] = temp;
++ }
++ }
++ }
++
++ }
++
++ return result;
++}
++
++/*
++ * dal_bios_parser_create_integrated_info
++ *
++ * @brief
++ * Create integrated info
++ *
++ * @param
++ * bios_parser *bp - [in] BIOS parser handler
++ *
++ * @return
++ * struct integrated_info * - pointer to the newly created integrated info
++ */
++struct integrated_info *dal_bios_parser_create_integrated_info(
++ struct bios_parser *bp)
++{
++ struct integrated_info *info = NULL;
++
++ info = dc_service_alloc(bp->ctx, sizeof(struct integrated_info));
++
++ if (info == NULL) {
++ ASSERT_CRITICAL(0);
++ return NULL;
++ }
++
++ if (construct_integrated_info(bp, info) == BP_RESULT_OK)
++ return info;
++
++ dc_service_free(bp->ctx, info);
++
++ return NULL;
++}
++
++/*
++ * dal_bios_parser_destroy_integrated_info
++ *
++ * @brief
++ * Destroy provided integrated info
++ *
++ * @param
++ * struct integrated_info **info - [in] info to be destroied
++ */
++void dal_bios_parser_destroy_integrated_info(struct dc_context *ctx, struct integrated_info **info)
++{
++ if (info == NULL) {
++ ASSERT_CRITICAL(0);
++ return;
++ }
++
++ if (*info != NULL) {
++ dc_service_free(ctx, *info);
++ *info = NULL;
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser.h b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser.h
+new file mode 100644
+index 0000000..db169f1
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser.h
+@@ -0,0 +1,78 @@
++/*
++ * 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_BIOS_PARSER_H__
++#define __DAL_BIOS_PARSER_H__
++
++#include "bios_parser_helper.h"
++
++struct atom_data_revision {
++ uint32_t major;
++ uint32_t minor;
++};
++
++struct object_info_table {
++ struct atom_data_revision revision;
++ union {
++ ATOM_OBJECT_HEADER *v1_1;
++ ATOM_OBJECT_HEADER_V3 *v1_3;
++ };
++};
++
++enum spread_spectrum_id {
++ SS_ID_UNKNOWN = 0,
++ SS_ID_DP1 = 0xf1,
++ SS_ID_DP2 = 0xf2,
++ SS_ID_LVLINK_2700MHZ = 0xf3,
++ SS_ID_LVLINK_1620MHZ = 0xf4
++};
++
++struct bios_parser {
++ struct dc_context *ctx;
++ struct adapter_service *as;
++
++ struct object_info_table object_info_tbl;
++ uint32_t object_info_tbl_offset;
++ ATOM_MASTER_DATA_TABLE *master_data_tbl;
++
++ uint8_t *bios;
++ uint32_t bios_size;
++
++#if defined(CONFIG_DRM_AMD_DAL_VBIOS_PRESENT)
++ const struct bios_parser_helper *bios_helper;
++ struct vbios_helper_data vbios_helper_data;
++#endif /* CONFIG_DRM_AMD_DAL_VBIOS_PRESENT */
++
++ const struct command_table_helper *cmd_helper;
++ struct cmd_tbl cmd_tbl;
++
++ uint8_t *bios_local_image;
++ enum lcd_scale lcd_scale;
++
++ bool remap_device_tags;
++ bool headless_no_opm;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
+new file mode 100644
+index 0000000..0089800
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.c
+@@ -0,0 +1,193 @@
++/*
++ * 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 "dal_services.h"
++
++#include "atom.h"
++
++#include "include/bios_parser_types.h"
++#include "include/adapter_service_types.h"
++#include "bios_parser_helper.h"
++#include "command_table_helper.h"
++#include "command_table.h"
++#include "bios_parser.h"
++
++bool dal_bios_parser_init_bios_helper(
++ struct bios_parser *bp,
++ enum dce_version version)
++{
++ switch (version) {
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ bp->bios_helper = dal_bios_parser_helper_dce110_get_table();
++ return true;
++
++#endif
++ default:
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++}
++
++bool dal_bios_parser_is_lid_open(
++ struct bios_parser *bp)
++{
++ const struct graphics_object_id encoder = dal_graphics_object_id_init(
++ ENCODER_ID_INTERNAL_UNIPHY,
++ ENUM_ID_UNKNOWN,
++ OBJECT_TYPE_UNKNOWN);
++ const struct graphics_object_id connector = dal_graphics_object_id_init(
++ CONNECTOR_ID_LVDS,
++ ENUM_ID_UNKNOWN,
++ OBJECT_TYPE_UNKNOWN);
++
++ enum signal_type signal;
++
++ /* check if VBIOS reported LCD as connected */
++ signal = bp->bios_helper->detect_sink(bp->ctx,
++ encoder, connector, SIGNAL_TYPE_LVDS);
++
++ if (signal == SIGNAL_TYPE_NONE)
++ return false;
++
++ return bp->bios_helper->is_lid_open(bp->ctx);
++}
++
++bool dal_bios_parser_is_lid_status_changed(
++ struct bios_parser *bp)
++{
++ return bp->bios_helper->is_lid_status_changed(
++ bp->ctx);
++}
++
++bool dal_bios_parser_is_display_config_changed(
++ struct bios_parser *bp)
++{
++ return bp->bios_helper->is_display_config_changed(
++ bp->ctx);
++}
++
++/**
++* dal_bios_parser_set_scratch_lcd_scale
++*
++* @brief
++* update VBIOS scratch pad registers about LCD scale
++*
++* @param
++* bool - to set to full panel mode or aspect-ratio mode
++*/
++void dal_bios_parser_set_scratch_lcd_scale(
++ struct bios_parser *bp,
++ enum lcd_scale scale)
++{
++ bp->bios_helper->set_scratch_lcd_scale(
++ bp->ctx, scale);
++}
++
++/**
++* dal_bios_parser_get_scratch_lcd_scale
++*
++* @brief
++* get LCD Scale Mode from VBIOS scratch register
++*
++* @param
++* NONE
++*/
++enum lcd_scale dal_bios_parser_get_scratch_lcd_scale(
++ struct bios_parser *bp)
++{
++ return bp->bios_helper->get_scratch_lcd_scale(
++ bp->ctx);
++}
++
++void dal_bios_parser_get_bios_event_info(
++ struct bios_parser *bp,
++ struct bios_event_info *info)
++{
++ bp->bios_helper->get_bios_event_info(
++ bp->ctx, info);
++}
++
++/* ABM related */
++
++void dal_bios_parser_update_requested_backlight_level(
++ struct bios_parser *bp,
++ uint32_t backlight_8bit)
++{
++ bp->bios_helper->update_requested_backlight_level(
++ bp->ctx,
++ backlight_8bit);
++}
++
++uint32_t dal_bios_parser_get_requested_backlight_level(
++ struct bios_parser *bp)
++{
++ return bp->bios_helper->get_requested_backlight_level(
++ bp->ctx);
++}
++
++void dal_bios_parser_take_backlight_control(
++ struct bios_parser *bp,
++ bool cntl)
++{
++ bp->bios_helper->take_backlight_control(
++ bp->ctx, cntl);
++}
++
++/**
++ * dal_bios_parser_is_active_display
++ * Check video bios active display.
++ */
++bool dal_bios_parser_is_active_display(
++ struct bios_parser *bp,
++ enum signal_type signal,
++ const struct connector_device_tag_info *device_tag)
++{
++ return bp->bios_helper->is_active_display(
++ bp->ctx, signal, device_tag);
++}
++
++/**
++ * dal_bios_parser_get_embedded_display_controller_id
++ * Get controller ID for embedded display from scratch registers
++ */
++enum controller_id dal_bios_parser_get_embedded_display_controller_id(
++ struct bios_parser *bp)
++{
++ return bp->bios_helper->get_embedded_display_controller_id(
++ bp->ctx);
++}
++
++/**
++ * dal_bios_parser_get_embedded_display_refresh_rate
++ * Get refresh rate for embedded display from scratch registers
++ */
++uint32_t dal_bios_parser_get_embedded_display_refresh_rate(
++ struct bios_parser *bp)
++{
++ return bp->bios_helper->get_embedded_display_refresh_rate(
++ bp->ctx);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
+new file mode 100644
+index 0000000..d0e9de9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/bios_parser_helper.h
+@@ -0,0 +1,108 @@
++/*
++ * 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_BIOS_PARSER_HELPER_H__
++#define __DAL_BIOS_PARSER_HELPER_H__
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/bios_parser_helper_dce110.h"
++#endif
++
++struct bios_parser;
++
++struct vbios_helper_data {
++ uint32_t active;
++ uint32_t requested;
++};
++
++struct bios_parser_helper {
++ enum signal_type (*detect_sink)(
++ struct dc_context *ctx,
++ struct graphics_object_id encoder,
++ struct graphics_object_id connector,
++ enum signal_type signal);
++ bool (*is_lid_open)(
++ struct dc_context *ctx);
++ bool (*is_lid_status_changed)(
++ struct dc_context *ctx);
++ bool (*is_display_config_changed)(
++ struct dc_context *ctx);
++ void (*set_scratch_acc_mode_change)(
++ struct dc_context *ctx);
++ bool (*is_accelerated_mode)(
++ struct dc_context *ctx);
++ void (*set_scratch_critical_state)(
++ struct dc_context *ctx,
++ bool state);
++ void (*prepare_scratch_active_and_requested)(
++ struct dc_context *ctx,
++ struct vbios_helper_data *data,
++ enum controller_id id, enum signal_type s,
++ const struct connector_device_tag_info *dev_tag);
++ void (*set_scratch_active_and_requested)(
++ struct dc_context *ctx,
++ struct vbios_helper_data *d);
++ void (*set_scratch_connected)(
++ struct dc_context *ctx,
++ struct graphics_object_id id,
++ bool connected,
++ const struct connector_device_tag_info *device_tag);
++ void (*set_scratch_lcd_scale)(
++ struct dc_context *ctx,
++ enum lcd_scale lcd_scale_request);
++ enum lcd_scale (*get_scratch_lcd_scale)(
++ struct dc_context *ctx);
++ uint32_t (*fmt_control)(
++ struct dc_context *ctx,
++ enum controller_id id, uint32_t *value);
++ uint32_t (*fmt_bit_depth_control)(
++ struct dc_context *ctx,
++ enum controller_id id,
++ uint32_t *value);
++ void (*get_bios_event_info)(
++ struct dc_context *ctx,
++ struct bios_event_info *info);
++ void (*take_backlight_control)(
++ struct dc_context *ctx, bool control);
++ uint32_t (*get_requested_backlight_level)(
++ struct dc_context *ctx);
++ void (*update_requested_backlight_level)(
++ struct dc_context *ctx,
++ uint32_t backlight_8bit);
++ bool (*is_active_display)(
++ struct dc_context *ctx,
++ enum signal_type signal,
++ const struct connector_device_tag_info *dev_tag);
++ enum controller_id (*get_embedded_display_controller_id)(
++ struct dc_context *ctx);
++ uint32_t (*get_embedded_display_refresh_rate)(
++ struct dc_context *ctx);
++};
++
++bool dal_bios_parser_init_bios_helper(
++ struct bios_parser *bp,
++ enum dce_version ver);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table.c b/drivers/gpu/drm/amd/dal/dc/bios/command_table.c
+new file mode 100644
+index 0000000..a807ab6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table.c
+@@ -0,0 +1,2616 @@
++/*
++ * 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 "dal_services.h"
++
++#include "atom.h"
++
++#include "include/bios_parser_interface.h"
++
++#include "command_table.h"
++#include "command_table_helper.h"
++#include "bios_parser_helper.h"
++#include "bios_parser.h"
++
++#define EXEC_BIOS_CMD_TABLE(command, params)\
++ (cgs_atom_exec_cmd_table(bp->ctx->cgs_device, \
++ GetIndexIntoMasterTable(COMMAND, command), \
++ &params) == 0)
++
++#define BIOS_CMD_TABLE_REVISION(command, frev, crev)\
++ cgs_atom_get_cmd_table_revs(bp->ctx->cgs_device, \
++ GetIndexIntoMasterTable(COMMAND, command), &frev, &crev)
++
++#define BIOS_CMD_TABLE_PARA_REVISION(command)\
++ dal_bios_cmd_table_para_revision(bp->ctx, \
++ GetIndexIntoMasterTable(COMMAND, command))
++
++
++static void init_dig_encoder_control(struct bios_parser *bp);
++static void init_dvo_encoder_control(struct bios_parser *bp);
++static void init_transmitter_control(struct bios_parser *bp);
++static void init_set_pixel_clock(struct bios_parser *bp);
++static void init_enable_spread_spectrum_on_ppll(struct bios_parser *bp);
++static void init_adjust_display_pll(struct bios_parser *bp);
++static void init_dac_encoder_control(struct bios_parser *bp);
++static void init_dac_output_control(struct bios_parser *bp);
++static void init_dac_load_detection(struct bios_parser *bp);
++static void init_blank_crtc(struct bios_parser *bp);
++static void init_set_crtc_timing(struct bios_parser *bp);
++static void init_set_crtc_overscan(struct bios_parser *bp);
++static void init_select_crtc_source(struct bios_parser *bp);
++static void init_enable_crtc(struct bios_parser *bp);
++static void init_enable_crtc_mem_req(struct bios_parser *bp);
++static void init_compute_memore_engine_pll(struct bios_parser *bp);
++static void init_external_encoder_control(struct bios_parser *bp);
++static void init_enable_disp_power_gating(struct bios_parser *bp);
++static void init_program_clock(struct bios_parser *bp);
++
++void dal_bios_parser_init_cmd_tbl(struct bios_parser *bp)
++{
++ init_dig_encoder_control(bp);
++ init_dvo_encoder_control(bp);
++ init_transmitter_control(bp);
++ init_set_pixel_clock(bp);
++ init_enable_spread_spectrum_on_ppll(bp);
++ init_adjust_display_pll(bp);
++ init_dac_encoder_control(bp);
++ init_dac_output_control(bp);
++ init_dac_load_detection(bp);
++ init_blank_crtc(bp);
++ init_set_crtc_timing(bp);
++ init_set_crtc_overscan(bp);
++ init_select_crtc_source(bp);
++ init_enable_crtc(bp);
++ init_enable_crtc_mem_req(bp);
++ init_program_clock(bp);
++ init_compute_memore_engine_pll(bp);
++ init_external_encoder_control(bp);
++ init_enable_disp_power_gating(bp);
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** D I G E N C O D E R C O N T R O L
++**
++********************************************************************************
++*******************************************************************************/
++static enum bp_result encoder_control_digx_v3(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl);
++
++static enum bp_result encoder_control_digx_v4(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl);
++static void init_encoder_control_dig_v1(struct bios_parser *bp);
++
++static void init_dig_encoder_control(struct bios_parser *bp)
++{
++ uint32_t version =
++ BIOS_CMD_TABLE_PARA_REVISION(DIGxEncoderControl);
++
++ switch (version) {
++ case 4:
++ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v4;
++ break;
++ case 2:
++ bp->cmd_tbl.dig_encoder_control = encoder_control_digx_v3;
++ break;
++ default:
++ init_encoder_control_dig_v1(bp);
++ break;
++ }
++}
++
++static enum bp_result encoder_control_dig_v1(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl);
++static enum bp_result encoder_control_dig1_v1(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl);
++static enum bp_result encoder_control_dig2_v1(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl);
++
++static void init_encoder_control_dig_v1(struct bios_parser *bp)
++{
++ struct cmd_tbl *cmd_tbl = &bp->cmd_tbl;
++
++ if (1 == BIOS_CMD_TABLE_PARA_REVISION(DIG1EncoderControl))
++ cmd_tbl->encoder_control_dig1 = encoder_control_dig1_v1;
++ else
++ cmd_tbl->encoder_control_dig1 = NULL;
++
++ if (1 == BIOS_CMD_TABLE_PARA_REVISION(DIG2EncoderControl))
++ cmd_tbl->encoder_control_dig2 = encoder_control_dig2_v1;
++ else
++ cmd_tbl->encoder_control_dig2 = NULL;
++
++ cmd_tbl->dig_encoder_control = encoder_control_dig_v1;
++}
++
++static enum bp_result encoder_control_dig_v1(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ struct cmd_tbl *cmd_tbl = &bp->cmd_tbl;
++
++ if (cntl != NULL)
++ switch (cntl->engine_id) {
++ case ENGINE_ID_DIGA:
++ if (cmd_tbl->encoder_control_dig1 != NULL)
++ result =
++ cmd_tbl->encoder_control_dig1(bp, cntl);
++ break;
++ case ENGINE_ID_DIGB:
++ if (cmd_tbl->encoder_control_dig2 != NULL)
++ result =
++ cmd_tbl->encoder_control_dig2(bp, cntl);
++ break;
++
++ default:
++ break;
++ }
++
++ return result;
++}
++
++static enum bp_result encoder_control_dig1_v1(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DIG_ENCODER_CONTROL_PARAMETERS_V2 params = {0};
++
++ bp->cmd_helper->assign_control_parameter(bp->cmd_helper, cntl, &params);
++
++ if (EXEC_BIOS_CMD_TABLE(DIG1EncoderControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result encoder_control_dig2_v1(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DIG_ENCODER_CONTROL_PARAMETERS_V2 params = {0};
++
++ bp->cmd_helper->assign_control_parameter(bp->cmd_helper, cntl, &params);
++
++ if (EXEC_BIOS_CMD_TABLE(DIG2EncoderControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result encoder_control_digx_v3(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DIG_ENCODER_CONTROL_PARAMETERS_V3 params = {0};
++
++ if (LANE_COUNT_FOUR < cntl->lanes_number)
++ params.acConfig.ucDPLinkRate = 1; /* dual link 2.7GHz */
++ else
++ params.acConfig.ucDPLinkRate = 0; /* single link 1.62GHz */
++
++ params.acConfig.ucDigSel = (uint8_t)(cntl->engine_id);
++
++ /* We need to convert from KHz units into 10KHz units */
++ params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action);
++ params.usPixelClock = cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
++ params.ucEncoderMode =
++ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
++ cntl->signal,
++ cntl->enable_dp_audio);
++ params.ucLaneNum = (uint8_t)(cntl->lanes_number);
++
++ if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A)
++ switch (cntl->color_depth) {
++ case COLOR_DEPTH_101010:
++ params.usPixelClock =
++ cpu_to_le16((le32_to_cpu(params.usPixelClock) * 30) / 24);
++ break;
++ case COLOR_DEPTH_121212:
++ params.usPixelClock =
++ cpu_to_le16((le32_to_cpu(params.usPixelClock) * 36) / 24);
++ break;
++ case COLOR_DEPTH_161616:
++ params.usPixelClock =
++ cpu_to_le16((le32_to_cpu(params.usPixelClock) * 48) / 24);
++ break;
++ default:
++ break;
++ }
++
++ if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result encoder_control_digx_v4(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DIG_ENCODER_CONTROL_PARAMETERS_V4 params = {0};
++
++ if (LANE_COUNT_FOUR < cntl->lanes_number)
++ params.acConfig.ucDPLinkRate = 1; /* dual link 2.7GHz */
++ else
++ params.acConfig.ucDPLinkRate = 0; /* single link 1.62GHz */
++
++
++ params.acConfig.ucDigSel = (uint8_t)(cntl->engine_id);
++
++ /* We need to convert from KHz units into 10KHz units */
++ params.ucAction = bp->cmd_helper->encoder_action_to_atom(cntl->action);
++ params.usPixelClock = cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
++ params.ucEncoderMode =
++ (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom(
++ cntl->signal,
++ cntl->enable_dp_audio));
++ params.ucLaneNum = (uint8_t)(cntl->lanes_number);
++
++ if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A)
++ switch (cntl->color_depth) {
++ case COLOR_DEPTH_101010:
++ params.usPixelClock =
++ cpu_to_le16((le32_to_cpu(params.usPixelClock) * 30) / 24);
++ break;
++ case COLOR_DEPTH_121212:
++ params.usPixelClock =
++ cpu_to_le16((le32_to_cpu(params.usPixelClock) * 36) / 24);
++ break;
++ case COLOR_DEPTH_161616:
++ params.usPixelClock =
++ cpu_to_le16((le32_to_cpu(params.usPixelClock) * 48) / 24);
++ break;
++ default:
++ break;
++ }
++
++ if (EXEC_BIOS_CMD_TABLE(DIGxEncoderControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** DVO ENCODER CONTROL
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result dvo_encoder_control_v3(
++ struct bios_parser *bp,
++ struct bp_dvo_encoder_control *cntl);
++
++static void init_dvo_encoder_control(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(DVOEncoderControl)) {
++ case 3:
++ bp->cmd_tbl.dvo_encoder_control = dvo_encoder_control_v3;
++ break;
++ default:
++ bp->cmd_tbl.dvo_encoder_control = NULL;
++ break;
++ }
++}
++
++static enum bp_result dvo_encoder_control_v3(
++ struct bios_parser *bp,
++ struct bp_dvo_encoder_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DVO_ENCODER_CONTROL_PARAMETERS_V3 params;
++ uint8_t config = 0;
++
++ if (cntl->memory_rate == DVO_ENCODER_MEMORY_RATE_SDR)
++ config |= DVO_ENCODER_CONFIG_SDR_SPEED;
++
++ switch (cntl->interface_width) {
++ case DVO_ENCODER_INTERFACE_WIDTH_FULL24BIT:
++ config |= DVO_ENCODER_CONFIG_24BIT;
++ break;
++ case DVO_ENCODER_INTERFACE_WIDTH_HIGH12BIT:
++ config |= DVO_ENCODER_CONFIG_UPPER12BIT;
++ break;
++ default:
++ config |= DVO_ENCODER_CONFIG_LOW12BIT;
++ break;
++ }
++
++ /* We need to convert from KHz units into 10KHz units */
++ dc_service_memset(&params, 0, sizeof(params));
++ params.ucAction = (uint8_t) cntl->action;
++ params.usPixelClock = cpu_to_le16((uint16_t) (cntl->pixel_clock / 10));
++ params.ucDVOConfig = config;
++
++ if (EXEC_BIOS_CMD_TABLE(DVOEncoderControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** TRANSMITTER CONTROL
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result transmitter_control_v2(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl);
++static enum bp_result transmitter_control_v3(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl);
++static enum bp_result transmitter_control_v4(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl);
++static enum bp_result transmitter_control_v1_5(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl);
++
++static void init_transmitter_control(struct bios_parser *bp)
++{
++ uint8_t frev;
++ uint8_t crev;
++
++ if (BIOS_CMD_TABLE_REVISION(UNIPHYTransmitterControl,
++ frev, crev) != 0)
++ BREAK_TO_DEBUGGER();
++ switch (crev) {
++ case 2:
++ bp->cmd_tbl.transmitter_control = transmitter_control_v2;
++ break;
++ case 3:
++ bp->cmd_tbl.transmitter_control = transmitter_control_v3;
++ break;
++ case 4:
++ bp->cmd_tbl.transmitter_control = transmitter_control_v4;
++ break;
++ case 5:
++ bp->cmd_tbl.transmitter_control = transmitter_control_v1_5;
++ break;
++ default:
++ bp->cmd_tbl.transmitter_control = NULL;
++ break;
++ }
++}
++
++static enum bp_result transmitter_control_v2(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DIG_TRANSMITTER_CONTROL_PARAMETERS_V2 params;
++ enum connector_id connector_id =
++ dal_graphics_object_id_get_connector_id(cntl->connector_obj_id);
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ switch (cntl->transmitter) {
++ case TRANSMITTER_UNIPHY_A:
++ case TRANSMITTER_UNIPHY_B:
++ case TRANSMITTER_UNIPHY_C:
++ case TRANSMITTER_UNIPHY_D:
++ case TRANSMITTER_UNIPHY_E:
++ case TRANSMITTER_UNIPHY_F:
++ case TRANSMITTER_TRAVIS_LCD:
++ break;
++ default:
++ return BP_RESULT_BADINPUT;
++ }
++
++ switch (cntl->action) {
++ case TRANSMITTER_CONTROL_INIT:
++ if ((CONNECTOR_ID_DUAL_LINK_DVII == connector_id) ||
++ (CONNECTOR_ID_DUAL_LINK_DVID == connector_id))
++ /* on INIT this bit should be set according to the
++ * phisycal connector
++ * Bit0: dual link connector flag
++ * =0 connector is single link connector
++ * =1 connector is dual link connector
++ */
++ params.acConfig.fDualLinkConnector = 1;
++
++ /* connector object id */
++ params.usInitInfo =
++ cpu_to_le16((uint8_t)cntl->connector_obj_id.id);
++ break;
++ case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS:
++ /* votage swing and pre-emphsis */
++ params.asMode.ucLaneSel = (uint8_t)cntl->lane_select;
++ params.asMode.ucLaneSet = (uint8_t)cntl->lane_settings;
++ break;
++ default:
++ /* if dual-link */
++ if (LANE_COUNT_FOUR < cntl->lanes_number) {
++ /* on ENABLE/DISABLE this bit should be set according to
++ * actual timing (number of lanes)
++ * Bit0: dual link connector flag
++ * =0 connector is single link connector
++ * =1 connector is dual link connector
++ */
++ params.acConfig.fDualLinkConnector = 1;
++
++ /* link rate, half for dual link
++ * We need to convert from KHz units into 20KHz units
++ */
++ params.usPixelClock =
++ cpu_to_le16((uint16_t)(cntl->pixel_clock / 20));
++ } else
++ /* link rate, half for dual link
++ * We need to convert from KHz units into 10KHz units
++ */
++ params.usPixelClock =
++ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
++ break;
++ }
++
++ /* 00 - coherent mode
++ * 01 - incoherent mode
++ */
++
++ params.acConfig.fCoherentMode = cntl->coherent;
++
++ if ((TRANSMITTER_UNIPHY_B == cntl->transmitter)
++ || (TRANSMITTER_UNIPHY_D == cntl->transmitter)
++ || (TRANSMITTER_UNIPHY_F == cntl->transmitter))
++ /* Bit2: Transmitter Link selection
++ * =0 when bit0=0, single link A/C/E, when bit0=1,
++ * master link A/C/E
++ * =1 when bit0=0, single link B/D/F, when bit0=1,
++ * master link B/D/F
++ */
++ params.acConfig.ucLinkSel = 1;
++
++ if (ENGINE_ID_DIGB == cntl->engine_id)
++ /* Bit3: Transmitter data source selection
++ * =0 DIGA is data source.
++ * =1 DIGB is data source.
++ * This bit is only useful when ucAction= ATOM_ENABLE
++ */
++ params.acConfig.ucEncoderSel = 1;
++
++ if (CONNECTOR_ID_DISPLAY_PORT == connector_id)
++ /* Bit4: DP connector flag
++ * =0 connector is none-DP connector
++ * =1 connector is DP connector
++ */
++ params.acConfig.fDPConnector = 1;
++
++ /* Bit[7:6]: Transmitter selection
++ * =0 UNIPHY_ENCODER: UNIPHYA/B
++ * =1 UNIPHY1_ENCODER: UNIPHYC/D
++ * =2 UNIPHY2_ENCODER: UNIPHYE/F
++ * =3 reserved
++ */
++ params.acConfig.ucTransmitterSel =
++ (uint8_t)bp->cmd_helper->transmitter_bp_to_atom(
++ cntl->transmitter);
++
++ params.ucAction = (uint8_t)cntl->action;
++
++ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result transmitter_control_v3(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DIG_TRANSMITTER_CONTROL_PARAMETERS_V3 params;
++ uint32_t pll_id;
++ enum connector_id conn_id =
++ dal_graphics_object_id_get_connector_id(cntl->connector_obj_id);
++ const struct command_table_helper *cmd = bp->cmd_helper;
++ bool dual_link_conn = (CONNECTOR_ID_DUAL_LINK_DVII == conn_id)
++ || (CONNECTOR_ID_DUAL_LINK_DVID == conn_id);
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ switch (cntl->transmitter) {
++ case TRANSMITTER_UNIPHY_A:
++ case TRANSMITTER_UNIPHY_B:
++ case TRANSMITTER_UNIPHY_C:
++ case TRANSMITTER_UNIPHY_D:
++ case TRANSMITTER_UNIPHY_E:
++ case TRANSMITTER_UNIPHY_F:
++ case TRANSMITTER_TRAVIS_LCD:
++ break;
++ default:
++ return BP_RESULT_BADINPUT;
++ }
++
++ if (!cmd->clock_source_id_to_atom(cntl->pll_id, &pll_id))
++ return BP_RESULT_BADINPUT;
++
++ /* fill information based on the action */
++ switch (cntl->action) {
++ case TRANSMITTER_CONTROL_INIT:
++ if (dual_link_conn) {
++ /* on INIT this bit should be set according to the
++ * phisycal connector
++ * Bit0: dual link connector flag
++ * =0 connector is single link connector
++ * =1 connector is dual link connector
++ */
++ params.acConfig.fDualLinkConnector = 1;
++ }
++
++ /* connector object id */
++ params.usInitInfo =
++ cpu_to_le16((uint8_t)(cntl->connector_obj_id.id));
++ break;
++ case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS:
++ /* votage swing and pre-emphsis */
++ params.asMode.ucLaneSel = (uint8_t)cntl->lane_select;
++ params.asMode.ucLaneSet = (uint8_t)cntl->lane_settings;
++ break;
++ default:
++ if (dual_link_conn && cntl->multi_path)
++ /* on ENABLE/DISABLE this bit should be set according to
++ * actual timing (number of lanes)
++ * Bit0: dual link connector flag
++ * =0 connector is single link connector
++ * =1 connector is dual link connector
++ */
++ params.acConfig.fDualLinkConnector = 1;
++
++ /* if dual-link */
++ if (LANE_COUNT_FOUR < cntl->lanes_number) {
++ /* on ENABLE/DISABLE this bit should be set according to
++ * actual timing (number of lanes)
++ * Bit0: dual link connector flag
++ * =0 connector is single link connector
++ * =1 connector is dual link connector
++ */
++ params.acConfig.fDualLinkConnector = 1;
++
++ /* link rate, half for dual link
++ * We need to convert from KHz units into 20KHz units
++ */
++ params.usPixelClock =
++ cpu_to_le16((uint16_t)(cntl->pixel_clock / 20));
++ } else {
++ /* link rate, half for dual link
++ * We need to convert from KHz units into 10KHz units
++ */
++ params.usPixelClock =
++ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
++ if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A)
++ switch (cntl->color_depth) {
++ case COLOR_DEPTH_101010:
++ params.usPixelClock =
++ cpu_to_le16((le16_to_cpu(params.usPixelClock) * 30) / 24);
++ break;
++ case COLOR_DEPTH_121212:
++ params.usPixelClock =
++ cpu_to_le16((le16_to_cpu(params.usPixelClock) * 36) / 24);
++ break;
++ case COLOR_DEPTH_161616:
++ params.usPixelClock =
++ cpu_to_le16((le16_to_cpu(params.usPixelClock) * 48) / 24);
++ break;
++ default:
++ break;
++ }
++ }
++ break;
++ }
++
++ /* 00 - coherent mode
++ * 01 - incoherent mode
++ */
++
++ params.acConfig.fCoherentMode = cntl->coherent;
++
++ if ((TRANSMITTER_UNIPHY_B == cntl->transmitter)
++ || (TRANSMITTER_UNIPHY_D == cntl->transmitter)
++ || (TRANSMITTER_UNIPHY_F == cntl->transmitter))
++ /* Bit2: Transmitter Link selection
++ * =0 when bit0=0, single link A/C/E, when bit0=1,
++ * master link A/C/E
++ * =1 when bit0=0, single link B/D/F, when bit0=1,
++ * master link B/D/F
++ */
++ params.acConfig.ucLinkSel = 1;
++
++ if (ENGINE_ID_DIGB == cntl->engine_id)
++ /* Bit3: Transmitter data source selection
++ * =0 DIGA is data source.
++ * =1 DIGB is data source.
++ * This bit is only useful when ucAction= ATOM_ENABLE
++ */
++ params.acConfig.ucEncoderSel = 1;
++
++ /* Bit[7:6]: Transmitter selection
++ * =0 UNIPHY_ENCODER: UNIPHYA/B
++ * =1 UNIPHY1_ENCODER: UNIPHYC/D
++ * =2 UNIPHY2_ENCODER: UNIPHYE/F
++ * =3 reserved
++ */
++ params.acConfig.ucTransmitterSel =
++ (uint8_t)cmd->transmitter_bp_to_atom(cntl->transmitter);
++
++ params.ucLaneNum = (uint8_t)cntl->lanes_number;
++
++ params.acConfig.ucRefClkSource = (uint8_t)pll_id;
++
++ params.ucAction = (uint8_t)cntl->action;
++
++ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result transmitter_control_v4(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DIG_TRANSMITTER_CONTROL_PARAMETERS_V4 params;
++ uint32_t ref_clk_src_id;
++ enum connector_id conn_id =
++ dal_graphics_object_id_get_connector_id(cntl->connector_obj_id);
++ const struct command_table_helper *cmd = bp->cmd_helper;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ switch (cntl->transmitter) {
++ case TRANSMITTER_UNIPHY_A:
++ case TRANSMITTER_UNIPHY_B:
++ case TRANSMITTER_UNIPHY_C:
++ case TRANSMITTER_UNIPHY_D:
++ case TRANSMITTER_UNIPHY_E:
++ case TRANSMITTER_UNIPHY_F:
++ case TRANSMITTER_TRAVIS_LCD:
++ break;
++ default:
++ return BP_RESULT_BADINPUT;
++ }
++
++ if (!cmd->clock_source_id_to_ref_clk_src(cntl->pll_id, &ref_clk_src_id))
++ return BP_RESULT_BADINPUT;
++
++ switch (cntl->action) {
++ case TRANSMITTER_CONTROL_INIT:
++ {
++ if ((CONNECTOR_ID_DUAL_LINK_DVII == conn_id) ||
++ (CONNECTOR_ID_DUAL_LINK_DVID == conn_id))
++ /* on INIT this bit should be set according to the
++ * phisycal connector
++ * Bit0: dual link connector flag
++ * =0 connector is single link connector
++ * =1 connector is dual link connector
++ */
++ params.acConfig.fDualLinkConnector = 1;
++
++ /* connector object id */
++ params.usInitInfo =
++ cpu_to_le16((uint8_t)(cntl->connector_obj_id.id));
++ }
++ break;
++ case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS:
++ /* votage swing and pre-emphsis */
++ params.asMode.ucLaneSel = (uint8_t)(cntl->lane_select);
++ params.asMode.ucLaneSet = (uint8_t)(cntl->lane_settings);
++ break;
++ default:
++ if ((CONNECTOR_ID_DUAL_LINK_DVII == conn_id) ||
++ (CONNECTOR_ID_DUAL_LINK_DVID == conn_id))
++ /* on ENABLE/DISABLE this bit should be set according to
++ * actual timing (number of lanes)
++ * Bit0: dual link connector flag
++ * =0 connector is single link connector
++ * =1 connector is dual link connector
++ */
++ params.acConfig.fDualLinkConnector = 1;
++
++ /* if dual-link */
++ if (LANE_COUNT_FOUR < cntl->lanes_number)
++ /* link rate, half for dual link
++ * We need to convert from KHz units into 20KHz units
++ */
++ params.usPixelClock =
++ cpu_to_le16((uint16_t)(cntl->pixel_clock / 20));
++ else {
++ /* link rate, half for dual link
++ * We need to convert from KHz units into 10KHz units
++ */
++ params.usPixelClock =
++ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
++
++ if (cntl->signal == SIGNAL_TYPE_HDMI_TYPE_A)
++ switch (cntl->color_depth) {
++ case COLOR_DEPTH_101010:
++ params.usPixelClock =
++ cpu_to_le16((le16_to_cpu(params.usPixelClock) * 30) / 24);
++ break;
++ case COLOR_DEPTH_121212:
++ params.usPixelClock =
++ cpu_to_le16((le16_to_cpu(params.usPixelClock) * 36) / 24);
++ break;
++ case COLOR_DEPTH_161616:
++ params.usPixelClock =
++ cpu_to_le16((le16_to_cpu(params.usPixelClock) * 48) / 24);
++ break;
++ default:
++ break;
++ }
++ }
++ break;
++ }
++
++ /* 00 - coherent mode
++ * 01 - incoherent mode
++ */
++
++ params.acConfig.fCoherentMode = cntl->coherent;
++
++ if ((TRANSMITTER_UNIPHY_B == cntl->transmitter)
++ || (TRANSMITTER_UNIPHY_D == cntl->transmitter)
++ || (TRANSMITTER_UNIPHY_F == cntl->transmitter))
++ /* Bit2: Transmitter Link selection
++ * =0 when bit0=0, single link A/C/E, when bit0=1,
++ * master link A/C/E
++ * =1 when bit0=0, single link B/D/F, when bit0=1,
++ * master link B/D/F
++ */
++ params.acConfig.ucLinkSel = 1;
++
++ if (ENGINE_ID_DIGB == cntl->engine_id)
++ /* Bit3: Transmitter data source selection
++ * =0 DIGA is data source.
++ * =1 DIGB is data source.
++ * This bit is only useful when ucAction= ATOM_ENABLE
++ */
++ params.acConfig.ucEncoderSel = 1;
++
++ /* Bit[7:6]: Transmitter selection
++ * =0 UNIPHY_ENCODER: UNIPHYA/B
++ * =1 UNIPHY1_ENCODER: UNIPHYC/D
++ * =2 UNIPHY2_ENCODER: UNIPHYE/F
++ * =3 reserved
++ */
++ params.acConfig.ucTransmitterSel =
++ (uint8_t)(cmd->transmitter_bp_to_atom(cntl->transmitter));
++ params.ucLaneNum = (uint8_t)(cntl->lanes_number);
++ params.acConfig.ucRefClkSource = (uint8_t)(ref_clk_src_id);
++ params.ucAction = (uint8_t)(cntl->action);
++
++ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result transmitter_control_v1_5(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ const struct command_table_helper *cmd = bp->cmd_helper;
++ DIG_TRANSMITTER_CONTROL_PARAMETERS_V1_5 params;
++
++ dc_service_memset(&params, 0, sizeof(params));
++ params.ucPhyId = cmd->phy_id_to_atom(cntl->transmitter);
++ params.ucAction = (uint8_t)cntl->action;
++ params.ucLaneNum = (uint8_t)cntl->lanes_number;
++ params.ucConnObjId = (uint8_t)cntl->connector_obj_id.id;
++
++ params.ucDigMode =
++ cmd->signal_type_to_atom_dig_mode(cntl->signal);
++ params.asConfig.ucPhyClkSrcId =
++ cmd->clock_source_id_to_atom_phy_clk_src_id(cntl->pll_id);
++ /* 00 - coherent mode */
++ params.asConfig.ucCoherentMode = cntl->coherent;
++ params.asConfig.ucHPDSel =
++ cmd->hpd_sel_to_atom(cntl->hpd_sel);
++ params.ucDigEncoderSel =
++ cmd->dig_encoder_sel_to_atom(cntl->engine_id);
++ params.ucDPLaneSet = (uint8_t) cntl->lane_settings;
++ params.usSymClock = cpu_to_le16((uint16_t) (cntl->pixel_clock / 10));
++ /*
++ * In SI/TN case, caller have to set usPixelClock as following:
++ * DP mode: usPixelClock = DP_LINK_CLOCK/10
++ * (DP_LINK_CLOCK = 1.62GHz, 2.7GHz, 5.4GHz)
++ * DVI single link mode: usPixelClock = pixel clock
++ * DVI dual link mode: usPixelClock = pixel clock
++ * HDMI mode: usPixelClock = pixel clock * deep_color_ratio
++ * (=1: 8bpp, =1.25: 10bpp, =1.5:12bpp, =2: 16bpp)
++ * LVDS mode: usPixelClock = pixel clock
++ */
++ switch (cntl->signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ switch (cntl->color_depth) {
++ case COLOR_DEPTH_101010:
++ params.usSymClock =
++ cpu_to_le16((le16_to_cpu(params.usSymClock) * 30) / 24);
++ break;
++ case COLOR_DEPTH_121212:
++ params.usSymClock =
++ cpu_to_le16((le16_to_cpu(params.usSymClock) * 36) / 24);
++ break;
++ case COLOR_DEPTH_161616:
++ params.usSymClock =
++ cpu_to_le16((le16_to_cpu(params.usSymClock) * 48) / 24);
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ break;
++ }
++
++ if (EXEC_BIOS_CMD_TABLE(UNIPHYTransmitterControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** SET PIXEL CLOCK
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result set_pixel_clock_v3(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++static enum bp_result set_pixel_clock_v5(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++static enum bp_result set_pixel_clock_v6(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++
++static void init_set_pixel_clock(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(SetPixelClock)) {
++ case 3:
++ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v3;
++ break;
++ case 5:
++ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v5;
++ break;
++ case 6:
++ bp->cmd_tbl.set_pixel_clock = set_pixel_clock_v6;
++ break;
++ default:
++ bp->cmd_tbl.set_pixel_clock = NULL;
++ break;
++ }
++}
++
++static enum bp_result set_pixel_clock_v3(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ PIXEL_CLOCK_PARAMETERS_V3 *params;
++ SET_PIXEL_CLOCK_PS_ALLOCATION allocation;
++
++ dc_service_memset(&allocation, 0, sizeof(allocation));
++
++ if (CLOCK_SOURCE_ID_PLL1 == bp_params->pll_id)
++ allocation.sPCLKInput.ucPpll = ATOM_PPLL1;
++ else if (CLOCK_SOURCE_ID_PLL2 == bp_params->pll_id)
++ allocation.sPCLKInput.ucPpll = ATOM_PPLL2;
++ else
++ return BP_RESULT_BADINPUT;
++
++ allocation.sPCLKInput.usRefDiv =
++ cpu_to_le16((uint16_t)bp_params->reference_divider);
++ allocation.sPCLKInput.usFbDiv =
++ cpu_to_le16((uint16_t)bp_params->feedback_divider);
++ allocation.sPCLKInput.ucFracFbDiv =
++ (uint8_t)bp_params->fractional_feedback_divider;
++ allocation.sPCLKInput.ucPostDiv =
++ (uint8_t)bp_params->pixel_clock_post_divider;
++
++ /* We need to convert from KHz units into 10KHz units */
++ allocation.sPCLKInput.usPixelClock =
++ cpu_to_le16((uint16_t)(bp_params->target_pixel_clock / 10));
++
++ params = (PIXEL_CLOCK_PARAMETERS_V3 *)&allocation.sPCLKInput;
++ params->ucTransmitterId =
++ bp->cmd_helper->encoder_id_to_atom(
++ dal_graphics_object_id_get_encoder_id(
++ bp_params->encoder_object_id));
++ params->ucEncoderMode =
++ (uint8_t)(bp->cmd_helper->encoder_mode_bp_to_atom(
++ bp_params->signal_type, false));
++
++ if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL)
++ params->ucMiscInfo |= PIXEL_CLOCK_MISC_FORCE_PROG_PPLL;
++
++ if (bp_params->flags.USE_E_CLOCK_AS_SOURCE_FOR_D_CLOCK)
++ params->ucMiscInfo |= PIXEL_CLOCK_MISC_USE_ENGINE_FOR_DISPCLK;
++
++ if (CONTROLLER_ID_D1 != bp_params->controller_id)
++ params->ucMiscInfo |= PIXEL_CLOCK_MISC_CRTC_SEL_CRTC2;
++
++ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, allocation))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++#ifndef SET_PIXEL_CLOCK_PS_ALLOCATION_V5
++/* video bios did not define this: */
++typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION_V5 {
++ PIXEL_CLOCK_PARAMETERS_V5 sPCLKInput;
++ /* Caller doesn't need to init this portion */
++ ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;
++} SET_PIXEL_CLOCK_PS_ALLOCATION_V5;
++#endif
++
++#ifndef SET_PIXEL_CLOCK_PS_ALLOCATION_V6
++/* video bios did not define this: */
++typedef struct _SET_PIXEL_CLOCK_PS_ALLOCATION_V6 {
++ PIXEL_CLOCK_PARAMETERS_V6 sPCLKInput;
++ /* Caller doesn't need to init this portion */
++ ENABLE_SPREAD_SPECTRUM_ON_PPLL sReserved;
++} SET_PIXEL_CLOCK_PS_ALLOCATION_V6;
++#endif
++
++static enum bp_result set_pixel_clock_v5(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ SET_PIXEL_CLOCK_PS_ALLOCATION_V5 clk;
++ uint8_t controller_id;
++ uint32_t pll_id;
++
++ dc_service_memset(&clk, 0, sizeof(clk));
++
++ if (bp->cmd_helper->clock_source_id_to_atom(bp_params->pll_id, &pll_id)
++ && bp->cmd_helper->controller_id_to_atom(
++ bp_params->controller_id, &controller_id)) {
++ clk.sPCLKInput.ucCRTC = controller_id;
++ clk.sPCLKInput.ucPpll = (uint8_t)pll_id;
++ clk.sPCLKInput.ucRefDiv =
++ (uint8_t)(bp_params->reference_divider);
++ clk.sPCLKInput.usFbDiv =
++ cpu_to_le16((uint16_t)(bp_params->feedback_divider));
++ clk.sPCLKInput.ulFbDivDecFrac =
++ cpu_to_le32(bp_params->fractional_feedback_divider);
++ clk.sPCLKInput.ucPostDiv =
++ (uint8_t)(bp_params->pixel_clock_post_divider);
++ clk.sPCLKInput.ucTransmitterID =
++ bp->cmd_helper->encoder_id_to_atom(
++ dal_graphics_object_id_get_encoder_id(
++ bp_params->encoder_object_id));
++ clk.sPCLKInput.ucEncoderMode =
++ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
++ bp_params->signal_type, false);
++
++ /* We need to convert from KHz units into 10KHz units */
++ clk.sPCLKInput.usPixelClock =
++ cpu_to_le16((uint16_t)(bp_params->target_pixel_clock / 10));
++
++ if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL)
++ clk.sPCLKInput.ucMiscInfo |=
++ PIXEL_CLOCK_MISC_FORCE_PROG_PPLL;
++
++ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
++ clk.sPCLKInput.ucMiscInfo |=
++ PIXEL_CLOCK_MISC_REF_DIV_SRC;
++
++ /* clkV5.ucMiscInfo bit[3:2]= HDMI panel bit depth: =0: 24bpp
++ * =1:30bpp, =2:32bpp
++ * driver choose program it itself, i.e. here we program it
++ * to 888 by default.
++ */
++
++ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk))
++ result = BP_RESULT_OK;
++ }
++
++ return result;
++}
++
++static enum bp_result set_pixel_clock_v6(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ SET_PIXEL_CLOCK_PS_ALLOCATION_V6 clk;
++ uint8_t controller_id;
++ uint32_t pll_id;
++
++ dc_service_memset(&clk, 0, sizeof(clk));
++
++ if (bp->cmd_helper->clock_source_id_to_atom(bp_params->pll_id, &pll_id)
++ && bp->cmd_helper->controller_id_to_atom(
++ bp_params->controller_id, &controller_id)) {
++ /* Note: VBIOS still wants to use ucCRTC name which is now
++ * 1 byte in ULONG
++ *typedef struct _CRTC_PIXEL_CLOCK_FREQ
++ *{
++ * target the pixel clock to drive the CRTC timing.
++ * ULONG ulPixelClock:24;
++ * 0 means disable PPLL/DCPLL. Expanded to 24 bits comparing to
++ * previous version.
++ * ATOM_CRTC1~6, indicate the CRTC controller to
++ * ULONG ucCRTC:8;
++ * drive the pixel clock. not used for DCPLL case.
++ *}CRTC_PIXEL_CLOCK_FREQ;
++ *union
++ *{
++ * pixel clock and CRTC id frequency
++ * CRTC_PIXEL_CLOCK_FREQ ulCrtcPclkFreq;
++ * ULONG ulDispEngClkFreq; dispclk frequency
++ *};
++ */
++ clk.sPCLKInput.ulCrtcPclkFreq.ucCRTC = controller_id;
++ clk.sPCLKInput.ucPpll = (uint8_t) pll_id;
++ clk.sPCLKInput.ucRefDiv =
++ (uint8_t) bp_params->reference_divider;
++ clk.sPCLKInput.usFbDiv =
++ cpu_to_le16((uint16_t) bp_params->feedback_divider);
++ clk.sPCLKInput.ulFbDivDecFrac =
++ cpu_to_le32(bp_params->fractional_feedback_divider);
++ clk.sPCLKInput.ucPostDiv =
++ (uint8_t) bp_params->pixel_clock_post_divider;
++ clk.sPCLKInput.ucTransmitterID =
++ bp->cmd_helper->encoder_id_to_atom(
++ dal_graphics_object_id_get_encoder_id(
++ bp_params->encoder_object_id));
++ clk.sPCLKInput.ucEncoderMode =
++ (uint8_t) bp->cmd_helper->encoder_mode_bp_to_atom(
++ bp_params->signal_type, false);
++
++ /* We need to convert from KHz units into 10KHz units */
++ clk.sPCLKInput.ulCrtcPclkFreq.ulPixelClock =
++ cpu_to_le32(bp_params->target_pixel_clock / 10);
++
++ if (bp_params->flags.FORCE_PROGRAMMING_OF_PLL) {
++ clk.sPCLKInput.ucMiscInfo |=
++ PIXEL_CLOCK_V6_MISC_FORCE_PROG_PPLL;
++ }
++
++ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC) {
++ clk.sPCLKInput.ucMiscInfo |=
++ PIXEL_CLOCK_V6_MISC_REF_DIV_SRC;
++ }
++
++ /* clkV6.ucMiscInfo bit[3:2]= HDMI panel bit depth: =0:
++ * 24bpp =1:30bpp, =2:32bpp
++ * driver choose program it itself, i.e. here we pass required
++ * target rate that includes deep color.
++ */
++
++ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, clk))
++ result = BP_RESULT_OK;
++ }
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** ENABLE PIXEL CLOCK SS
++**
++********************************************************************************
++*******************************************************************************/
++static enum bp_result enable_spread_spectrum_on_ppll_v1(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable);
++static enum bp_result enable_spread_spectrum_on_ppll_v2(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable);
++static enum bp_result enable_spread_spectrum_on_ppll_v3(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable);
++
++static void init_enable_spread_spectrum_on_ppll(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(EnableSpreadSpectrumOnPPLL)) {
++ case 1:
++ bp->cmd_tbl.enable_spread_spectrum_on_ppll =
++ enable_spread_spectrum_on_ppll_v1;
++ break;
++ case 2:
++ bp->cmd_tbl.enable_spread_spectrum_on_ppll =
++ enable_spread_spectrum_on_ppll_v2;
++ break;
++ case 3:
++ bp->cmd_tbl.enable_spread_spectrum_on_ppll =
++ enable_spread_spectrum_on_ppll_v3;
++ break;
++ default:
++ bp->cmd_tbl.enable_spread_spectrum_on_ppll = NULL;
++ break;
++ }
++}
++
++static enum bp_result enable_spread_spectrum_on_ppll_v1(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ ENABLE_SPREAD_SPECTRUM_ON_PPLL params;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ if ((enable == true) && (bp_params->percentage > 0))
++ params.ucEnable = ATOM_ENABLE;
++ else
++ params.ucEnable = ATOM_DISABLE;
++
++ params.usSpreadSpectrumPercentage =
++ cpu_to_le16((uint16_t)bp_params->percentage);
++ params.ucSpreadSpectrumStep =
++ (uint8_t)bp_params->ver1.step;
++ params.ucSpreadSpectrumDelay =
++ (uint8_t)bp_params->ver1.delay;
++ /* convert back to unit of 10KHz */
++ params.ucSpreadSpectrumRange =
++ (uint8_t)(bp_params->ver1.range / 10000);
++
++ if (bp_params->flags.EXTERNAL_SS)
++ params.ucSpreadSpectrumType |= ATOM_EXTERNAL_SS_MASK;
++
++ if (bp_params->flags.CENTER_SPREAD)
++ params.ucSpreadSpectrumType |= ATOM_SS_CENTRE_SPREAD_MODE;
++
++ if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL1)
++ params.ucPpll = ATOM_PPLL1;
++ else if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL2)
++ params.ucPpll = ATOM_PPLL2;
++ else
++ BREAK_TO_DEBUGGER(); /* Unexpected PLL value!! */
++
++ if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result enable_spread_spectrum_on_ppll_v2(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ ENABLE_SPREAD_SPECTRUM_ON_PPLL_V2 params;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL1)
++ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V2_P1PLL;
++ else if (bp_params->pll_id == CLOCK_SOURCE_ID_PLL2)
++ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V2_P2PLL;
++ else
++ BREAK_TO_DEBUGGER(); /* Unexpected PLL value!! */
++
++ if ((enable == true) && (bp_params->percentage > 0)) {
++ params.ucEnable = ATOM_ENABLE;
++
++ params.usSpreadSpectrumPercentage =
++ cpu_to_le16((uint16_t)(bp_params->percentage));
++ params.usSpreadSpectrumStep =
++ cpu_to_le16((uint16_t)(bp_params->ds.ds_frac_size));
++
++ if (bp_params->flags.EXTERNAL_SS)
++ params.ucSpreadSpectrumType |=
++ ATOM_PPLL_SS_TYPE_V2_EXT_SPREAD;
++
++ if (bp_params->flags.CENTER_SPREAD)
++ params.ucSpreadSpectrumType |=
++ ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD;
++
++ /* Both amounts need to be left shifted first before bit
++ * comparison. Otherwise, the result will always be zero here
++ */
++ params.usSpreadSpectrumAmount = cpu_to_le16((uint16_t)(
++ ((bp_params->ds.feedback_amount <<
++ ATOM_PPLL_SS_AMOUNT_V2_FBDIV_SHIFT) &
++ ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK) |
++ ((bp_params->ds.nfrac_amount <<
++ ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
++ ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK)));
++ } else
++ params.ucEnable = ATOM_DISABLE;
++
++ if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result enable_spread_spectrum_on_ppll_v3(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ ENABLE_SPREAD_SPECTRUM_ON_PPLL_V3 params;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ switch (bp_params->pll_id) {
++ case CLOCK_SOURCE_ID_PLL0:
++ /* ATOM_PPLL_SS_TYPE_V3_P0PLL; this is pixel clock only,
++ * not for SI display clock.
++ */
++ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_DCPLL;
++ break;
++ case CLOCK_SOURCE_ID_PLL1:
++ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_P1PLL;
++ break;
++
++ case CLOCK_SOURCE_ID_PLL2:
++ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_P2PLL;
++ break;
++
++ case CLOCK_SOURCE_ID_DCPLL:
++ params.ucSpreadSpectrumType = ATOM_PPLL_SS_TYPE_V3_DCPLL;
++ break;
++
++ default:
++ BREAK_TO_DEBUGGER();
++ /* Unexpected PLL value!! */
++ return result;
++ }
++
++ if (enable == true) {
++ params.ucEnable = ATOM_ENABLE;
++
++ params.usSpreadSpectrumAmountFrac =
++ cpu_to_le16((uint16_t)(bp_params->ds_frac_amount));
++ params.usSpreadSpectrumStep =
++ cpu_to_le16((uint16_t)(bp_params->ds.ds_frac_size));
++
++ if (bp_params->flags.EXTERNAL_SS)
++ params.ucSpreadSpectrumType |=
++ ATOM_PPLL_SS_TYPE_V3_EXT_SPREAD;
++ if (bp_params->flags.CENTER_SPREAD)
++ params.ucSpreadSpectrumType |=
++ ATOM_PPLL_SS_TYPE_V3_CENTRE_SPREAD;
++
++ /* Both amounts need to be left shifted first before bit
++ * comparison. Otherwise, the result will always be zero here
++ */
++ params.usSpreadSpectrumAmount = cpu_to_le16((uint16_t)(
++ ((bp_params->ds.feedback_amount <<
++ ATOM_PPLL_SS_AMOUNT_V3_FBDIV_SHIFT) &
++ ATOM_PPLL_SS_AMOUNT_V3_FBDIV_MASK) |
++ ((bp_params->ds.nfrac_amount <<
++ ATOM_PPLL_SS_AMOUNT_V3_NFRAC_SHIFT) &
++ ATOM_PPLL_SS_AMOUNT_V3_NFRAC_MASK)));
++ } else
++ params.ucEnable = ATOM_DISABLE;
++
++ if (EXEC_BIOS_CMD_TABLE(EnableSpreadSpectrumOnPPLL, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** ADJUST DISPLAY PLL
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result adjust_display_pll_v2(
++ struct bios_parser *bp,
++ struct bp_adjust_pixel_clock_parameters *bp_params);
++static enum bp_result adjust_display_pll_v3(
++ struct bios_parser *bp,
++ struct bp_adjust_pixel_clock_parameters *bp_params);
++
++static void init_adjust_display_pll(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(AdjustDisplayPll)) {
++ case 2:
++ bp->cmd_tbl.adjust_display_pll = adjust_display_pll_v2;
++ break;
++ case 3:
++ bp->cmd_tbl.adjust_display_pll = adjust_display_pll_v3;
++ break;
++ default:
++ bp->cmd_tbl.adjust_display_pll = NULL;
++ break;
++ }
++}
++
++static bool adjust_display_pll_bug_patch(ADJUST_DISPLAY_PLL_PARAMETERS *params)
++{
++ /* vbios bug: pixel clock should not be doubled for DVO with 24bit
++ * interface */
++ if ((params->ucTransmitterID == ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1)
++ && (params->ucDVOConfig == DVO_ENCODER_CONFIG_24BIT))
++ /* the current pixel clock is good. no adjustment is required */
++ return true;
++ return false;
++}
++
++static enum bp_result adjust_display_pll_v2(
++ struct bios_parser *bp,
++ struct bp_adjust_pixel_clock_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ ADJUST_DISPLAY_PLL_PS_ALLOCATION params = { 0 };
++
++ /* We need to convert from KHz units into 10KHz units and then convert
++ * output pixel clock back 10KHz-->KHz */
++ uint32_t pixel_clock_10KHz_in = bp_params->pixel_clock / 10;
++
++ params.usPixelClock = cpu_to_le16((uint16_t)(pixel_clock_10KHz_in));
++ params.ucTransmitterID =
++ bp->cmd_helper->encoder_id_to_atom(
++ dal_graphics_object_id_get_encoder_id(
++ bp_params->encoder_object_id));
++ params.ucEncodeMode =
++ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
++ bp_params->signal_type, false);
++ params.ucDVOConfig = (uint8_t)(bp_params->dvo_config);
++
++ if (adjust_display_pll_bug_patch(&params)
++ || EXEC_BIOS_CMD_TABLE(AdjustDisplayPll, params)) {
++ /* Convert output pixel clock back 10KHz-->KHz: multiply
++ * original pixel clock in KHz by ratio
++ * [output pxlClk/input pxlClk] */
++ uint64_t pixel_clock_10KHz_out =
++ le16_to_cpu((uint64_t)params.usPixelClock);
++ uint64_t pixel_clock = (uint64_t)bp_params->pixel_clock;
++
++ bp_params->adjusted_pixel_clock =
++ div_u64(pixel_clock * pixel_clock_10KHz_out,
++ pixel_clock_10KHz_in);
++ result = BP_RESULT_OK;
++ }
++
++ return result;
++}
++
++static enum bp_result adjust_display_pll_v3(
++ struct bios_parser *bp,
++ struct bp_adjust_pixel_clock_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ ADJUST_DISPLAY_PLL_PS_ALLOCATION_V3 params;
++ uint32_t pixel_clk_10_kHz_in = bp_params->pixel_clock / 10;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ /* We need to convert from KHz units into 10KHz units and then convert
++ * output pixel clock back 10KHz-->KHz */
++ params.sInput.usPixelClock = cpu_to_le16((uint16_t)pixel_clk_10_kHz_in);
++ params.sInput.ucTransmitterID =
++ bp->cmd_helper->encoder_id_to_atom(
++ dal_graphics_object_id_get_encoder_id(
++ bp_params->encoder_object_id));
++ params.sInput.ucEncodeMode =
++ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
++ bp_params->signal_type, false);
++
++ if (DISP_PLL_CONFIG_DVO_DDR_MODE_LOW_12BIT ==
++ bp_params->display_pll_config)
++ params.sInput.ucDispPllConfig =
++ DISPPLL_CONFIG_DVO_DDR_SPEED |
++ DISPPLL_CONFIG_DVO_LOW12BIT;
++ else if (DISP_PLL_CONFIG_DVO_DDR_MODE_UPPER_12BIT ==
++ bp_params->display_pll_config)
++ params.sInput.ucDispPllConfig =
++ DISPPLL_CONFIG_DVO_DDR_SPEED |
++ DISPPLL_CONFIG_DVO_UPPER12BIT;
++ else if (DISP_PLL_CONFIG_DVO_DDR_MODE_24BIT ==
++ bp_params->display_pll_config)
++ params.sInput.ucDispPllConfig =
++ DISPPLL_CONFIG_DVO_DDR_SPEED | DISPPLL_CONFIG_DVO_24BIT;
++ else
++ /* this does not mean anything here */
++ params.sInput.ucDispPllConfig =
++ (uint8_t)(bp_params->display_pll_config);
++
++ if (bp_params->ss_enable == true)
++ params.sInput.ucDispPllConfig |= DISPPLL_CONFIG_SS_ENABLE;
++
++ if (bp_params->signal_type == SIGNAL_TYPE_DVI_DUAL_LINK)
++ params.sInput.ucDispPllConfig |= DISPPLL_CONFIG_DUAL_LINK;
++
++ if (EXEC_BIOS_CMD_TABLE(AdjustDisplayPll, params)) {
++ /* Convert output pixel clock back 10KHz-->KHz: multiply
++ * original pixel clock in KHz by ratio
++ * [output pxlClk/input pxlClk] */
++ uint64_t pixel_clk_10_khz_out =
++ (uint64_t)le32_to_cpu(params.sOutput.ulDispPllFreq);
++ uint64_t pixel_clk = (uint64_t)bp_params->pixel_clock;
++
++ if (pixel_clk_10_kHz_in != 0) {
++ bp_params->adjusted_pixel_clock =
++ div_u64(pixel_clk * pixel_clk_10_khz_out,
++ pixel_clk_10_kHz_in);
++ } else {
++ bp_params->adjusted_pixel_clock = 0;
++ BREAK_TO_DEBUGGER();
++ }
++
++ bp_params->reference_divider = params.sOutput.ucRefDiv;
++ bp_params->pixel_clock_post_divider = params.sOutput.ucPostDiv;
++
++ result = BP_RESULT_OK;
++ }
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** DAC ENCODER CONTROL
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result dac1_encoder_control_v1(
++ struct bios_parser *bp,
++ bool enable,
++ uint32_t pixel_clock,
++ uint8_t dac_standard);
++static enum bp_result dac2_encoder_control_v1(
++ struct bios_parser *bp,
++ bool enable,
++ uint32_t pixel_clock,
++ uint8_t dac_standard);
++
++static void init_dac_encoder_control(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC1EncoderControl)) {
++ case 1:
++ bp->cmd_tbl.dac1_encoder_control = dac1_encoder_control_v1;
++ break;
++ default:
++ bp->cmd_tbl.dac1_encoder_control = NULL;
++ break;
++ }
++ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC2EncoderControl)) {
++ case 1:
++ bp->cmd_tbl.dac2_encoder_control = dac2_encoder_control_v1;
++ break;
++ default:
++ bp->cmd_tbl.dac2_encoder_control = NULL;
++ break;
++ }
++}
++
++static void dac_encoder_control_prepare_params(
++ DAC_ENCODER_CONTROL_PS_ALLOCATION *params,
++ bool enable,
++ uint32_t pixel_clock,
++ uint8_t dac_standard)
++{
++ params->ucDacStandard = dac_standard;
++ if (enable)
++ params->ucAction = ATOM_ENABLE;
++ else
++ params->ucAction = ATOM_DISABLE;
++
++ /* We need to convert from KHz units into 10KHz units
++ * it looks as if the TvControl do not care about pixel clock
++ */
++ params->usPixelClock = cpu_to_le16((uint16_t)(pixel_clock / 10));
++}
++
++static enum bp_result dac1_encoder_control_v1(
++ struct bios_parser *bp,
++ bool enable,
++ uint32_t pixel_clock,
++ uint8_t dac_standard)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DAC_ENCODER_CONTROL_PS_ALLOCATION params;
++
++ dac_encoder_control_prepare_params(
++ &params,
++ enable,
++ pixel_clock,
++ dac_standard);
++
++ if (EXEC_BIOS_CMD_TABLE(DAC1EncoderControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result dac2_encoder_control_v1(
++ struct bios_parser *bp,
++ bool enable,
++ uint32_t pixel_clock,
++ uint8_t dac_standard)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DAC_ENCODER_CONTROL_PS_ALLOCATION params;
++
++ dac_encoder_control_prepare_params(
++ &params,
++ enable,
++ pixel_clock,
++ dac_standard);
++
++ if (EXEC_BIOS_CMD_TABLE(DAC2EncoderControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** DAC OUTPUT CONTROL
++**
++********************************************************************************
++*******************************************************************************/
++static enum bp_result dac1_output_control_v1(
++ struct bios_parser *bp,
++ bool enable);
++static enum bp_result dac2_output_control_v1(
++ struct bios_parser *bp,
++ bool enable);
++
++static void init_dac_output_control(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC1OutputControl)) {
++ case 1:
++ bp->cmd_tbl.dac1_output_control = dac1_output_control_v1;
++ break;
++ default:
++ bp->cmd_tbl.dac1_output_control = NULL;
++ break;
++ }
++ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC2OutputControl)) {
++ case 1:
++ bp->cmd_tbl.dac2_output_control = dac2_output_control_v1;
++ break;
++ default:
++ bp->cmd_tbl.dac2_output_control = NULL;
++ break;
++ }
++}
++
++static enum bp_result dac1_output_control_v1(
++ struct bios_parser *bp, bool enable)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION params;
++
++ if (enable)
++ params.ucAction = ATOM_ENABLE;
++ else
++ params.ucAction = ATOM_DISABLE;
++
++ if (EXEC_BIOS_CMD_TABLE(DAC1OutputControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result dac2_output_control_v1(
++ struct bios_parser *bp, bool enable)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ DISPLAY_DEVICE_OUTPUT_CONTROL_PS_ALLOCATION params;
++
++ if (enable)
++ params.ucAction = ATOM_ENABLE;
++ else
++ params.ucAction = ATOM_DISABLE;
++
++ if (EXEC_BIOS_CMD_TABLE(DAC2OutputControl, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** DAC LOAD DETECTION
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum signal_type dac_load_detection_v3(
++ struct bios_parser *bp,
++ struct graphics_object_id encoder,
++ struct graphics_object_id connector,
++ enum signal_type display_signal);
++
++static void init_dac_load_detection(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(DAC_LoadDetection)) {
++ case 3:
++ bp->cmd_tbl.dac_load_detection = dac_load_detection_v3;
++ break;
++ default:
++ bp->cmd_tbl.dac_load_detection = NULL;
++ break;
++ }
++}
++
++static enum signal_type dac_load_detection_v3(
++ struct bios_parser *bp,
++ struct graphics_object_id encoder,
++ struct graphics_object_id connector,
++ enum signal_type display_signal)
++{
++ DAC_LOAD_DETECTION_PS_ALLOCATION params;
++ enum signal_type signal = SIGNAL_TYPE_NONE;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ /* load detection is cupported for CRT, TV and CV */
++ switch (display_signal) {
++ case SIGNAL_TYPE_RGB:
++ switch (dal_graphics_object_id_get_encoder_id(encoder)) {
++ case ENCODER_ID_INTERNAL_DAC1:
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
++ params.sDacload.usDeviceID =
++ cpu_to_le16(ATOM_DEVICE_CRT1_SUPPORT);
++ break;
++ case ENCODER_ID_INTERNAL_DAC2:
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
++ params.sDacload.usDeviceID =
++ cpu_to_le16(ATOM_DEVICE_CRT2_SUPPORT);
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ return signal;
++ }
++
++ /* set the encoder to detect on */
++ switch (dal_graphics_object_id_get_encoder_id(encoder)) {
++ case ENCODER_ID_INTERNAL_DAC1:
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
++ params.sDacload.ucDacType = ATOM_DAC_A;
++ break;
++ case ENCODER_ID_INTERNAL_DAC2:
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
++ params.sDacload.ucDacType = ATOM_DAC_B;
++ break;
++ case ENCODER_ID_EXTERNAL_CH7303:
++ params.sDacload.ucDacType = ATOM_EXT_DAC;
++ break;
++ default:
++ return signal;
++ }
++
++ if (!EXEC_BIOS_CMD_TABLE(DAC_LoadDetection, params))
++ return signal;
++#if defined(CONFIG_DRM_AMD_DAL_VBIOS_PRESENT)
++ signal = bp->bios_helper->detect_sink(
++ bp->ctx,
++ encoder,
++ connector,
++ display_signal);
++#else
++ BREAK_TO_DEBUGGER(); /* VBios is needed */
++#endif
++
++ return signal;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** BLANK CRTC
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result blank_crtc_v1(
++ struct bios_parser *bp,
++ struct bp_blank_crtc_parameters *bp_params,
++ bool blank);
++
++static void init_blank_crtc(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(BlankCRTC)) {
++ case 1:
++ bp->cmd_tbl.blank_crtc = blank_crtc_v1;
++ break;
++ default:
++ bp->cmd_tbl.blank_crtc = NULL;
++ break;
++ }
++}
++
++static enum bp_result blank_crtc_v1(
++ struct bios_parser *bp,
++ struct bp_blank_crtc_parameters *bp_params,
++ bool blank)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ BLANK_CRTC_PARAMETERS params = {0};
++ uint8_t atom_controller_id;
++
++ if (bp->cmd_helper->controller_id_to_atom(bp_params->controller_id,
++ &atom_controller_id)) {
++ params.ucCRTC = (uint8_t)atom_controller_id;
++
++ if (blank)
++ params.ucBlanking = ATOM_BLANKING;
++ else
++ params.ucBlanking = ATOM_BLANKING_OFF;
++ params.usBlackColorRCr =
++ cpu_to_le16((uint16_t)bp_params->black_color_rcr);
++ params.usBlackColorGY =
++ cpu_to_le16((uint16_t)bp_params->black_color_gy);
++ params.usBlackColorBCb =
++ cpu_to_le16((uint16_t)bp_params->black_color_bcb);
++
++ if (EXEC_BIOS_CMD_TABLE(BlankCRTC, params))
++ result = BP_RESULT_OK;
++ } else
++ /* Not support more than two CRTC as current ASIC, update this
++ * if needed.
++ */
++ result = BP_RESULT_BADINPUT;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** SET CRTC TIMING
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result set_crtc_using_dtd_timing_v3(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_timing_parameters *bp_params);
++static enum bp_result set_crtc_timing_v1(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_timing_parameters *bp_params);
++
++static void init_set_crtc_timing(struct bios_parser *bp)
++{
++ uint32_t dtd_version =
++ BIOS_CMD_TABLE_PARA_REVISION(SetCRTC_UsingDTDTiming);
++ if (dtd_version > 2)
++ switch (dtd_version) {
++ case 3:
++ bp->cmd_tbl.set_crtc_timing =
++ set_crtc_using_dtd_timing_v3;
++ break;
++ default:
++ bp->cmd_tbl.set_crtc_timing = NULL;
++ break;
++ }
++ else
++ switch (BIOS_CMD_TABLE_PARA_REVISION(SetCRTC_Timing)) {
++ case 1:
++ bp->cmd_tbl.set_crtc_timing = set_crtc_timing_v1;
++ break;
++ default:
++ bp->cmd_tbl.set_crtc_timing = NULL;
++ break;
++ }
++}
++
++static enum bp_result set_crtc_timing_v1(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_timing_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ SET_CRTC_TIMING_PARAMETERS_PS_ALLOCATION params = {0};
++ uint8_t atom_controller_id;
++
++ if (bp->cmd_helper->controller_id_to_atom(
++ bp_params->controller_id, &atom_controller_id))
++ params.ucCRTC = atom_controller_id;
++
++ params.usH_Total = cpu_to_le16((uint16_t)(bp_params->h_total));
++ params.usH_Disp = cpu_to_le16((uint16_t)(bp_params->h_addressable));
++ params.usH_SyncStart = cpu_to_le16((uint16_t)(bp_params->h_sync_start));
++ params.usH_SyncWidth = cpu_to_le16((uint16_t)(bp_params->h_sync_width));
++ params.usV_Total = cpu_to_le16((uint16_t)(bp_params->v_total));
++ params.usV_Disp = cpu_to_le16((uint16_t)(bp_params->v_addressable));
++ params.usV_SyncStart =
++ cpu_to_le16((uint16_t)(bp_params->v_sync_start));
++ params.usV_SyncWidth =
++ cpu_to_le16((uint16_t)(bp_params->v_sync_width));
++
++
++ /* VBIOS does not expect any value except zero into this call, for
++ * underscan use another entry ProgramOverscan call but when mode
++ * 1776x1000 with the overscan 72x44 .e.i. 1920x1080 @30 DAL2 is ok,
++ * but when same ,but 60 Hz there is corruption
++ * DAL1 does not allow the mode 1776x1000@60
++ */
++ params.ucOverscanRight = (uint8_t)bp_params->h_overscan_right;
++ params.ucOverscanLeft = (uint8_t)bp_params->h_overscan_left;
++ params.ucOverscanBottom = (uint8_t)bp_params->v_overscan_bottom;
++ params.ucOverscanTop = (uint8_t)bp_params->v_overscan_top;
++
++ if (0 == bp_params->flags.HSYNC_POSITIVE_POLARITY)
++ params.susModeMiscInfo.usAccess =
++ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_HSYNC_POLARITY);
++
++ if (0 == bp_params->flags.VSYNC_POSITIVE_POLARITY)
++ params.susModeMiscInfo.usAccess =
++ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_VSYNC_POLARITY);
++
++ if (bp_params->flags.INTERLACE) {
++ params.susModeMiscInfo.usAccess =
++ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_INTERLACE);
++
++ /* original DAL code has this condition to apply tis for
++ * non-TV/CV only due to complex MV testing for possible
++ * impact
++ * if (pACParameters->signal != SignalType_YPbPr &&
++ * pACParameters->signal != SignalType_Composite &&
++ * pACParameters->signal != SignalType_SVideo)
++ */
++ /* HW will deduct 0.5 line from 2nd feild.
++ * i.e. for 1080i, it is 2 lines for 1st field, 2.5
++ * lines for the 2nd feild. we need input as 5 instead
++ * of 4, but it is 4 either from Edid data
++ * (spec CEA 861) or CEA timing table.
++ */
++ params.usV_SyncStart =
++ cpu_to_le16((uint16_t)(bp_params->v_sync_start + 1));
++ }
++
++ if (bp_params->flags.HORZ_COUNT_BY_TWO)
++ params.susModeMiscInfo.usAccess =
++ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_DOUBLE_CLOCK_MODE);
++
++ if (EXEC_BIOS_CMD_TABLE(SetCRTC_Timing, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result set_crtc_using_dtd_timing_v3(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_timing_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ SET_CRTC_USING_DTD_TIMING_PARAMETERS params = {0};
++ uint8_t atom_controller_id;
++
++ if (bp->cmd_helper->controller_id_to_atom(
++ bp_params->controller_id, &atom_controller_id))
++ params.ucCRTC = atom_controller_id;
++
++ /* bios usH_Size wants h addressable size */
++ params.usH_Size = cpu_to_le16((uint16_t)bp_params->h_addressable);
++ /* bios usH_Blanking_Time wants borders included in blanking */
++ params.usH_Blanking_Time =
++ cpu_to_le16((uint16_t)(bp_params->h_total - bp_params->h_addressable));
++ /* bios usV_Size wants v addressable size */
++ params.usV_Size = cpu_to_le16((uint16_t)bp_params->v_addressable);
++ /* bios usV_Blanking_Time wants borders included in blanking */
++ params.usV_Blanking_Time =
++ cpu_to_le16((uint16_t)(bp_params->v_total - bp_params->v_addressable));
++ /* bios usHSyncOffset is the offset from the end of h addressable,
++ * our horizontalSyncStart is the offset from the beginning
++ * of h addressable */
++ params.usH_SyncOffset =
++ cpu_to_le16((uint16_t)(bp_params->h_sync_start - bp_params->h_addressable));
++ params.usH_SyncWidth = cpu_to_le16((uint16_t)bp_params->h_sync_width);
++ /* bios usHSyncOffset is the offset from the end of v addressable,
++ * our verticalSyncStart is the offset from the beginning of
++ * v addressable */
++ params.usV_SyncOffset =
++ cpu_to_le16((uint16_t)(bp_params->v_sync_start - bp_params->v_addressable));
++ params.usV_SyncWidth = cpu_to_le16((uint16_t)bp_params->v_sync_width);
++
++ /* we assume that overscan from original timing does not get bigger
++ * than 255
++ * we will program all the borders in the Set CRTC Overscan call below
++ */
++
++ if (0 == bp_params->flags.HSYNC_POSITIVE_POLARITY)
++ params.susModeMiscInfo.usAccess =
++ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_HSYNC_POLARITY);
++
++ if (0 == bp_params->flags.VSYNC_POSITIVE_POLARITY)
++ params.susModeMiscInfo.usAccess =
++ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_VSYNC_POLARITY);
++
++
++ if (bp_params->flags.INTERLACE) {
++ params.susModeMiscInfo.usAccess =
++ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_INTERLACE);
++
++ /* original DAL code has this condition to apply this
++ * for non-TV/CV only
++ * due to complex MV testing for possible impact
++ * if ( pACParameters->signal != SignalType_YPbPr &&
++ * pACParameters->signal != SignalType_Composite &&
++ * pACParameters->signal != SignalType_SVideo)
++ */
++ {
++ /* HW will deduct 0.5 line from 2nd feild.
++ * i.e. for 1080i, it is 2 lines for 1st field,
++ * 2.5 lines for the 2nd feild. we need input as 5
++ * instead of 4.
++ * but it is 4 either from Edid data (spec CEA 861)
++ * or CEA timing table.
++ */
++ params.usV_SyncOffset =
++ cpu_to_le16(le16_to_cpu(params.usV_SyncOffset) + 1);
++
++ }
++ }
++
++ if (bp_params->flags.HORZ_COUNT_BY_TWO)
++ params.susModeMiscInfo.usAccess =
++ cpu_to_le16(le16_to_cpu(params.susModeMiscInfo.usAccess) | ATOM_DOUBLE_CLOCK_MODE);
++
++ if (EXEC_BIOS_CMD_TABLE(SetCRTC_UsingDTDTiming, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** SET CRTC OVERSCAN
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result set_crtc_overscan_v1(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_overscan_parameters *bp_params);
++
++static void init_set_crtc_overscan(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(SetCRTC_OverScan)) {
++ case 1:
++ bp->cmd_tbl.set_crtc_overscan = set_crtc_overscan_v1;
++ break;
++ default:
++ bp->cmd_tbl.set_crtc_overscan = NULL;
++ break;
++ }
++}
++
++static enum bp_result set_crtc_overscan_v1(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_overscan_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ SET_CRTC_OVERSCAN_PARAMETERS params = {0};
++ uint8_t atom_controller_id;
++
++ if (bp->cmd_helper->controller_id_to_atom(
++ bp_params->controller_id, &atom_controller_id))
++ params.ucCRTC = atom_controller_id;
++ else
++ return BP_RESULT_BADINPUT;
++
++ params.usOverscanRight =
++ cpu_to_le16((uint16_t)bp_params->h_overscan_right);
++ params.usOverscanLeft =
++ cpu_to_le16((uint16_t)bp_params->h_overscan_left);
++ params.usOverscanBottom =
++ cpu_to_le16((uint16_t)bp_params->v_overscan_bottom);
++ params.usOverscanTop =
++ cpu_to_le16((uint16_t)bp_params->v_overscan_top);
++
++ if (EXEC_BIOS_CMD_TABLE(SetCRTC_OverScan, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** SELECT CRTC SOURCE
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result select_crtc_source_v2(
++ struct bios_parser *bp,
++ struct bp_crtc_source_select *bp_params);
++static enum bp_result select_crtc_source_v3(
++ struct bios_parser *bp,
++ struct bp_crtc_source_select *bp_params);
++
++static void init_select_crtc_source(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(SelectCRTC_Source)) {
++ case 2:
++ bp->cmd_tbl.select_crtc_source = select_crtc_source_v2;
++ break;
++ case 3:
++ bp->cmd_tbl.select_crtc_source = select_crtc_source_v3;
++ break;
++ default:
++ bp->cmd_tbl.select_crtc_source = NULL;
++ break;
++ }
++}
++
++static enum bp_result select_crtc_source_v2(
++ struct bios_parser *bp,
++ struct bp_crtc_source_select *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ SELECT_CRTC_SOURCE_PARAMETERS_V2 params;
++ uint8_t atom_controller_id;
++ uint32_t atom_engine_id;
++ enum signal_type s = bp_params->signal;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ /* set controller id */
++ if (bp->cmd_helper->controller_id_to_atom(
++ bp_params->controller_id, &atom_controller_id))
++ params.ucCRTC = atom_controller_id;
++ else
++ return BP_RESULT_FAILURE;
++
++ /* set encoder id */
++ if (bp->cmd_helper->engine_bp_to_atom(
++ bp_params->engine_id, &atom_engine_id))
++ params.ucEncoderID = (uint8_t)atom_engine_id;
++ else
++ return BP_RESULT_FAILURE;
++
++ if (SIGNAL_TYPE_EDP == s ||
++ (SIGNAL_TYPE_DISPLAY_PORT == s &&
++ SIGNAL_TYPE_LVDS == bp_params->sink_signal))
++ s = SIGNAL_TYPE_LVDS;
++
++ params.ucEncodeMode =
++ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
++ s, bp_params->enable_dp_audio);
++
++ if (EXEC_BIOS_CMD_TABLE(SelectCRTC_Source, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result select_crtc_source_v3(
++ struct bios_parser *bp,
++ struct bp_crtc_source_select *bp_params)
++{
++ bool result = BP_RESULT_FAILURE;
++ SELECT_CRTC_SOURCE_PARAMETERS_V3 params;
++ uint8_t atom_controller_id;
++ uint32_t atom_engine_id;
++ enum signal_type s = bp_params->signal;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ if (bp->cmd_helper->controller_id_to_atom(bp_params->controller_id,
++ &atom_controller_id))
++ params.ucCRTC = atom_controller_id;
++ else
++ return result;
++
++ if (bp->cmd_helper->engine_bp_to_atom(bp_params->engine_id,
++ &atom_engine_id))
++ params.ucEncoderID = (uint8_t)atom_engine_id;
++ else
++ return result;
++
++ if (SIGNAL_TYPE_EDP == s ||
++ (SIGNAL_TYPE_DISPLAY_PORT == s &&
++ SIGNAL_TYPE_LVDS == bp_params->sink_signal))
++ s = SIGNAL_TYPE_LVDS;
++
++ params.ucEncodeMode =
++ bp->cmd_helper->encoder_mode_bp_to_atom(
++ s, bp_params->enable_dp_audio);
++ /* Needed for VBIOS Random Spatial Dithering feature */
++ params.ucDstBpc = (uint8_t)(bp_params->display_output_bit_depth);
++
++ if (EXEC_BIOS_CMD_TABLE(SelectCRTC_Source, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** ENABLE CRTC
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result enable_crtc_v1(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ bool enable);
++
++static void init_enable_crtc(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(EnableCRTC)) {
++ case 1:
++ bp->cmd_tbl.enable_crtc = enable_crtc_v1;
++ break;
++ default:
++ bp->cmd_tbl.enable_crtc = NULL;
++ break;
++ }
++}
++
++static enum bp_result enable_crtc_v1(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ bool enable)
++{
++ bool result = BP_RESULT_FAILURE;
++ ENABLE_CRTC_PARAMETERS params = {0};
++ uint8_t id;
++
++ if (bp->cmd_helper->controller_id_to_atom(controller_id, &id))
++ params.ucCRTC = id;
++ else
++ return BP_RESULT_BADINPUT;
++
++ if (enable)
++ params.ucEnable = ATOM_ENABLE;
++ else
++ params.ucEnable = ATOM_DISABLE;
++
++ if (EXEC_BIOS_CMD_TABLE(EnableCRTC, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** ENABLE CRTC MEM REQ
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result enable_crtc_mem_req_v1(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ bool enable);
++
++static void init_enable_crtc_mem_req(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(EnableCRTCMemReq)) {
++ case 1:
++ bp->cmd_tbl.enable_crtc_mem_req = enable_crtc_mem_req_v1;
++ break;
++ default:
++ bp->cmd_tbl.enable_crtc_mem_req = NULL;
++ break;
++ }
++}
++
++static enum bp_result enable_crtc_mem_req_v1(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ bool enable)
++{
++ bool result = BP_RESULT_BADINPUT;
++ ENABLE_CRTC_PARAMETERS params = {0};
++ uint8_t id;
++
++ if (bp->cmd_helper->controller_id_to_atom(controller_id, &id)) {
++ params.ucCRTC = id;
++
++ if (enable)
++ params.ucEnable = ATOM_ENABLE;
++ else
++ params.ucEnable = ATOM_DISABLE;
++
++ if (EXEC_BIOS_CMD_TABLE(EnableCRTCMemReq, params))
++ result = BP_RESULT_OK;
++ else
++ result = BP_RESULT_FAILURE;
++ }
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** DISPLAY PLL
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result program_clock_v5(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++static enum bp_result program_clock_v6(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++
++static void init_program_clock(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(SetPixelClock)) {
++ case 5:
++ bp->cmd_tbl.program_clock = program_clock_v5;
++ break;
++ case 6:
++ bp->cmd_tbl.program_clock = program_clock_v6;
++ break;
++ default:
++ bp->cmd_tbl.program_clock = NULL;
++ break;
++ }
++}
++
++static enum bp_result program_clock_v5(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++
++ SET_PIXEL_CLOCK_PS_ALLOCATION_V5 params;
++ uint32_t atom_pll_id;
++
++ dc_service_memset(&params, 0, sizeof(params));
++ if (!bp->cmd_helper->clock_source_id_to_atom(
++ bp_params->pll_id, &atom_pll_id)) {
++ BREAK_TO_DEBUGGER(); /* Invalid Inpute!! */
++ return BP_RESULT_BADINPUT;
++ }
++
++ /* We need to convert from KHz units into 10KHz units */
++ params.sPCLKInput.ucPpll = (uint8_t) atom_pll_id;
++ params.sPCLKInput.usPixelClock =
++ cpu_to_le16((uint16_t) (bp_params->target_pixel_clock / 10));
++ params.sPCLKInput.ucCRTC = (uint8_t) ATOM_CRTC_INVALID;
++
++ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
++ params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
++
++ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
++
++static enum bp_result program_clock_v6(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++
++ SET_PIXEL_CLOCK_PS_ALLOCATION_V6 params;
++ uint32_t atom_pll_id;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ if (!bp->cmd_helper->clock_source_id_to_atom(
++ bp_params->pll_id, &atom_pll_id)) {
++ BREAK_TO_DEBUGGER(); /*Invalid Input!!*/
++ return BP_RESULT_BADINPUT;
++ }
++
++ /* We need to convert from KHz units into 10KHz units */
++ params.sPCLKInput.ucPpll = (uint8_t)atom_pll_id;
++ params.sPCLKInput.ulDispEngClkFreq =
++ cpu_to_le32(bp_params->target_pixel_clock / 10);
++
++ if (bp_params->flags.SET_EXTERNAL_REF_DIV_SRC)
++ params.sPCLKInput.ucMiscInfo |= PIXEL_CLOCK_MISC_REF_DIV_SRC;
++
++ if (EXEC_BIOS_CMD_TABLE(SetPixelClock, params)) {
++ /* True display clock is returned by VBIOS if DFS bypass
++ * is enabled. */
++ bp_params->dfs_bypass_display_clock =
++ (uint32_t)(le32_to_cpu(params.sPCLKInput.ulDispEngClkFreq) * 10);
++ result = BP_RESULT_OK;
++ }
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** COMPUTE MEMORY ENGINE PLL
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result compute_memore_engine_pll_v4(
++ struct bios_parser *bp,
++ struct bp_display_clock_parameters *bp_params);
++
++static void init_compute_memore_engine_pll(struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(ComputeMemoryEnginePLL)) {
++ case 4:
++ bp->cmd_tbl.compute_memore_engine_pll =
++ compute_memore_engine_pll_v4;
++ break;
++ default:
++ bp->cmd_tbl.compute_memore_engine_pll = NULL;
++ break;
++ }
++}
++
++static enum bp_result compute_memore_engine_pll_v4(
++ struct bios_parser *bp,
++ struct bp_display_clock_parameters *bp_params)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++ COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 params;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ params.ulClock = cpu_to_le32(bp_params->target_display_clock / 10);
++
++ /* Initialize this to the target clock in case this call fails */
++ bp_params->actual_display_clock = bp_params->target_display_clock;
++
++ if (EXEC_BIOS_CMD_TABLE(ComputeMemoryEnginePLL, params)) {
++ /* Convert from 10KHz units back to KHz */
++ bp_params->actual_display_clock =
++ le32_to_cpu(params.ulClock) * 10;
++ bp_params->actual_post_divider_id = params.ucPostDiv;
++ result = BP_RESULT_OK;
++ }
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** EXTERNAL ENCODER CONTROL
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result external_encoder_control_v3(
++ struct bios_parser *bp,
++ struct bp_external_encoder_control *cntl);
++
++static void init_external_encoder_control(
++ struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(ExternalEncoderControl)) {
++ case 3:
++ bp->cmd_tbl.external_encoder_control =
++ external_encoder_control_v3;
++ break;
++ default:
++ bp->cmd_tbl.external_encoder_control = NULL;
++ break;
++ }
++}
++
++static enum bp_result external_encoder_control_v3(
++ struct bios_parser *bp,
++ struct bp_external_encoder_control *cntl)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++
++ /* we need use _PS_Alloc struct */
++ EXTERNAL_ENCODER_CONTROL_PS_ALLOCATION_V3 params;
++ EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 *cntl_params;
++ struct graphics_object_id encoder;
++ bool is_input_signal_dp = false;
++
++ dc_service_memset(&params, 0, sizeof(params));
++
++ cntl_params = &params.sExtEncoder;
++
++ encoder = cntl->encoder_id;
++
++ /* check if encoder supports external encoder control table */
++ switch (dal_graphics_object_id_get_encoder_id(encoder)) {
++ case ENCODER_ID_EXTERNAL_NUTMEG:
++ case ENCODER_ID_EXTERNAL_TRAVIS:
++ is_input_signal_dp = true;
++ break;
++
++ default:
++ BREAK_TO_DEBUGGER();
++ return BP_RESULT_BADINPUT;
++ }
++
++ /* Fill information based on the action
++ *
++ * Bit[6:4]: indicate external encoder, applied to all functions.
++ * =0: external encoder1, mapped to external encoder enum id1
++ * =1: external encoder2, mapped to external encoder enum id2
++ *
++ * enum ObjectEnumId
++ * {
++ * EnumId_Unknown = 0,
++ * EnumId_1,
++ * EnumId_2,
++ * };
++ */
++ cntl_params->ucConfig = (uint8_t)((encoder.enum_id - 1) << 4);
++
++ switch (cntl->action) {
++ case EXTERNAL_ENCODER_CONTROL_INIT:
++ /* output display connector type. Only valid in encoder
++ * initialization */
++ cntl_params->usConnectorId =
++ cpu_to_le16((uint16_t)cntl->connector_obj_id.id);
++ break;
++ case EXTERNAL_ENCODER_CONTROL_SETUP:
++ /* EXTERNAL_ENCODER_CONTROL_PARAMETERS_V3 pixel clock unit in
++ * 10KHz
++ * output display device pixel clock frequency in unit of 10KHz.
++ * Only valid in setup and enableoutput
++ */
++ cntl_params->usPixelClock =
++ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
++ /* Indicate display output signal type drive by external
++ * encoder, only valid in setup and enableoutput */
++ cntl_params->ucEncoderMode =
++ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
++ cntl->signal, false);
++
++ if (is_input_signal_dp) {
++ /* Bit[0]: indicate link rate, =1: 2.7Ghz, =0: 1.62Ghz,
++ * only valid in encoder setup with DP mode. */
++ if (LINK_RATE_HIGH == cntl->link_rate)
++ cntl_params->ucConfig |= 1;
++ /* output color depth Indicate encoder data bpc format
++ * in DP mode, only valid in encoder setup in DP mode.
++ */
++ cntl_params->ucBitPerColor =
++ (uint8_t)(cntl->color_depth);
++ }
++ /* Indicate how many lanes used by external encoder, only valid
++ * in encoder setup and enableoutput. */
++ cntl_params->ucLaneNum = (uint8_t)(cntl->lanes_number);
++ break;
++ case EXTERNAL_ENCODER_CONTROL_ENABLE:
++ cntl_params->usPixelClock =
++ cpu_to_le16((uint16_t)(cntl->pixel_clock / 10));
++ cntl_params->ucEncoderMode =
++ (uint8_t)bp->cmd_helper->encoder_mode_bp_to_atom(
++ cntl->signal, false);
++ cntl_params->ucLaneNum = (uint8_t)cntl->lanes_number;
++ break;
++ default:
++ break;
++ }
++
++ cntl_params->ucAction = (uint8_t)cntl->action;
++
++ if (EXEC_BIOS_CMD_TABLE(ExternalEncoderControl, params))
++ result = BP_RESULT_OK;
++
++ if (EXTERNAL_ENCODER_CONTROL_DAC_LOAD_DETECT == cntl->action) {
++#if defined(CONFIG_DRM_AMD_DAL_VBIOS_PRESENT)
++ if (BP_RESULT_OK == result)
++ /* get VBIOS result from scratch register.
++ * ExternalEncoderControl runs detection and save result
++ * in BIOS scratch registers. */
++ cntl->signal = bp->bios_helper->detect_sink(
++ bp->ctx,
++ encoder,
++ cntl->connector_obj_id,
++ cntl->signal);
++ else/* BIOS table does not work. */
++#endif
++ {
++ BREAK_TO_DEBUGGER(); /* VBios is needed */
++ cntl->signal = SIGNAL_TYPE_NONE;
++ }
++ }
++
++ return result;
++}
++
++/*******************************************************************************
++********************************************************************************
++**
++** ENABLE DISPLAY POWER GATING
++**
++********************************************************************************
++*******************************************************************************/
++
++static enum bp_result enable_disp_power_gating_v2_1(
++ struct bios_parser *bp,
++ enum controller_id crtc_id,
++ enum bp_pipe_control_action action);
++
++static void init_enable_disp_power_gating(
++ struct bios_parser *bp)
++{
++ switch (BIOS_CMD_TABLE_PARA_REVISION(EnableDispPowerGating)) {
++ case 1:
++ bp->cmd_tbl.enable_disp_power_gating =
++ enable_disp_power_gating_v2_1;
++ break;
++ default:
++ bp->cmd_tbl.enable_disp_power_gating = NULL;
++ break;
++ }
++}
++
++static enum bp_result enable_disp_power_gating_v2_1(
++ struct bios_parser *bp,
++ enum controller_id crtc_id,
++ enum bp_pipe_control_action action)
++{
++ enum bp_result result = BP_RESULT_FAILURE;
++
++ ENABLE_DISP_POWER_GATING_PARAMETERS_V2_1 params = {0};
++ uint8_t atom_crtc_id;
++
++ if (bp->cmd_helper->controller_id_to_atom(crtc_id, &atom_crtc_id))
++ params.ucDispPipeId = atom_crtc_id;
++ else
++ return BP_RESULT_BADINPUT;
++
++ params.ucEnable =
++ bp->cmd_helper->disp_power_gating_action_to_atom(action);
++
++ if (EXEC_BIOS_CMD_TABLE(EnableDispPowerGating, params))
++ result = BP_RESULT_OK;
++
++ return result;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table.h b/drivers/gpu/drm/amd/dal/dc/bios/command_table.h
+new file mode 100644
+index 0000000..814d31f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table.h
+@@ -0,0 +1,117 @@
++/*
++ * 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_COMMAND_TABLE_H__
++#define __DAL_COMMAND_TABLE_H__
++
++struct bios_parser;
++struct bp_encoder_control;
++
++struct cmd_tbl {
++ enum bp_result (*dig_encoder_control)(
++ struct bios_parser *bp,
++ struct bp_encoder_control *control);
++ enum bp_result (*encoder_control_dig1)(
++ struct bios_parser *bp,
++ struct bp_encoder_control *control);
++ enum bp_result (*encoder_control_dig2)(
++ struct bios_parser *bp,
++ struct bp_encoder_control *control);
++ enum bp_result (*dvo_encoder_control)(
++ struct bios_parser *bp,
++ struct bp_dvo_encoder_control *cntl);
++ enum bp_result (*transmitter_control)(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *control);
++ enum bp_result (*set_pixel_clock)(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++ enum bp_result (*enable_spread_spectrum_on_ppll)(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable);
++ enum bp_result (*adjust_display_pll)(
++ struct bios_parser *bp,
++ struct bp_adjust_pixel_clock_parameters *bp_params);
++ enum bp_result (*dac1_encoder_control)(
++ struct bios_parser *bp,
++ bool enable,
++ uint32_t pixel_clock,
++ uint8_t dac_standard);
++ enum bp_result (*dac2_encoder_control)(
++ struct bios_parser *bp,
++ bool enable,
++ uint32_t pixel_clock,
++ uint8_t dac_standard);
++ enum bp_result (*dac1_output_control)(
++ struct bios_parser *bp,
++ bool enable);
++ enum bp_result (*dac2_output_control)(
++ struct bios_parser *bp,
++ bool enable);
++ enum signal_type (*dac_load_detection)(
++ struct bios_parser *bp,
++ struct graphics_object_id encoder,
++ struct graphics_object_id connector,
++ enum signal_type display_signal);
++ enum bp_result (*blank_crtc)(
++ struct bios_parser *bp,
++ struct bp_blank_crtc_parameters *bp_params,
++ bool blank);
++ enum bp_result (*set_crtc_timing)(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_timing_parameters *bp_params);
++ enum bp_result (*set_crtc_overscan)(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_overscan_parameters *bp_params);
++ enum bp_result (*select_crtc_source)(
++ struct bios_parser *bp,
++ struct bp_crtc_source_select *bp_params);
++ enum bp_result (*enable_crtc)(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ bool enable);
++ enum bp_result (*enable_crtc_mem_req)(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ bool enable);
++ enum bp_result (*program_clock)(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++ enum bp_result (*compute_memore_engine_pll)(
++ struct bios_parser *bp,
++ struct bp_display_clock_parameters *bp_params);
++ enum bp_result (*external_encoder_control)(
++ struct bios_parser *bp,
++ struct bp_external_encoder_control *cntl);
++ enum bp_result (*enable_disp_power_gating)(
++ struct bios_parser *bp,
++ enum controller_id crtc_id,
++ enum bp_pipe_control_action action);
++};
++
++void dal_bios_parser_init_cmd_tbl(struct bios_parser *bp);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
+new file mode 100644
+index 0000000..dad1426
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.c
+@@ -0,0 +1,315 @@
++/*
++ * 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 "dal_services.h"
++
++#include "atom.h"
++
++#include "include/bios_parser_types.h"
++#include "include/adapter_service_types.h"
++
++#include "command_table_helper.h"
++
++bool dal_bios_parser_init_cmd_tbl_helper(
++ const struct command_table_helper **h,
++ enum dce_version dce)
++{
++ switch (dce) {
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ *h = dal_cmd_tbl_helper_dce110_get_table();
++ return true;
++
++#endif
++ default:
++ /* Unsupported DCE */
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++}
++
++/* real implementations */
++
++bool dal_cmd_table_helper_controller_id_to_atom(
++ enum controller_id id,
++ uint8_t *atom_id)
++{
++ if (atom_id == NULL) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ switch (id) {
++ case CONTROLLER_ID_D0:
++ *atom_id = ATOM_CRTC1;
++ return true;
++ case CONTROLLER_ID_D1:
++ *atom_id = ATOM_CRTC2;
++ return true;
++ case CONTROLLER_ID_D2:
++ *atom_id = ATOM_CRTC3;
++ return true;
++ case CONTROLLER_ID_D3:
++ *atom_id = ATOM_CRTC4;
++ return true;
++ case CONTROLLER_ID_D4:
++ *atom_id = ATOM_CRTC5;
++ return true;
++ case CONTROLLER_ID_D5:
++ *atom_id = ATOM_CRTC6;
++ return true;
++ case CONTROLLER_ID_UNDERLAY0:
++ *atom_id = ATOM_UNDERLAY_PIPE0;
++ return true;
++ case CONTROLLER_ID_UNDEFINED:
++ *atom_id = ATOM_CRTC_INVALID;
++ return true;
++ default:
++ /* Wrong controller id */
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++}
++
++/**
++* translate_transmitter_bp_to_atom
++*
++* @brief
++* Translate the Transmitter to the corresponding ATOM BIOS value
++*
++* @param
++* input transmitter
++* output digitalTransmitter
++* // =00: Digital Transmitter1 ( UNIPHY linkAB )
++* // =01: Digital Transmitter2 ( UNIPHY linkCD )
++* // =02: Digital Transmitter3 ( UNIPHY linkEF )
++*/
++uint8_t dal_cmd_table_helper_transmitter_bp_to_atom(
++ enum transmitter t)
++{
++ switch (t) {
++ case TRANSMITTER_UNIPHY_A:
++ case TRANSMITTER_UNIPHY_B:
++ case TRANSMITTER_TRAVIS_LCD:
++ return 0;
++ case TRANSMITTER_UNIPHY_C:
++ case TRANSMITTER_UNIPHY_D:
++ return 1;
++ case TRANSMITTER_UNIPHY_E:
++ case TRANSMITTER_UNIPHY_F:
++ return 2;
++ default:
++ /* Invalid Transmitter Type! */
++ BREAK_TO_DEBUGGER();
++ return 0;
++ }
++}
++
++uint32_t dal_cmd_table_helper_encoder_mode_bp_to_atom(
++ enum signal_type s,
++ bool enable_dp_audio)
++{
++ switch (s) {
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ return ATOM_ENCODER_MODE_DVI;
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ return ATOM_ENCODER_MODE_HDMI;
++ case SIGNAL_TYPE_LVDS:
++ return ATOM_ENCODER_MODE_LVDS;
++ case SIGNAL_TYPE_EDP:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ if (enable_dp_audio)
++ return ATOM_ENCODER_MODE_DP_AUDIO;
++ else
++ return ATOM_ENCODER_MODE_DP;
++ case SIGNAL_TYPE_RGB:
++ return ATOM_ENCODER_MODE_CRT;
++ default:
++ return ATOM_ENCODER_MODE_CRT;
++ }
++}
++
++void dal_cmd_table_helper_assign_control_parameter(
++ const struct command_table_helper *h,
++ struct bp_encoder_control *control,
++ DIG_ENCODER_CONTROL_PARAMETERS_V2 *ctrl_param)
++{
++ /* there are three transmitter blocks, each one has two links 4-lanes
++ * each, A+B, C+D, E+F, Uniphy A, C and E are enumerated as link 0 in
++ * each transmitter block B, D and F as link 1, third transmitter block
++ * has non splitable links (UniphyE and UniphyF can not be configured
++ * separately to drive two different streams)
++ */
++ if ((control->transmitter == TRANSMITTER_UNIPHY_B) ||
++ (control->transmitter == TRANSMITTER_UNIPHY_D) ||
++ (control->transmitter == TRANSMITTER_UNIPHY_F)) {
++ /* Bit2: Link Select
++ * =0: PHY linkA/C/E
++ * =1: PHY linkB/D/F
++ */
++ ctrl_param->acConfig.ucLinkSel = 1;
++ }
++
++ /* Bit[4:3]: Transmitter Selection
++ * =00: Digital Transmitter1 ( UNIPHY linkAB )
++ * =01: Digital Transmitter2 ( UNIPHY linkCD )
++ * =02: Digital Transmitter3 ( UNIPHY linkEF )
++ * =03: Reserved
++ */
++ ctrl_param->acConfig.ucTransmitterSel =
++ (uint8_t)(h->transmitter_bp_to_atom(control->transmitter));
++
++ /* We need to convert from KHz units into 10KHz units */
++ ctrl_param->ucAction = h->encoder_action_to_atom(control->action);
++ ctrl_param->usPixelClock = cpu_to_le16((uint16_t)(control->pixel_clock / 10));
++ ctrl_param->ucEncoderMode =
++ (uint8_t)(h->encoder_mode_bp_to_atom(
++ control->signal, control->enable_dp_audio));
++ ctrl_param->ucLaneNum = (uint8_t)(control->lanes_number);
++}
++
++bool dal_cmd_table_helper_clock_source_id_to_ref_clk_src(
++ enum clock_source_id id,
++ uint32_t *ref_clk_src_id)
++{
++ if (ref_clk_src_id == NULL) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ switch (id) {
++ case CLOCK_SOURCE_ID_PLL1:
++ *ref_clk_src_id = ENCODER_REFCLK_SRC_P1PLL;
++ return true;
++ case CLOCK_SOURCE_ID_PLL2:
++ *ref_clk_src_id = ENCODER_REFCLK_SRC_P2PLL;
++ return true;
++ case CLOCK_SOURCE_ID_DCPLL:
++ *ref_clk_src_id = ENCODER_REFCLK_SRC_DCPLL;
++ return true;
++ case CLOCK_SOURCE_ID_EXTERNAL:
++ *ref_clk_src_id = ENCODER_REFCLK_SRC_EXTCLK;
++ return true;
++ case CLOCK_SOURCE_ID_UNDEFINED:
++ *ref_clk_src_id = ENCODER_REFCLK_SRC_INVALID;
++ return true;
++ default:
++ /* Unsupported clock source id */
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++}
++
++uint8_t dal_cmd_table_helper_encoder_id_to_atom(
++ enum encoder_id id)
++{
++ switch (id) {
++ case ENCODER_ID_INTERNAL_LVDS:
++ return ENCODER_OBJECT_ID_INTERNAL_LVDS;
++ case ENCODER_ID_INTERNAL_TMDS1:
++ return ENCODER_OBJECT_ID_INTERNAL_TMDS1;
++ case ENCODER_ID_INTERNAL_TMDS2:
++ return ENCODER_OBJECT_ID_INTERNAL_TMDS2;
++ case ENCODER_ID_INTERNAL_DAC1:
++ return ENCODER_OBJECT_ID_INTERNAL_DAC1;
++ case ENCODER_ID_INTERNAL_DAC2:
++ return ENCODER_OBJECT_ID_INTERNAL_DAC2;
++ case ENCODER_ID_INTERNAL_SDVOA:
++ return ENCODER_OBJECT_ID_INTERNAL_SDVOA;
++ case ENCODER_ID_INTERNAL_SDVOB:
++ return ENCODER_OBJECT_ID_INTERNAL_SDVOB;
++ case ENCODER_ID_EXTERNAL_SI170B:
++ return ENCODER_OBJECT_ID_SI170B;
++ case ENCODER_ID_EXTERNAL_CH7303:
++ return ENCODER_OBJECT_ID_CH7303;
++ case ENCODER_ID_EXTERNAL_CH7301:
++ return ENCODER_OBJECT_ID_CH7301;
++ case ENCODER_ID_INTERNAL_DVO1:
++ return ENCODER_OBJECT_ID_INTERNAL_DVO1;
++ case ENCODER_ID_EXTERNAL_SDVOA:
++ return ENCODER_OBJECT_ID_EXTERNAL_SDVOA;
++ case ENCODER_ID_EXTERNAL_SDVOB:
++ return ENCODER_OBJECT_ID_EXTERNAL_SDVOB;
++ case ENCODER_ID_EXTERNAL_TITFP513:
++ return ENCODER_OBJECT_ID_TITFP513;
++ case ENCODER_ID_INTERNAL_LVTM1:
++ return ENCODER_OBJECT_ID_INTERNAL_LVTM1;
++ case ENCODER_ID_EXTERNAL_VT1623:
++ return ENCODER_OBJECT_ID_VT1623;
++ case ENCODER_ID_EXTERNAL_SI1930:
++ return ENCODER_OBJECT_ID_HDMI_SI1930;
++ case ENCODER_ID_INTERNAL_HDMI:
++ return ENCODER_OBJECT_ID_HDMI_INTERNAL;
++ case ENCODER_ID_EXTERNAL_TRAVIS:
++ return ENCODER_OBJECT_ID_TRAVIS;
++ case ENCODER_ID_EXTERNAL_NUTMEG:
++ return ENCODER_OBJECT_ID_NUTMEG;
++ case ENCODER_ID_INTERNAL_KLDSCP_TMDS1:
++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_TMDS1;
++ case ENCODER_ID_INTERNAL_KLDSCP_DVO1:
++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DVO1;
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC1;
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_DAC2;
++ case ENCODER_ID_EXTERNAL_SI178:
++ return ENCODER_OBJECT_ID_SI178;
++ case ENCODER_ID_EXTERNAL_MVPU_FPGA:
++ return ENCODER_OBJECT_ID_MVPU_FPGA;
++ case ENCODER_ID_INTERNAL_DDI:
++ return ENCODER_OBJECT_ID_INTERNAL_DDI;
++ case ENCODER_ID_EXTERNAL_VT1625:
++ return ENCODER_OBJECT_ID_VT1625;
++ case ENCODER_ID_EXTERNAL_SI1932:
++ return ENCODER_OBJECT_ID_HDMI_SI1932;
++ case ENCODER_ID_EXTERNAL_AN9801:
++ return ENCODER_OBJECT_ID_DP_AN9801;
++ case ENCODER_ID_EXTERNAL_DP501:
++ return ENCODER_OBJECT_ID_DP_DP501;
++ case ENCODER_ID_INTERNAL_UNIPHY:
++ return ENCODER_OBJECT_ID_INTERNAL_UNIPHY;
++ case ENCODER_ID_INTERNAL_KLDSCP_LVTMA:
++ return ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA;
++ case ENCODER_ID_INTERNAL_UNIPHY1:
++ return ENCODER_OBJECT_ID_INTERNAL_UNIPHY1;
++ case ENCODER_ID_INTERNAL_UNIPHY2:
++ return ENCODER_OBJECT_ID_INTERNAL_UNIPHY2;
++ case ENCODER_ID_INTERNAL_UNIPHY3:
++ return ENCODER_OBJECT_ID_INTERNAL_UNIPHY3;
++ case ENCODER_ID_INTERNAL_WIRELESS:
++ return ENCODER_OBJECT_ID_INTERNAL_VCE;
++ case ENCODER_ID_EXTERNAL_GENERIC_DVO:
++ return ENCODER_OBJECT_ID_GENERAL_EXTERNAL_DVO;
++ case ENCODER_ID_UNKNOWN:
++ return ENCODER_OBJECT_ID_NONE;
++ default:
++ /* Invalid encoder id */
++ BREAK_TO_DEBUGGER();
++ return ENCODER_OBJECT_ID_NONE;
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
+new file mode 100644
+index 0000000..e5c00de
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/command_table_helper.h
+@@ -0,0 +1,87 @@
++/*
++ * 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_COMMAND_TABLE_HELPER_H__
++#define __DAL_COMMAND_TABLE_HELPER_H__
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/command_table_helper_dce110.h"
++#endif
++
++struct command_table_helper {
++ bool (*controller_id_to_atom)(enum controller_id id, uint8_t *atom_id);
++ uint8_t (*encoder_action_to_atom)(
++ enum bp_encoder_control_action action);
++ uint32_t (*encoder_mode_bp_to_atom)(enum signal_type s,
++ bool enable_dp_audio);
++ bool (*engine_bp_to_atom)(enum engine_id engine_id,
++ uint32_t *atom_engine_id);
++ void (*assign_control_parameter)(
++ const struct command_table_helper *h,
++ struct bp_encoder_control *control,
++ DIG_ENCODER_CONTROL_PARAMETERS_V2 *ctrl_param);
++ bool (*clock_source_id_to_atom)(enum clock_source_id id,
++ uint32_t *atom_pll_id);
++ bool (*clock_source_id_to_ref_clk_src)(
++ enum clock_source_id id,
++ uint32_t *ref_clk_src_id);
++ uint8_t (*transmitter_bp_to_atom)(enum transmitter t);
++ uint8_t (*encoder_id_to_atom)(enum encoder_id id);
++ uint8_t (*clock_source_id_to_atom_phy_clk_src_id)(
++ enum clock_source_id id);
++ uint8_t (*signal_type_to_atom_dig_mode)(enum signal_type s);
++ uint8_t (*hpd_sel_to_atom)(enum hpd_source_id id);
++ uint8_t (*dig_encoder_sel_to_atom)(enum engine_id engine_id);
++ uint8_t (*phy_id_to_atom)(enum transmitter t);
++ uint8_t (*disp_power_gating_action_to_atom)(
++ enum bp_pipe_control_action action);
++};
++
++bool dal_bios_parser_init_cmd_tbl_helper(const struct command_table_helper **h,
++ enum dce_version dce);
++
++bool dal_cmd_table_helper_controller_id_to_atom(
++ enum controller_id id,
++ uint8_t *atom_id);
++
++uint32_t dal_cmd_table_helper_encoder_mode_bp_to_atom(
++ enum signal_type s,
++ bool enable_dp_audio);
++
++void dal_cmd_table_helper_assign_control_parameter(
++ const struct command_table_helper *h,
++ struct bp_encoder_control *control,
++DIG_ENCODER_CONTROL_PARAMETERS_V2 *ctrl_param);
++
++bool dal_cmd_table_helper_clock_source_id_to_ref_clk_src(
++ enum clock_source_id id,
++ uint32_t *ref_clk_src_id);
++
++uint8_t dal_cmd_table_helper_transmitter_bp_to_atom(
++ enum transmitter t);
++
++uint8_t dal_cmd_table_helper_encoder_id_to_atom(
++ enum encoder_id id);
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce110/bios_parser_helper_dce110.c b/drivers/gpu/drm/amd/dal/dc/bios/dce110/bios_parser_helper_dce110.c
+new file mode 100644
+index 0000000..2cc2d2d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/dce110/bios_parser_helper_dce110.c
+@@ -0,0 +1,484 @@
++/*
++ * 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, sub license,
++ * 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 "dal_services.h"
++
++#include "atom.h"
++
++#include "include/bios_parser_types.h"
++#include "include/adapter_service_types.h"
++#include "include/logger_interface.h"
++
++#include "../bios_parser_helper.h"
++
++#include "dce/dce_11_0_d.h"
++#include "bif/bif_5_1_d.h"
++
++/**
++ * set_scratch_acc_mode_change
++ *
++ * @brief
++ * set Accelerated Mode in VBIOS scratch register, VBIOS will clean it when
++ * VGA/non-Accelerated mode is set
++ *
++ * @param
++ * struct dc_context *ctx - [in] DAL context
++ */
++static void set_scratch_acc_mode_change(
++ struct dc_context *ctx)
++{
++ uint32_t addr = mmBIOS_SCRATCH_6;
++ uint32_t value = 0;
++
++ value = dal_read_reg(ctx, addr);
++
++ value |= ATOM_S6_ACC_MODE;
++
++ dal_write_reg(ctx, addr, value);
++}
++
++/*
++ * set_scratch_active_and_requested
++ *
++ * @brief
++ * Set VBIOS scratch pad registers about active and requested displays
++ *
++ * @param
++ * struct dc_context *ctx - [in] DAL context for register accessing
++ * struct vbios_helper_data *d - [in] values to write
++ */
++static void set_scratch_active_and_requested(
++ struct dc_context *ctx,
++ struct vbios_helper_data *d)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ /* mmBIOS_SCRATCH_3 = mmBIOS_SCRATCH_0 + ATOM_ACTIVE_INFO_DEF */
++ addr = mmBIOS_SCRATCH_3;
++
++ value = dal_read_reg(ctx, addr);
++
++ value &= ~ATOM_S3_DEVICE_ACTIVE_MASK;
++ value |= (d->active & ATOM_S3_DEVICE_ACTIVE_MASK);
++
++ dal_write_reg(ctx, addr, value);
++
++ /* mmBIOS_SCRATCH_6 = mmBIOS_SCRATCH_0 + ATOM_ACC_CHANGE_INFO_DEF */
++ addr = mmBIOS_SCRATCH_6;
++
++ value = dal_read_reg(ctx, addr);
++
++ value &= ~ATOM_S6_ACC_REQ_MASK;
++ value |= (d->requested & ATOM_S6_ACC_REQ_MASK);
++
++ dal_write_reg(ctx, addr, value);
++
++ /* mmBIOS_SCRATCH_5 = mmBIOS_SCRATCH_0 + ATOM_DOS_REQ_INFO_DEF */
++ addr = mmBIOS_SCRATCH_5;
++
++ value = dal_read_reg(ctx, addr);
++
++ value &= ~ATOM_S5_DOS_REQ_DEVICEw0;
++ value |= (d->active & ATOM_S5_DOS_REQ_DEVICEw0);
++
++ dal_write_reg(ctx, addr, value);
++
++ d->active = 0;
++ d->requested = 0;
++}
++
++/**
++ * get LCD Scale Mode from VBIOS scratch register
++ */
++static enum lcd_scale get_scratch_lcd_scale(
++ struct dc_context *ctx)
++{
++ uint32_t addr = mmBIOS_SCRATCH_6;
++ uint32_t value = 0;
++
++ value = dal_read_reg(ctx, addr);
++
++ if (value & ATOM_S6_REQ_LCD_EXPANSION_FULL)
++ return LCD_SCALE_FULLPANEL;
++ else if (value & ATOM_S6_REQ_LCD_EXPANSION_ASPEC_RATIO)
++ return LCD_SCALE_ASPECTRATIO;
++ else
++ return LCD_SCALE_NONE;
++}
++
++/**
++ * prepare_scratch_active_and_requested
++ *
++ * @brief
++ * prepare and update VBIOS scratch pad registers about active and requested
++ * displays
++ *
++ * @param
++ * data - helper's shared data
++ * enum controller_ild - controller Id
++ * enum signal_type - signal type used on display
++ * const struct connector_device_tag_info* - pointer to display type and enum id
++ */
++static void prepare_scratch_active_and_requested(
++ struct dc_context *ctx,
++ struct vbios_helper_data *data,
++ enum controller_id id,
++ enum signal_type s,
++ const struct connector_device_tag_info *dev_tag)
++{
++ switch (s) {
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ if (dev_tag->dev_id.device_type == DEVICE_TYPE_DFP)
++ switch (dev_tag->dev_id.enum_id) {
++ case 1:
++ data->requested |= ATOM_S6_ACC_REQ_DFP1;
++ data->active |= ATOM_S3_DFP1_ACTIVE;
++ break;
++ case 2:
++ data->requested |= ATOM_S6_ACC_REQ_DFP2;
++ data->active |= ATOM_S3_DFP2_ACTIVE;
++ break;
++ case 3:
++ data->requested |= ATOM_S6_ACC_REQ_DFP3;
++ data->active |= ATOM_S3_DFP3_ACTIVE;
++ break;
++ case 4:
++ data->requested |= ATOM_S6_ACC_REQ_DFP4;
++ data->active |= ATOM_S3_DFP4_ACTIVE;
++ break;
++ case 5:
++ data->requested |= ATOM_S6_ACC_REQ_DFP5;
++ data->active |= ATOM_S3_DFP5_ACTIVE;
++ break;
++ case 6:
++ data->requested |= ATOM_S6_ACC_REQ_DFP6;
++ data->active |= ATOM_S3_DFP6_ACTIVE;
++ break;
++ default:
++ break;
++ }
++ break;
++ case SIGNAL_TYPE_LVDS:
++ case SIGNAL_TYPE_EDP:
++ data->requested |= ATOM_S6_ACC_REQ_LCD1;
++ data->active |= ATOM_S3_LCD1_ACTIVE;
++ break;
++ case SIGNAL_TYPE_RGB:
++ if (dev_tag->dev_id.device_type == DEVICE_TYPE_CRT)
++ switch (dev_tag->dev_id.enum_id) {
++ case 1:
++ data->requested |= ATOM_S6_ACC_REQ_CRT1;
++ data->active |= ATOM_S3_CRT1_ACTIVE;
++ break;
++ case 2:
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_COMPONENT_BIOS,
++ "%s: DAL does not support DAC2!\n",
++ __func__);
++ break;
++ default:
++ break;
++ }
++ break;
++ default:
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_BIOS,
++ LOG_MINOR_COMPONENT_BIOS,
++ "%s: No such signal!\n",
++ __func__);
++ break;
++ }
++}
++
++/*
++ * is_accelerated_mode
++ *
++ * @brief
++ * set Accelerated Mode in VBIOS scratch register, VBIOS will clean it when
++ * VGA/non-Accelerated mode is set
++ *
++ * @param
++ * struct dc_context *ctx
++ *
++ * @return
++ * true if in acceleration mode, false otherwise.
++ */
++static bool is_accelerated_mode(
++ struct dc_context *ctx)
++{
++ uint32_t addr = mmBIOS_SCRATCH_6;
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ return (value & ATOM_S6_ACC_MODE) ? true : false;
++}
++
++#define BIOS_SCRATCH0_DAC_B_SHIFT 8
++
++/**
++ * detect_sink
++ *
++ * @brief
++ * read VBIOS scratch register to determine whether display for the specified
++ * signal is present and return the actual sink signal type
++ * For analog signals VBIOS load detection has to be called prior reading the
++ * register
++ *
++ * @param
++ * encoder - encoder id (to specify DAC)
++ * connector - connector id (to check CV on DIN)
++ * signal - signal (as display type) to check
++ *
++ * @return
++ * signal_type - actual (on the sink) signal type detected
++ */
++static enum signal_type detect_sink(
++ struct dc_context *ctx,
++ struct graphics_object_id encoder,
++ struct graphics_object_id connector,
++ enum signal_type signal)
++{
++ uint32_t bios_scratch0;
++ uint32_t encoder_id = encoder.id;
++ /* after DCE 10.x does not support DAC2, so assert and return
++ * SIGNAL_TYPE_NONE */
++ if (encoder_id == ENCODER_ID_INTERNAL_DAC2
++ || encoder_id == ENCODER_ID_INTERNAL_KLDSCP_DAC2) {
++ ASSERT(false);
++ return SIGNAL_TYPE_NONE;
++ }
++
++ bios_scratch0 = dal_read_reg(ctx,
++ mmBIOS_SCRATCH_0 + ATOM_DEVICE_CONNECT_INFO_DEF);
++
++ /* In further processing we use DACB masks. If we want detect load on
++ * DACA, we need to shift the register so DACA bits will be in place of
++ * DACB bits
++ */
++ if (encoder_id == ENCODER_ID_INTERNAL_DAC1
++ || encoder_id == ENCODER_ID_INTERNAL_KLDSCP_DAC1
++ || encoder_id == ENCODER_ID_EXTERNAL_NUTMEG
++ || encoder_id == ENCODER_ID_EXTERNAL_TRAVIS) {
++ bios_scratch0 <<= BIOS_SCRATCH0_DAC_B_SHIFT;
++ }
++
++ switch (signal) {
++ case SIGNAL_TYPE_RGB: {
++ if (bios_scratch0 & ATOM_S0_CRT2_MASK)
++ return SIGNAL_TYPE_RGB;
++ break;
++ }
++ case SIGNAL_TYPE_LVDS: {
++ if (bios_scratch0 & ATOM_S0_LCD1)
++ return SIGNAL_TYPE_LVDS;
++ break;
++ }
++ case SIGNAL_TYPE_EDP: {
++ if (bios_scratch0 & ATOM_S0_LCD1)
++ return SIGNAL_TYPE_EDP;
++ break;
++ }
++ default:
++ break;
++ }
++
++ return SIGNAL_TYPE_NONE;
++}
++
++/**
++ * set_scratch_connected
++ *
++ * @brief
++ * update BIOS_SCRATCH_0 register about connected displays
++ *
++ * @param
++ * bool - update scratch register or just prepare info to be updated
++ * bool - connection state
++ * const struct connector_device_tag_info * - pointer to device type and enum ID
++ */
++static void set_scratch_connected(
++ struct dc_context *ctx,
++ struct graphics_object_id id,
++ bool connected,
++ const struct connector_device_tag_info *device_tag)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++ uint32_t update = 0;
++
++ switch (device_tag->dev_id.device_type) {
++ case DEVICE_TYPE_LCD:
++ /* For LCD VBIOS will update LCD Panel connected bit always and
++ * Lid state bit based on SBIOS info do not do anything here
++ * for LCD
++ */
++ break;
++ case DEVICE_TYPE_CRT:
++ /*
++ * CRT is not supported in DCE11
++ */
++ break;
++ case DEVICE_TYPE_DFP:
++ switch (device_tag->dev_id.enum_id) {
++ case 1:
++ update |= ATOM_S0_DFP1;
++ break;
++ case 2:
++ update |= ATOM_S0_DFP2;
++ break;
++ case 3:
++ update |= ATOM_S0_DFP3;
++ break;
++ case 4:
++ update |= ATOM_S0_DFP4;
++ break;
++ case 5:
++ update |= ATOM_S0_DFP5;
++ break;
++ case 6:
++ update |= ATOM_S0_DFP6;
++ break;
++ default:
++ break;
++ }
++ break;
++ case DEVICE_TYPE_CV:
++ /* DCE 8.0 does not support CV,
++ * so don't do anything */
++ break;
++
++ case DEVICE_TYPE_TV:
++ /* For TV VBIOS will update S-Video or
++ * Composite scratch bits on DAL_LoadDetect
++ * when called by driver, do not do anything
++ * here for TV
++ */
++ break;
++
++ default:
++ break;
++
++ }
++
++ /* update scratch register */
++ addr = mmBIOS_SCRATCH_0 + ATOM_DEVICE_CONNECT_INFO_DEF;
++
++ value = dal_read_reg(ctx, addr);
++
++ if (connected)
++ value |= update;
++ else
++ value &= ~update;
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void set_scratch_critical_state(
++ struct dc_context *ctx,
++ bool state)
++{
++ uint32_t addr = mmBIOS_SCRATCH_6;
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ if (state)
++ value |= ATOM_S6_CRITICAL_STATE;
++ else
++ value &= ~ATOM_S6_CRITICAL_STATE;
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void set_scratch_lcd_scale(
++ struct dc_context *ctx,
++ enum lcd_scale lcd_scale_request)
++{
++ DAL_LOGGER_NOT_IMPL(
++ LOG_MINOR_COMPONENT_BIOS,
++ "Bios Parser:%s\n",
++ __func__);
++}
++
++static bool is_lid_open(struct dc_context *ctx)
++{
++ uint32_t bios_scratch6;
++
++ bios_scratch6 =
++ dal_read_reg(
++ ctx,
++ mmBIOS_SCRATCH_0 + ATOM_ACC_CHANGE_INFO_DEF);
++
++ /* lid is open if the bit is not set */
++ if (!(bios_scratch6 & ATOM_S6_LID_STATE))
++ return true;
++
++ return false;
++}
++
++/* function table */
++static const struct bios_parser_helper bios_parser_helper_funcs = {
++ .detect_sink = detect_sink,
++ .fmt_bit_depth_control = NULL,
++ .fmt_control = NULL,
++ .get_bios_event_info = NULL,
++ .get_embedded_display_controller_id = NULL,
++ .get_embedded_display_refresh_rate = NULL,
++ .get_requested_backlight_level = NULL,
++ .get_scratch_lcd_scale = get_scratch_lcd_scale,
++ .is_accelerated_mode = is_accelerated_mode,
++ .is_active_display = NULL,
++ .is_display_config_changed = NULL,
++ .is_lid_open = is_lid_open,
++ .is_lid_status_changed = NULL,
++ .prepare_scratch_active_and_requested =
++ prepare_scratch_active_and_requested,
++ .set_scratch_acc_mode_change = set_scratch_acc_mode_change,
++ .set_scratch_active_and_requested = set_scratch_active_and_requested,
++ .set_scratch_connected = set_scratch_connected,
++ .set_scratch_critical_state = set_scratch_critical_state,
++ .set_scratch_lcd_scale = set_scratch_lcd_scale,
++ .take_backlight_control = NULL,
++ .update_requested_backlight_level = NULL,
++};
++
++/*
++ * dal_bios_parser_dce110_init_bios_helper
++ *
++ * @brief
++ * Initialize BIOS helper functions
++ *
++ * @param
++ * const struct command_table_helper **h - [out] struct of functions
++ *
++ */
++
++const struct bios_parser_helper *dal_bios_parser_helper_dce110_get_table()
++{
++ return &bios_parser_helper_funcs;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce110/bios_parser_helper_dce110.h b/drivers/gpu/drm/amd/dal/dc/bios/dce110/bios_parser_helper_dce110.h
+new file mode 100644
+index 0000000..915f31a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/dce110/bios_parser_helper_dce110.h
+@@ -0,0 +1,34 @@
++/*
++ * 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, sub license,
++ * 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_BIOS_PARSER_HELPER_DCE110_H__
++#define __DAL_BIOS_PARSER_HELPER_DCE110_H__
++
++struct bios_parser_helper;
++
++/* Initialize BIOS helper functions */
++const struct bios_parser_helper *dal_bios_parser_helper_dce110_get_table(void);
++
++#endif /* __DAL_BIOS_PARSER_HELPER_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce110/command_table_helper_dce110.c b/drivers/gpu/drm/amd/dal/dc/bios/dce110/command_table_helper_dce110.c
+new file mode 100644
+index 0000000..e75b51b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/dce110/command_table_helper_dce110.c
+@@ -0,0 +1,369 @@
++/*
++ * 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 "dal_services.h"
++#include "atom.h"
++
++#include "include/bios_parser_types.h"
++#include "include/adapter_service_types.h"
++
++#include "../command_table_helper.h"
++
++static uint8_t phy_id_to_atom(enum transmitter t)
++{
++ uint8_t atom_phy_id;
++
++ switch (t) {
++ case TRANSMITTER_UNIPHY_A:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYA;
++ break;
++ case TRANSMITTER_UNIPHY_B:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYB;
++ break;
++ case TRANSMITTER_UNIPHY_C:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYC;
++ break;
++ case TRANSMITTER_UNIPHY_D:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYD;
++ break;
++ case TRANSMITTER_UNIPHY_E:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYE;
++ break;
++ case TRANSMITTER_UNIPHY_F:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYF;
++ break;
++ case TRANSMITTER_UNIPHY_G:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYG;
++ break;
++ default:
++ atom_phy_id = ATOM_PHY_ID_UNIPHYA;
++ break;
++ }
++ return atom_phy_id;
++}
++
++
++static uint8_t signal_type_to_atom_dig_mode(enum signal_type s)
++{
++ uint8_t atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP;
++
++ switch (s) {
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_EDP:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP;
++ break;
++ case SIGNAL_TYPE_LVDS:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_LVDS;
++ break;
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI;
++ break;
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_HDMI;
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DP_MST;
++ break;
++ default:
++ atom_dig_mode = ATOM_TRANSMITTER_DIGMODE_V5_DVI;
++ break;
++ }
++
++ return atom_dig_mode;
++}
++
++static uint8_t clock_source_id_to_atom_phy_clk_src_id(
++ enum clock_source_id id)
++{
++ uint8_t atom_phy_clk_src_id = 0;
++
++ switch (id) {
++ case CLOCK_SOURCE_ID_PLL0:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P0PLL;
++ break;
++ case CLOCK_SOURCE_ID_PLL1:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL;
++ break;
++ case CLOCK_SOURCE_ID_PLL2:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P2PLL;
++ break;
++ case CLOCK_SOURCE_ID_EXTERNAL:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_REFCLK_SRC_EXT;
++ break;
++ default:
++ atom_phy_clk_src_id = ATOM_TRANSMITTER_CONFIG_V5_P1PLL;
++ break;
++ }
++
++ return atom_phy_clk_src_id >> 2;
++}
++
++static uint8_t hpd_sel_to_atom(enum hpd_source_id id)
++{
++ uint8_t atom_hpd_sel = 0;
++
++ switch (id) {
++ case HPD_SOURCEID1:
++ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD1_SEL;
++ break;
++ case HPD_SOURCEID2:
++ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD2_SEL;
++ break;
++ case HPD_SOURCEID3:
++ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD3_SEL;
++ break;
++ case HPD_SOURCEID4:
++ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD4_SEL;
++ break;
++ case HPD_SOURCEID5:
++ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD5_SEL;
++ break;
++ case HPD_SOURCEID6:
++ atom_hpd_sel = ATOM_TRANSMITTER_CONFIG_V5_HPD6_SEL;
++ break;
++ case HPD_SOURCEID_UNKNOWN:
++ default:
++ atom_hpd_sel = 0;
++ break;
++ }
++ return atom_hpd_sel >> 4;
++}
++
++static uint8_t dig_encoder_sel_to_atom(enum engine_id id)
++{
++ uint8_t atom_dig_encoder_sel = 0;
++
++ switch (id) {
++ case ENGINE_ID_DIGA:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGA_SEL;
++ break;
++ case ENGINE_ID_DIGB:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGB_SEL;
++ break;
++ case ENGINE_ID_DIGC:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGC_SEL;
++ break;
++ case ENGINE_ID_DIGD:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGD_SEL;
++ break;
++ case ENGINE_ID_DIGE:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGE_SEL;
++ break;
++ case ENGINE_ID_DIGF:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGF_SEL;
++ break;
++ case ENGINE_ID_DIGG:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGG_SEL;
++ break;
++ case ENGINE_ID_UNKNOWN:
++ /* No DIG_FRONT is associated to DIG_BACKEND */
++ atom_dig_encoder_sel = 0;
++ break;
++ default:
++ atom_dig_encoder_sel = ATOM_TRANMSITTER_V5__DIGA_SEL;
++ break;
++ }
++
++ return atom_dig_encoder_sel;
++}
++
++static bool clock_source_id_to_atom(
++ enum clock_source_id id,
++ uint32_t *atom_pll_id)
++{
++ bool result = true;
++
++ if (atom_pll_id != NULL)
++ switch (id) {
++ case CLOCK_SOURCE_ID_PLL0:
++ *atom_pll_id = ATOM_PPLL0;
++ break;
++ case CLOCK_SOURCE_ID_PLL1:
++ *atom_pll_id = ATOM_PPLL1;
++ break;
++ case CLOCK_SOURCE_ID_PLL2:
++ *atom_pll_id = ATOM_PPLL2;
++ break;
++ case CLOCK_SOURCE_ID_EXTERNAL:
++ *atom_pll_id = ATOM_PPLL_INVALID;
++ break;
++ case CLOCK_SOURCE_ID_DFS:
++ *atom_pll_id = ATOM_EXT_PLL1;
++ break;
++ case CLOCK_SOURCE_ID_VCE:
++ /* for VCE encoding,
++ * we need to pass in ATOM_PPLL_INVALID
++ */
++ *atom_pll_id = ATOM_PPLL_INVALID;
++ break;
++ case CLOCK_SOURCE_ID_DP_DTO:
++ /* When programming DP DTO PLL ID should be invalid */
++ *atom_pll_id = ATOM_PPLL_INVALID;
++ break;
++ case CLOCK_SOURCE_ID_UNDEFINED:
++ /* Should not happen */
++ *atom_pll_id = ATOM_PPLL_INVALID;
++ result = false;
++ break;
++ default:
++ result = false;
++ break;
++ }
++
++ return result;
++}
++
++static bool engine_bp_to_atom(enum engine_id id, uint32_t *atom_engine_id)
++{
++ bool result = false;
++
++ if (atom_engine_id != NULL)
++ switch (id) {
++ case ENGINE_ID_DIGA:
++ *atom_engine_id = ASIC_INT_DIG1_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGB:
++ *atom_engine_id = ASIC_INT_DIG2_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGC:
++ *atom_engine_id = ASIC_INT_DIG3_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGD:
++ *atom_engine_id = ASIC_INT_DIG4_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGE:
++ *atom_engine_id = ASIC_INT_DIG5_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGF:
++ *atom_engine_id = ASIC_INT_DIG6_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DIGG:
++ *atom_engine_id = ASIC_INT_DIG7_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DVO:
++ *atom_engine_id = ASIC_EXT_DIG_ENCODER_ID;
++ result = true;
++ break;
++ case ENGINE_ID_DACA:
++ *atom_engine_id = ASIC_INT_DAC1_ENCODER_ID;
++ result = true;
++ break;
++ default:
++ break;
++ }
++
++ return result;
++}
++
++static uint8_t encoder_action_to_atom(enum bp_encoder_control_action action)
++{
++ uint8_t atom_action = 0;
++
++ switch (action) {
++ case ENCODER_CONTROL_ENABLE:
++ atom_action = ATOM_ENABLE;
++ break;
++ case ENCODER_CONTROL_DISABLE:
++ atom_action = ATOM_DISABLE;
++ break;
++ case ENCODER_CONTROL_SETUP:
++ atom_action = ATOM_ENCODER_CMD_SETUP;
++ break;
++ case ENCODER_CONTROL_INIT:
++ atom_action = ATOM_ENCODER_INIT;
++ break;
++ default:
++ BREAK_TO_DEBUGGER(); /* Unhandle action in driver.!! */
++ break;
++ }
++
++ return atom_action;
++}
++
++static uint8_t disp_power_gating_action_to_atom(
++ enum bp_pipe_control_action action)
++{
++ uint8_t atom_pipe_action = 0;
++
++ switch (action) {
++ case ASIC_PIPE_DISABLE:
++ atom_pipe_action = ATOM_DISABLE;
++ break;
++ case ASIC_PIPE_ENABLE:
++ atom_pipe_action = ATOM_ENABLE;
++ break;
++ case ASIC_PIPE_INIT:
++ atom_pipe_action = ATOM_INIT;
++ break;
++ default:
++ ASSERT_CRITICAL(false); /* Unhandle action in driver! */
++ break;
++ }
++
++ return atom_pipe_action;
++}
++
++/* function table */
++static const struct command_table_helper command_table_helper_funcs = {
++ .controller_id_to_atom = dal_cmd_table_helper_controller_id_to_atom,
++ .encoder_action_to_atom = encoder_action_to_atom,
++ .engine_bp_to_atom = engine_bp_to_atom,
++ .clock_source_id_to_atom = clock_source_id_to_atom,
++ .clock_source_id_to_atom_phy_clk_src_id =
++ clock_source_id_to_atom_phy_clk_src_id,
++ .signal_type_to_atom_dig_mode = signal_type_to_atom_dig_mode,
++ .hpd_sel_to_atom = hpd_sel_to_atom,
++ .dig_encoder_sel_to_atom = dig_encoder_sel_to_atom,
++ .phy_id_to_atom = phy_id_to_atom,
++ .disp_power_gating_action_to_atom = disp_power_gating_action_to_atom,
++ .assign_control_parameter = NULL,
++ .clock_source_id_to_ref_clk_src = NULL,
++ .transmitter_bp_to_atom = NULL,
++ .encoder_id_to_atom = dal_cmd_table_helper_encoder_id_to_atom,
++ .encoder_mode_bp_to_atom = dal_cmd_table_helper_encoder_mode_bp_to_atom,
++};
++
++/*
++ * dal_cmd_tbl_helper_dce110_get_table
++ *
++ * @brief
++ * Initialize command table helper functions
++ *
++ * @param
++ * const struct command_table_helper **h - [out] struct of functions
++ *
++ */
++const struct command_table_helper *dal_cmd_tbl_helper_dce110_get_table()
++{
++ return &command_table_helper_funcs;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/bios/dce110/command_table_helper_dce110.h b/drivers/gpu/drm/amd/dal/dc/bios/dce110/command_table_helper_dce110.h
+new file mode 100644
+index 0000000..eb60c2e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/bios/dce110/command_table_helper_dce110.h
+@@ -0,0 +1,34 @@
++/*
++ * 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_COMMAND_TABLE_HELPER_DCE110_H__
++#define __DAL_COMMAND_TABLE_HELPER_DCE110_H__
++
++struct command_table_helper;
++
++/* Initialize command table helper functions */
++const struct command_table_helper *dal_cmd_tbl_helper_dce110_get_table(void);
++
++#endif /* __DAL_COMMAND_TABLE_HELPER_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/calcs/Makefile b/drivers/gpu/drm/amd/dal/dc/calcs/Makefile
+new file mode 100644
+index 0000000..7f1916b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/calcs/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the 'calcs' sub-component of DAL.
++# It calculates Bandwidth and Watermarks values for HW programming
++#
++
++BW_CALCS = bandwidth_calcs.o bw_fixed.o scaler_filter.o
++
++AMD_DAL_BW_CALCS = $(addprefix $(AMDDALPATH)/dc/calcs/,$(BW_CALCS))
++
++AMD_DAL_FILES += $(AMD_DAL_BW_CALCS)
+diff --git a/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c b/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
+new file mode 100644
+index 0000000..68618bb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/calcs/bandwidth_calcs.c
+@@ -0,0 +1,3478 @@
++/*
++ * Copyright 2015 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#include "dc_services.h"
++
++#include "bandwidth_calcs.h"
++
++/*******************************************************************************
++ * Private Functions
++ ******************************************************************************/
++
++enum bw_defines {
++ def_ok,
++ def_na,
++ def_notok,
++ def_display_write_back420_chroma,
++ def_display_write_back420_luma,
++ def_graphics,
++ def_xl_pattern_solid,
++ def_xl_pattern_light_horizontal,
++ def_xl_pattern_checker,
++ def_notok_color,
++ def_na_color,
++ def_vb_black,
++ def_vb_white,
++ def_high_no_nbp_state_change_color,
++ def_high_no_nbp_state_change,
++ def_high_color,
++ def_mid_color,
++ def_low_color,
++ def_high,
++ def_mid,
++ def_low,
++ def_exceeded_allowed_maximum_sclk,
++ def_exceeded_allowed_maximum_bw,
++ def_exceeded_allowed_page_close_open,
++ def_exceeded_allowed_outstanding_pte_req_queue_size,
++ def_linear,
++ def_underlay444,
++ def_underlay422,
++ def_underlay420_chroma,
++ def_underlay420_luma,
++ def_any_lines,
++ def_auto,
++ def_manual,
++ def_portrait,
++ def_invalid_linear_or_stereo_mode,
++ def_invalid_rotation_or_bpp_or_stereo,
++ def_vsr_more_than_vtaps,
++ def_vsr_more_than_4,
++ def_ceil_htaps_div_4_more_or_eq_hsr,
++ def_hsr_more_than_htaps,
++ def_hsr_more_than_4,
++ def_none,
++ def_blended,
++ def_landscape
++};
++
++static void calculate_bandwidth(const struct bw_calcs_input_dceip *dceip,
++ const struct bw_calcs_input_vbios *vbios,
++ const struct bw_calcs_input_mode_data_internal *mode_data,
++ struct bw_results_internal *results)
++{
++ const struct bw_fixed pixels_per_chunk = int_to_fixed(512);
++ const struct bw_fixed max_chunks_non_fbc_mode = int_to_fixed(16);
++ const uint32_t high = 2;
++ const uint32_t mid = 1;
++ const uint32_t low = 0;
++
++ uint32_t i, j, k;
++ struct bw_fixed yclk[3];
++ struct bw_fixed sclk[3];
++ bool d0_underlay_enable;
++ bool d1_underlay_enable;
++ enum bw_defines v_filter_init_mode[maximum_number_of_surfaces];
++ enum bw_defines tiling_mode[maximum_number_of_surfaces];
++ enum bw_stereo_mode stereo_mode[maximum_number_of_surfaces];
++ enum bw_defines surface_type[maximum_number_of_surfaces];
++ enum bw_defines voltage;
++ enum bw_defines mode_background_color;
++ enum bw_defines mode_font_color;
++ enum bw_defines mode_pattern;
++ enum bw_defines sclk_message;
++ enum bw_defines yclk_message;
++ enum bw_defines pipe_check;
++ enum bw_defines hsr_check;
++ enum bw_defines vsr_check;
++ enum bw_defines lb_size_check;
++ enum bw_defines fbc_check;
++ enum bw_defines rotation_check;
++ enum bw_defines mode_check;
++ uint32_t y_clk_level;
++ uint32_t sclk_level;
++ yclk[high] = vbios->high_yclk;
++ yclk[mid] = vbios->high_yclk;
++ yclk[low] = vbios->low_yclk;
++ sclk[high] = vbios->high_sclk;
++ sclk[mid] = vbios->mid_sclk;
++ sclk[low] = vbios->low_sclk;
++ if (mode_data->d0_underlay_mode == ul_none) {
++ d0_underlay_enable = false;
++ } else {
++ d0_underlay_enable = true;
++ }
++ if (mode_data->d1_underlay_mode == ul_none) {
++ d1_underlay_enable = false;
++ } else {
++ d1_underlay_enable = true;
++ }
++ results->number_of_underlay_surfaces = int_to_fixed(
++ d0_underlay_enable + d1_underlay_enable);
++ if (mode_data->underlay_surface_type == yuv_420) {
++ surface_type[0] = def_underlay420_luma;
++ surface_type[2] = def_underlay420_luma;
++ results->bytes_per_pixel[0] = int_to_fixed(1);
++ results->bytes_per_pixel[2] = int_to_fixed(1);
++ surface_type[1] = def_underlay420_chroma;
++ surface_type[3] = def_underlay420_chroma;
++ results->bytes_per_pixel[1] = int_to_fixed(2);
++ results->bytes_per_pixel[3] = int_to_fixed(2);
++ results->lb_size_per_component[0] =
++ dceip->underlay420_luma_lb_size_per_component;
++ results->lb_size_per_component[1] =
++ dceip->underlay420_chroma_lb_size_per_component;
++ results->lb_size_per_component[2] =
++ dceip->underlay420_luma_lb_size_per_component;
++ results->lb_size_per_component[3] =
++ dceip->underlay420_chroma_lb_size_per_component;
++ } else if (mode_data->underlay_surface_type == yuv_422) {
++ surface_type[0] = def_underlay422;
++ surface_type[2] = def_underlay422;
++ results->bytes_per_pixel[0] = int_to_fixed(2);
++ results->bytes_per_pixel[2] = int_to_fixed(2);
++ results->lb_size_per_component[0] =
++ dceip->underlay422_lb_size_per_component;
++ results->lb_size_per_component[2] =
++ dceip->underlay422_lb_size_per_component;
++ } else {
++ surface_type[0] = def_underlay444;
++ surface_type[2] = def_underlay444;
++ results->bytes_per_pixel[0] = int_to_fixed(4);
++ results->bytes_per_pixel[2] = int_to_fixed(4);
++ results->lb_size_per_component[0] =
++ dceip->lb_size_per_component444;
++ results->lb_size_per_component[2] =
++ dceip->lb_size_per_component444;
++ }
++ if (d0_underlay_enable) {
++ if (mode_data->underlay_surface_type == yuv_420) {
++ results->enable[0] = true;
++ results->enable[1] = true;
++ } else {
++ results->enable[0] = true;
++ results->enable[1] = false;
++ }
++ } else {
++ results->enable[0] = false;
++ results->enable[1] = false;
++ }
++ if (d1_underlay_enable) {
++ if (mode_data->underlay_surface_type == yuv_420) {
++ results->enable[2] = true;
++ results->enable[3] = true;
++ } else {
++ results->enable[2] = true;
++ results->enable[3] = false;
++ }
++ } else {
++ results->enable[2] = false;
++ results->enable[3] = false;
++ }
++
++ results->use_alpha[0] = false;
++ results->use_alpha[1] = false;
++ results->use_alpha[2] = false;
++ results->use_alpha[3] = false;
++ results->scatter_gather_enable_for_pipe[0] =
++ vbios->scatter_gather_enable;
++ results->scatter_gather_enable_for_pipe[1] =
++ vbios->scatter_gather_enable;
++ results->scatter_gather_enable_for_pipe[2] =
++ vbios->scatter_gather_enable;
++ results->scatter_gather_enable_for_pipe[3] =
++ vbios->scatter_gather_enable;
++ results->interlace_mode[0] = mode_data->graphics_interlace_mode;
++ results->interlace_mode[1] = mode_data->graphics_interlace_mode;
++ results->interlace_mode[2] = mode_data->graphics_interlace_mode;
++ results->interlace_mode[3] = mode_data->graphics_interlace_mode;
++ results->h_total[0] = mode_data->d0_htotal;
++ results->h_total[1] = mode_data->d0_htotal;
++ results->h_total[2] = mode_data->d1_htotal;
++ results->h_total[3] = mode_data->d1_htotal;
++ results->pixel_rate[0] = mode_data->d0_pixel_rate;
++ results->pixel_rate[1] = mode_data->d0_pixel_rate;
++ results->pixel_rate[2] = mode_data->d1_pixel_rate;
++ results->pixel_rate[3] = mode_data->d1_pixel_rate;
++ results->src_width[0] = mode_data->underlay_src_width;
++ results->src_width[1] = mode_data->underlay_src_width;
++ results->src_width[2] = mode_data->underlay_src_width;
++ results->src_width[3] = mode_data->underlay_src_width;
++ results->src_height[0] = mode_data->underlay_src_height;
++ results->src_height[1] = mode_data->underlay_src_height;
++ results->src_height[2] = mode_data->underlay_src_height;
++ results->src_height[3] = mode_data->underlay_src_height;
++ results->pitch_in_pixels[0] = mode_data->underlay_pitch_in_pixels;
++ results->pitch_in_pixels[1] = mode_data->underlay_pitch_in_pixels;
++ results->pitch_in_pixels[2] = mode_data->underlay_pitch_in_pixels;
++ results->pitch_in_pixels[3] = mode_data->underlay_pitch_in_pixels;
++ results->scale_ratio[0] = mode_data->d0_underlay_scale_ratio;
++ results->scale_ratio[1] = mode_data->d0_underlay_scale_ratio;
++ results->scale_ratio[2] = mode_data->d1_underlay_scale_ratio;
++ results->scale_ratio[3] = mode_data->d1_underlay_scale_ratio;
++ results->h_taps[0] = mode_data->underlay_htaps;
++ results->h_taps[1] = mode_data->underlay_htaps;
++ results->h_taps[2] = mode_data->underlay_htaps;
++ results->h_taps[3] = mode_data->underlay_htaps;
++ results->v_taps[0] = mode_data->underlay_vtaps;
++ results->v_taps[1] = mode_data->underlay_vtaps;
++ results->v_taps[2] = mode_data->underlay_vtaps;
++ results->v_taps[3] = mode_data->underlay_vtaps;
++ results->rotation_angle[0] = mode_data->underlay_rotation_angle;
++ results->rotation_angle[1] = mode_data->underlay_rotation_angle;
++ results->rotation_angle[2] = mode_data->underlay_rotation_angle;
++ results->rotation_angle[3] = mode_data->underlay_rotation_angle;
++ if (mode_data->underlay_tiling_mode == linear) {
++ tiling_mode[0] = def_linear;
++ tiling_mode[1] = def_linear;
++ tiling_mode[2] = def_linear;
++ tiling_mode[3] = def_linear;
++ } else {
++ tiling_mode[0] = def_landscape;
++ tiling_mode[1] = def_landscape;
++ tiling_mode[2] = def_landscape;
++ tiling_mode[3] = def_landscape;
++ }
++ stereo_mode[0] = mode_data->underlay_stereo_mode;
++ stereo_mode[1] = mode_data->underlay_stereo_mode;
++ stereo_mode[2] = mode_data->underlay_stereo_mode;
++ stereo_mode[3] = mode_data->underlay_stereo_mode;
++ results->lb_bpc[0] = mode_data->underlay_lb_bpc;
++ results->lb_bpc[1] = mode_data->underlay_lb_bpc;
++ results->lb_bpc[2] = mode_data->underlay_lb_bpc;
++ results->lb_bpc[3] = mode_data->underlay_lb_bpc;
++ results->compression_rate[0] = int_to_fixed(1);
++ results->compression_rate[1] = int_to_fixed(1);
++ results->compression_rate[2] = int_to_fixed(1);
++ results->compression_rate[3] = int_to_fixed(1);
++ results->access_one_channel_only[0] = false;
++ results->access_one_channel_only[1] = false;
++ results->access_one_channel_only[2] = false;
++ results->access_one_channel_only[3] = false;
++ results->cursor_width_pixels[0] = int_to_fixed(0);
++ results->cursor_width_pixels[1] = int_to_fixed(0);
++ results->cursor_width_pixels[2] = int_to_fixed(0);
++ results->cursor_width_pixels[3] = int_to_fixed(0);
++ for (i = 4; i <= maximum_number_of_surfaces - 3; i += 1) {
++ if (i < mode_data->number_of_displays + 4) {
++ if (i == 4 && mode_data->d0_underlay_mode == ul_only) {
++ results->enable[i] = false;
++ results->use_alpha[i] = false;
++ } else if (i == 4
++ && mode_data->d0_underlay_mode == ul_blend) {
++ results->enable[i] = true;
++ results->use_alpha[i] = true;
++ } else if (i == 4) {
++ results->enable[i] = true;
++ results->use_alpha[i] = false;
++ } else if (i == 5
++ && mode_data->d1_underlay_mode == ul_only) {
++ results->enable[i] = false;
++ results->use_alpha[i] = false;
++ } else if (i == 5
++ && mode_data->d1_underlay_mode == ul_blend) {
++ results->enable[i] = true;
++ results->use_alpha[i] = true;
++ } else {
++ results->enable[i] = true;
++ results->use_alpha[i] = false;
++ }
++ } else {
++ results->enable[i] = false;
++ results->use_alpha[i] = false;
++ }
++ results->scatter_gather_enable_for_pipe[i] =
++ vbios->scatter_gather_enable;
++ surface_type[i] = def_graphics;
++ results->lb_size_per_component[i] =
++ dceip->lb_size_per_component444;
++ results->bytes_per_pixel[i] =
++ mode_data->graphics_bytes_per_pixel;
++ results->interlace_mode[i] = mode_data->graphics_interlace_mode;
++ results->h_taps[i] = mode_data->graphics_htaps;
++ results->v_taps[i] = mode_data->graphics_vtaps;
++ results->rotation_angle[i] = mode_data->graphics_rotation_angle;
++ if (mode_data->graphics_tiling_mode == linear) {
++ tiling_mode[i] = def_linear;
++ } else if (equ(mode_data->graphics_rotation_angle,
++ int_to_fixed(0))
++ || equ(mode_data->graphics_rotation_angle,
++ int_to_fixed(180))) {
++ tiling_mode[i] = def_landscape;
++ } else {
++ tiling_mode[i] = def_portrait;
++ }
++ results->lb_bpc[i] = mode_data->graphics_lb_bpc;
++ if (i == 4) {
++ /* todo: check original d0_underlay_mode comparison, possible bug there*/
++ if (mode_data->d0_fbc_enable
++ && (dceip->argb_compression_support
++ || mode_data->d0_underlay_mode
++ != ul_blend)) {
++ results->compression_rate[i] =
++ vbios->average_compression_rate;
++ results->access_one_channel_only[i] =
++ mode_data->d0_lpt_enable;
++ } else {
++ results->compression_rate[i] = int_to_fixed(1);
++ results->access_one_channel_only[i] = false;
++ }
++ results->h_total[i] = mode_data->d0_htotal;
++ results->pixel_rate[i] = mode_data->d0_pixel_rate;
++ results->src_width[i] =
++ mode_data->d0_graphics_src_width;
++ results->src_height[i] =
++ mode_data->d0_graphics_src_height;
++ results->pitch_in_pixels[i] =
++ mode_data->d0_graphics_src_width;
++ results->scale_ratio[i] =
++ mode_data->d0_graphics_scale_ratio;
++ stereo_mode[i] = mode_data->d0_graphics_stereo_mode;
++ } else if (i == 5) {
++ results->compression_rate[i] = int_to_fixed(1);
++ results->access_one_channel_only[i] = false;
++ results->h_total[i] = mode_data->d1_htotal;
++ results->pixel_rate[i] = mode_data->d1_pixel_rate;
++ results->src_width[i] =
++ mode_data->d1_graphics_src_width;
++ results->src_height[i] =
++ mode_data->d1_graphics_src_height;
++ results->pitch_in_pixels[i] =
++ mode_data->d1_graphics_src_width;
++ results->scale_ratio[i] =
++ mode_data->d1_graphics_scale_ratio;
++ stereo_mode[i] = mode_data->d1_graphics_stereo_mode;
++ } else {
++ results->compression_rate[i] = int_to_fixed(1);
++ results->access_one_channel_only[i] = false;
++ results->h_total[i] = mode_data->d2_htotal;
++ results->pixel_rate[i] = mode_data->d2_pixel_rate;
++ results->src_width[i] =
++ mode_data->d2_graphics_src_width;
++ results->src_height[i] =
++ mode_data->d2_graphics_src_height;
++ results->pitch_in_pixels[i] =
++ mode_data->d2_graphics_src_width;
++ results->scale_ratio[i] =
++ mode_data->d2_graphics_scale_ratio;
++ stereo_mode[i] = mode_data->d2_graphics_stereo_mode;
++ }
++ results->cursor_width_pixels[i] = vbios->cursor_width;
++ }
++ results->scatter_gather_enable_for_pipe[maximum_number_of_surfaces - 2] =
++ false;
++ results->scatter_gather_enable_for_pipe[maximum_number_of_surfaces - 1] =
++ false;
++ if (mode_data->d1_display_write_back_dwb_enable == true) {
++ results->enable[maximum_number_of_surfaces - 2] = true;
++ results->enable[maximum_number_of_surfaces - 1] = true;
++ } else {
++ results->enable[maximum_number_of_surfaces - 2] = false;
++ results->enable[maximum_number_of_surfaces - 1] = false;
++ }
++ surface_type[maximum_number_of_surfaces - 2] =
++ def_display_write_back420_luma;
++ surface_type[maximum_number_of_surfaces - 1] =
++ def_display_write_back420_chroma;
++ results->lb_size_per_component[maximum_number_of_surfaces - 2] =
++ dceip->underlay420_luma_lb_size_per_component;
++ results->lb_size_per_component[maximum_number_of_surfaces - 1] =
++ dceip->underlay420_chroma_lb_size_per_component;
++ results->bytes_per_pixel[maximum_number_of_surfaces - 2] = int_to_fixed(
++ 1);
++ results->bytes_per_pixel[maximum_number_of_surfaces - 1] = int_to_fixed(
++ 2);
++ results->interlace_mode[maximum_number_of_surfaces - 2] =
++ mode_data->graphics_interlace_mode;
++ results->interlace_mode[maximum_number_of_surfaces - 1] =
++ mode_data->graphics_interlace_mode;
++ results->h_taps[maximum_number_of_surfaces - 2] = int_to_fixed(1);
++ results->h_taps[maximum_number_of_surfaces - 1] = int_to_fixed(1);
++ results->v_taps[maximum_number_of_surfaces - 2] = int_to_fixed(1);
++ results->v_taps[maximum_number_of_surfaces - 1] = int_to_fixed(1);
++ results->rotation_angle[maximum_number_of_surfaces - 2] = int_to_fixed(
++ 0);
++ results->rotation_angle[maximum_number_of_surfaces - 1] = int_to_fixed(
++ 0);
++ tiling_mode[maximum_number_of_surfaces - 2] = def_linear;
++ tiling_mode[maximum_number_of_surfaces - 1] = def_linear;
++ results->lb_bpc[maximum_number_of_surfaces - 2] = int_to_fixed(8);
++ results->lb_bpc[maximum_number_of_surfaces - 1] = int_to_fixed(8);
++ results->compression_rate[maximum_number_of_surfaces - 2] =
++ int_to_fixed(1);
++ results->compression_rate[maximum_number_of_surfaces - 1] =
++ int_to_fixed(1);
++ results->access_one_channel_only[maximum_number_of_surfaces - 2] =
++ false;
++ results->access_one_channel_only[maximum_number_of_surfaces - 1] =
++ false;
++ results->h_total[maximum_number_of_surfaces - 2] = mode_data->d1_htotal;
++ results->h_total[maximum_number_of_surfaces - 1] = mode_data->d1_htotal;
++ results->pixel_rate[maximum_number_of_surfaces - 2] =
++ mode_data->d1_pixel_rate;
++ results->pixel_rate[maximum_number_of_surfaces - 1] =
++ mode_data->d1_pixel_rate;
++ results->src_width[maximum_number_of_surfaces - 2] =
++ mode_data->d1_graphics_src_width;
++ results->src_width[maximum_number_of_surfaces - 1] =
++ mode_data->d1_graphics_src_width;
++ results->src_height[maximum_number_of_surfaces - 2] =
++ mode_data->d1_graphics_src_height;
++ results->src_height[maximum_number_of_surfaces - 1] =
++ mode_data->d1_graphics_src_height;
++ results->pitch_in_pixels[maximum_number_of_surfaces - 2] =
++ mode_data->d1_graphics_src_width;
++ results->pitch_in_pixels[maximum_number_of_surfaces - 1] =
++ mode_data->d1_graphics_src_width;
++ results->scale_ratio[maximum_number_of_surfaces - 2] = int_to_fixed(1);
++ results->scale_ratio[maximum_number_of_surfaces - 1] = int_to_fixed(1);
++ stereo_mode[maximum_number_of_surfaces - 2] = mono;
++ stereo_mode[maximum_number_of_surfaces - 1] = mono;
++ results->cursor_width_pixels[maximum_number_of_surfaces - 2] =
++ int_to_fixed(0);
++ results->cursor_width_pixels[maximum_number_of_surfaces - 1] =
++ int_to_fixed(0);
++ results->use_alpha[maximum_number_of_surfaces - 2] = false;
++ results->use_alpha[maximum_number_of_surfaces - 1] = false;
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (equ(results->scale_ratio[i], int_to_fixed(1))
++ && surface_type[i] == def_graphics
++ && stereo_mode[i] == mono
++ && results->interlace_mode[i] == false) {
++ results->h_taps[i] = int_to_fixed(1);
++ results->v_taps[i] = int_to_fixed(1);
++ }
++ if (surface_type[i] == def_display_write_back420_chroma
++ || surface_type[i] == def_underlay420_chroma) {
++ results->pitch_in_pixels_after_surface_type[i] =
++ bw_div(results->pitch_in_pixels[i],
++ int_to_fixed(2));
++ results->src_width_after_surface_type = bw_div(
++ results->src_width[i], int_to_fixed(2));
++ results->src_height_after_surface_type = bw_div(
++ results->src_height[i],
++ int_to_fixed(2));
++ results->hsr_after_surface_type = bw_div(
++ results->scale_ratio[i],
++ int_to_fixed(2));
++ results->vsr_after_surface_type = bw_div(
++ results->scale_ratio[i],
++ int_to_fixed(2));
++ } else {
++ results->pitch_in_pixels_after_surface_type[i] =
++ results->pitch_in_pixels[i];
++ results->src_width_after_surface_type =
++ results->src_width[i];
++ results->src_height_after_surface_type =
++ results->src_height[i];
++ results->hsr_after_surface_type =
++ results->scale_ratio[i];
++ results->vsr_after_surface_type =
++ results->scale_ratio[i];
++ }
++ if ((equ(results->rotation_angle[i], int_to_fixed(90))
++ || equ(results->rotation_angle[i],
++ int_to_fixed(270)))
++ && surface_type[i] != def_graphics) {
++ results->src_width_after_rotation =
++ results->src_height_after_surface_type;
++ results->src_height_after_rotation =
++ results->src_width_after_surface_type;
++ results->hsr_after_rotation =
++ results->vsr_after_surface_type;
++ results->vsr_after_rotation =
++ results->hsr_after_surface_type;
++ } else {
++ results->src_width_after_rotation =
++ results->src_width_after_surface_type;
++ results->src_height_after_rotation =
++ results->src_height_after_surface_type;
++ results->hsr_after_rotation =
++ results->hsr_after_surface_type;
++ results->vsr_after_rotation =
++ results->vsr_after_surface_type;
++ }
++ if (stereo_mode[i] == top_bottom) {
++ results->source_width_pixels[i] =
++ results->src_width_after_rotation;
++ results->source_height_pixels = mul(
++ int_to_fixed(2),
++ results->src_height_after_rotation);
++ results->hsr_after_stereo =
++ results->hsr_after_rotation;
++ results->vsr_after_stereo = mul(
++ results->vsr_after_rotation,
++ int_to_fixed(1)); //todo: confirm correctness
++ } else if (stereo_mode[i] == side_by_side) {
++ results->source_width_pixels[i] = mul(
++ int_to_fixed(2),
++ results->src_width_after_rotation);
++ results->source_height_pixels =
++ results->src_height_after_rotation;
++ results->hsr_after_stereo = mul(
++ results->hsr_after_rotation,
++ int_to_fixed(1)); //todo: confirm correctness
++ results->vsr_after_stereo =
++ results->vsr_after_rotation;
++ } else {
++ results->source_width_pixels[i] =
++ results->src_width_after_rotation;
++ results->source_height_pixels =
++ results->src_height_after_rotation;
++ results->hsr_after_stereo =
++ results->hsr_after_rotation;
++ results->vsr_after_stereo =
++ results->vsr_after_rotation;
++ }
++ results->hsr[i] = results->hsr_after_stereo;
++ if (results->interlace_mode[i]) {
++ results->vsr[i] = mul(results->vsr_after_stereo,
++ int_to_fixed(2));
++ } else {
++ results->vsr[i] = results->vsr_after_stereo;
++ }
++ if (mode_data->panning_and_bezel_adjustment != none) {
++ results->source_width_rounded_up_to_chunks[i] =
++ add(
++ bw_floor(
++ sub(
++ results->source_width_pixels[i],
++ int_to_fixed(
++ 1)),
++ int_to_fixed(128)),
++ int_to_fixed(256));
++ } else {
++ results->source_width_rounded_up_to_chunks[i] =
++ bw_ceil(results->source_width_pixels[i],
++ int_to_fixed(128));
++ }
++ results->source_height_rounded_up_to_chunks[i] =
++ results->source_height_pixels;
++ }
++ }
++ if (geq(dceip->number_of_graphics_pipes,
++ int_to_fixed(mode_data->number_of_displays))
++ && geq(dceip->number_of_underlay_pipes,
++ results->number_of_underlay_surfaces)
++ && !(dceip->display_write_back_supported == false
++ && mode_data->d1_display_write_back_dwb_enable == true)) {
++ pipe_check = def_ok;
++ } else {
++ pipe_check = def_notok;
++ }
++ hsr_check = def_ok;
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (neq(results->hsr[i], int_to_fixed(1))) {
++ if (gtn(results->hsr[i], int_to_fixed(4))) {
++ hsr_check = def_hsr_more_than_4;
++ } else {
++ if (gtn(results->hsr[i],
++ results->h_taps[i])) {
++ hsr_check =
++ def_hsr_more_than_htaps;
++ } else {
++ if (dceip->pre_downscaler_enabled
++ == true
++ && gtn(results->hsr[i],
++ int_to_fixed(1))
++ && leq(results->hsr[i],
++ bw_ceil(
++ bw_div(
++ results->h_taps[i],
++ int_to_fixed(
++ 4)),
++ int_to_fixed(
++ 1)))) {
++ hsr_check =
++ def_ceil_htaps_div_4_more_or_eq_hsr;
++ }
++ }
++ }
++ }
++ }
++ }
++ vsr_check = def_ok;
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (neq(results->vsr[i], int_to_fixed(1))) {
++ if (gtn(results->vsr[i], int_to_fixed(4))) {
++ vsr_check = def_vsr_more_than_4;
++ } else {
++ if (gtn(results->vsr[i],
++ results->v_taps[i])) {
++ vsr_check =
++ def_vsr_more_than_vtaps;
++ }
++ }
++ }
++ }
++ }
++ lb_size_check = def_ok;
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if ((dceip->pre_downscaler_enabled
++ && gtn(results->hsr[i], int_to_fixed(1)))) {
++ results->source_width_in_lb = bw_div(
++ results->source_width_pixels[i],
++ results->hsr[i]);
++ } else {
++ results->source_width_in_lb =
++ results->source_width_pixels[i];
++ }
++ if (equ(results->lb_bpc[i], int_to_fixed(8))) {
++ results->lb_line_pitch =
++ bw_ceil(
++ mul(frc_to_fixed(24011, 3000),
++ bw_ceil(
++ results->source_width_in_lb,
++ int_to_fixed(
++ 8))),
++ int_to_fixed(48));
++ } else if (equ(results->lb_bpc[i], int_to_fixed(10))) {
++ results->lb_line_pitch =
++ bw_ceil(
++ mul(frc_to_fixed(30023, 3000),
++ bw_ceil(
++ results->source_width_in_lb,
++ int_to_fixed(
++ 8))),
++ int_to_fixed(48));
++ } else
++ // case else
++ {
++ results->lb_line_pitch = bw_ceil(
++ mul(results->source_width_in_lb,
++ results->lb_bpc[i]),
++ int_to_fixed(48));
++ }
++ results->lb_partitions[i] = bw_floor(
++ bw_div(results->lb_size_per_component[i],
++ results->lb_line_pitch),
++ int_to_fixed(1));
++ if ((surface_type[i] != def_graphics
++ || dceip->graphics_lb_nodownscaling_multi_line_prefetching
++ == true)) {
++ results->lb_partitions_max[i] = int_to_fixed(
++ 10);
++ } else {
++ results->lb_partitions_max[i] = int_to_fixed(7);
++ }
++ results->lb_partitions[i] = bw_min(
++ results->lb_partitions_max[i],
++ results->lb_partitions[i]);
++ if (gtn(add(results->v_taps[i], int_to_fixed(1)),
++ results->lb_partitions[i])) {
++ lb_size_check = def_notok;
++ }
++ }
++ }
++ if (mode_data->d0_fbc_enable
++ && (equ(mode_data->graphics_rotation_angle, int_to_fixed(90))
++ || equ(mode_data->graphics_rotation_angle,
++ int_to_fixed(270))
++ || mode_data->d0_graphics_stereo_mode != mono
++ || neq(mode_data->graphics_bytes_per_pixel,
++ int_to_fixed(4)))) {
++ fbc_check = def_invalid_rotation_or_bpp_or_stereo;
++ } else {
++ fbc_check = def_ok;
++ }
++ rotation_check = def_ok;
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if ((equ(results->rotation_angle[i], int_to_fixed(90))
++ || equ(results->rotation_angle[i],
++ int_to_fixed(270)))
++ && (tiling_mode[i] == def_linear
++ || stereo_mode[i] != mono)) {
++ rotation_check =
++ def_invalid_linear_or_stereo_mode;
++ }
++ }
++ }
++ if (pipe_check == def_ok && hsr_check == def_ok && vsr_check == def_ok
++ && lb_size_check == def_ok && fbc_check == def_ok
++ && rotation_check == def_ok) {
++ mode_check = def_ok;
++ } else {
++ mode_check = def_notok;
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if ((equ(results->rotation_angle[i], int_to_fixed(90))
++ || equ(results->rotation_angle[i],
++ int_to_fixed(270)))) {
++ if ((tiling_mode[i] == def_portrait)) {
++ results->orthogonal_rotation[i] = false;
++ } else {
++ results->orthogonal_rotation[i] = true;
++ }
++ } else {
++ if ((tiling_mode[i] == def_portrait)) {
++ results->orthogonal_rotation[i] = true;
++ } else {
++ results->orthogonal_rotation[i] = false;
++ }
++ }
++ if (equ(results->rotation_angle[i], int_to_fixed(90))
++ || equ(results->rotation_angle[i],
++ int_to_fixed(270))) {
++ results->underlay_maximum_source_efficient_for_tiling =
++ dceip->underlay_maximum_height_efficient_for_tiling;
++ } else {
++ results->underlay_maximum_source_efficient_for_tiling =
++ dceip->underlay_maximum_width_efficient_for_tiling;
++ }
++ if (equ(dceip->de_tiling_buffer, int_to_fixed(0))) {
++ if (surface_type[i]
++ == def_display_write_back420_luma
++ || surface_type[i]
++ == def_display_write_back420_chroma) {
++ results->bytes_per_request[i] =
++ int_to_fixed(64);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(64);
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(1);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(1);
++ } else if (tiling_mode[i] == def_linear) {
++ results->bytes_per_request[i] =
++ int_to_fixed(64);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(64);
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(2);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(2);
++ } else {
++ if (surface_type[i] == def_graphics
++ || (gtn(
++ results->source_width_rounded_up_to_chunks[i],
++ bw_ceil(
++ results->underlay_maximum_source_efficient_for_tiling,
++ int_to_fixed(
++ 256))))) {
++ if (equ(
++ results->bytes_per_pixel[i],
++ int_to_fixed(8))) {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(2);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(2);
++ if (results->orthogonal_rotation[i]) {
++ results->bytes_per_request[i] =
++ int_to_fixed(
++ 32);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(
++ 32);
++ } else {
++ results->bytes_per_request[i] =
++ int_to_fixed(
++ 64);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(
++ 64);
++ }
++ } else if (equ(
++ results->bytes_per_pixel[i],
++ int_to_fixed(4))) {
++ if (results->orthogonal_rotation[i]) {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(
++ 2);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(
++ 2);
++ results->bytes_per_request[i] =
++ int_to_fixed(
++ 32);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(
++ 16);
++ } else {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(
++ 2);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(
++ 2);
++ results->bytes_per_request[i] =
++ int_to_fixed(
++ 64);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(
++ 64);
++ }
++ } else if (equ(
++ results->bytes_per_pixel[i],
++ int_to_fixed(2))) {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(2);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(2);
++ results->bytes_per_request[i] =
++ int_to_fixed(
++ 32);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(
++ 32);
++ } else {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(2);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(2);
++ results->bytes_per_request[i] =
++ int_to_fixed(
++ 32);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(
++ 16);
++ }
++ } else {
++ results->bytes_per_request[i] =
++ int_to_fixed(64);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(64);
++ if (results->orthogonal_rotation[i]) {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(8);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(4);
++ } else {
++ if (equ(
++ results->bytes_per_pixel[i],
++ int_to_fixed(
++ 4))) {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(
++ 2);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(
++ 2);
++ } else if (equ(
++ results->bytes_per_pixel[i],
++ int_to_fixed(
++ 2))) {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(
++ 4);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(
++ 4);
++ } else {
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(
++ 8);
++ results->latency_hiding_lines[i] =
++ int_to_fixed(
++ 4);
++ }
++ }
++ }
++ }
++ } else {
++ results->bytes_per_request[i] = int_to_fixed(
++ 256);
++ results->useful_bytes_per_request[i] =
++ int_to_fixed(256);
++ results->lines_interleaved_in_mem_access[i] =
++ int_to_fixed(4);
++ results->latency_hiding_lines[i] = int_to_fixed(
++ 4);
++ }
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->v_filter_init[i] =
++ bw_floor(
++ bw_div(
++ (add(
++ add(
++ add(
++ results->vsr[i],
++ results->v_taps[i]),
++ mul(
++ mul(
++ frc_to_fixed(
++ 1,
++ 2),
++ results->vsr[i]),
++ int_to_fixed(
++ results->interlace_mode[i]))),
++ int_to_fixed(1))),
++ int_to_fixed(2)),
++ int_to_fixed(1));
++ if (mode_data->panning_and_bezel_adjustment
++ == any_lines) {
++ results->v_filter_init[i] = add(
++ results->v_filter_init[i],
++ int_to_fixed(1));
++ }
++ if (stereo_mode[i] == top_bottom) {
++ v_filter_init_mode[i] = def_manual;
++ results->v_filter_init[i] = bw_min(
++ results->v_filter_init[i],
++ int_to_fixed(4));
++ } else {
++ v_filter_init_mode[i] = def_auto;
++ }
++ if (stereo_mode[i] == top_bottom) {
++ results->num_lines_at_frame_start =
++ int_to_fixed(1);
++ } else {
++ results->num_lines_at_frame_start =
++ int_to_fixed(3);
++ }
++ if ((gtn(results->vsr[i], int_to_fixed(1))
++ && surface_type[i] == def_graphics)
++ || mode_data->panning_and_bezel_adjustment
++ == any_lines) {
++ results->line_buffer_prefetch[i] = int_to_fixed(
++ 0);
++ } else if ((((dceip->underlay_downscale_prefetch_enabled
++ == true && surface_type[i] != def_graphics)
++ || surface_type[i] == def_graphics)
++ && (gtn(results->lb_partitions[i],
++ add(results->v_taps[i],
++ bw_ceil(results->vsr[i],
++ int_to_fixed(1))))))) {
++ results->line_buffer_prefetch[i] = int_to_fixed(
++ 1);
++ } else {
++ results->line_buffer_prefetch[i] = int_to_fixed(
++ 0);
++ }
++ results->lb_lines_in_per_line_out_in_beginning_of_frame[i] =
++ bw_div(
++ bw_ceil(results->v_filter_init[i],
++ dceip->lines_interleaved_into_lb),
++ results->num_lines_at_frame_start);
++ if (equ(results->line_buffer_prefetch[i],
++ int_to_fixed(1))) {
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i] =
++ bw_max(int_to_fixed(1),
++ results->vsr[i]);
++ } else if (leq(results->vsr[i], int_to_fixed(1))) {
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i] =
++ int_to_fixed(1);
++ } else if (leq(results->vsr[i],
++ bw_div(int_to_fixed(4), int_to_fixed(3)))) {
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i] =
++ bw_div(int_to_fixed(4), int_to_fixed(3));
++ } else if (leq(results->vsr[i],
++ bw_div(int_to_fixed(6), int_to_fixed(4)))) {
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i] =
++ bw_div(int_to_fixed(6), int_to_fixed(4));
++ } else if (leq(results->vsr[i], int_to_fixed(2))) {
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i] =
++ int_to_fixed(2);
++ } else if (leq(results->vsr[i], int_to_fixed(3))) {
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i] =
++ int_to_fixed(3);
++ } else {
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i] =
++ int_to_fixed(4);
++ }
++ if (equ(results->line_buffer_prefetch[i],
++ int_to_fixed(1))
++ || equ(
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i],
++ int_to_fixed(2))
++ || equ(
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i],
++ int_to_fixed(4))) {
++ results->horizontal_blank_and_chunk_granularity_factor[i] =
++ int_to_fixed(1);
++ } else {
++ results->horizontal_blank_and_chunk_granularity_factor[i] =
++ bw_div(results->h_total[i],
++ (bw_div(
++ (add(
++ results->h_total[i],
++ bw_div(
++ (sub(
++ results->source_width_pixels[i],
++ dceip->chunk_width)),
++ results->hsr[i]))),
++ int_to_fixed(2))));
++ }
++ results->request_bandwidth[i] =
++ bw_div(
++ mul(
++ bw_div(
++ mul(
++ bw_div(
++ mul(
++ bw_max(
++ results->lb_lines_in_per_line_out_in_beginning_of_frame[i],
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i]),
++ results->source_width_rounded_up_to_chunks[i]),
++ (bw_div(
++ results->h_total[i],
++ results->pixel_rate[i]))),
++ results->bytes_per_pixel[i]),
++ results->useful_bytes_per_request[i]),
++ results->lines_interleaved_in_mem_access[i]),
++ results->latency_hiding_lines[i]);
++ results->display_bandwidth[i] = mul(
++ results->request_bandwidth[i],
++ results->bytes_per_request[i]);
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i] == def_display_write_back420_luma) {
++ results->data_buffer_size[i] =
++ dceip->display_write_back420_luma_mcifwr_buffer_size;
++ } else if (surface_type[i]
++ == def_display_write_back420_chroma) {
++ results->data_buffer_size[i] =
++ dceip->display_write_back420_chroma_mcifwr_buffer_size;
++ } else if (surface_type[i] == def_underlay420_luma) {
++ results->data_buffer_size[i] =
++ dceip->underlay_luma_dmif_size;
++ } else if (surface_type[i] == def_underlay420_chroma) {
++ results->data_buffer_size[i] = bw_div(
++ dceip->underlay_chroma_dmif_size,
++ int_to_fixed(2));
++ } else if (surface_type[i] == def_underlay422
++ || surface_type[i] == def_underlay444) {
++ if (results->orthogonal_rotation[i] == false) {
++ results->data_buffer_size[i] =
++ dceip->underlay_luma_dmif_size;
++ } else {
++ results->data_buffer_size[i] =
++ add(
++ dceip->underlay_luma_dmif_size,
++ dceip->underlay_chroma_dmif_size);
++ }
++ } else {
++ if (mode_data->number_of_displays == 1
++ && equ(dceip->de_tiling_buffer,
++ int_to_fixed(0))) {
++ if (mode_data->d0_fbc_enable) {
++ results->data_buffer_size[i] =
++ mul(
++ dceip->max_dmif_buffer_allocated,
++ dceip->graphics_dmif_size);
++ } else {
++ results->data_buffer_size[i] =
++ mul(
++ mul(
++ max_chunks_non_fbc_mode,
++ pixels_per_chunk),
++ results->bytes_per_pixel[i]);
++ }
++ } else {
++ results->data_buffer_size[i] =
++ dceip->graphics_dmif_size;
++ }
++ }
++ if (surface_type[i] == def_display_write_back420_luma
++ || surface_type[i]
++ == def_display_write_back420_chroma) {
++ results->memory_chunk_size_in_bytes[i] =
++ int_to_fixed(1024);
++ results->pipe_chunk_size_in_bytes[i] =
++ int_to_fixed(1024);
++ } else {
++ results->memory_chunk_size_in_bytes[i] =
++ mul(
++ mul(dceip->chunk_width,
++ results->lines_interleaved_in_mem_access[i]),
++ results->bytes_per_pixel[i]);
++ results->pipe_chunk_size_in_bytes[i] =
++ mul(
++ mul(dceip->chunk_width,
++ dceip->lines_interleaved_into_lb),
++ results->bytes_per_pixel[i]);
++ }
++ }
++ }
++ results->min_dmif_size_in_time = int_to_fixed(9999);
++ results->min_mcifwr_size_in_time = int_to_fixed(9999);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i] != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma) {
++ if (ltn(
++ bw_div(
++ bw_div(
++ mul(
++ results->data_buffer_size[i],
++ results->bytes_per_request[i]),
++ results->useful_bytes_per_request[i]),
++ results->display_bandwidth[i]),
++ results->min_dmif_size_in_time)) {
++ results->min_dmif_size_in_time =
++ bw_div(
++ bw_div(
++ mul(
++ results->data_buffer_size[i],
++ results->bytes_per_request[i]),
++ results->useful_bytes_per_request[i]),
++ results->display_bandwidth[i]);
++ }
++ } else {
++ if (ltn(
++ bw_div(
++ bw_div(
++ mul(
++ results->data_buffer_size[i],
++ results->bytes_per_request[i]),
++ results->useful_bytes_per_request[i]),
++ results->display_bandwidth[i]),
++ results->min_mcifwr_size_in_time)) {
++ results->min_mcifwr_size_in_time =
++ bw_div(
++ bw_div(
++ mul(
++ results->data_buffer_size[i],
++ results->bytes_per_request[i]),
++ results->useful_bytes_per_request[i]),
++ results->display_bandwidth[i]);
++ }
++ }
++ }
++ }
++ results->total_requests_for_dmif_size = int_to_fixed(0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]
++ && surface_type[i] != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma) {
++ results->total_requests_for_dmif_size = add(
++ results->total_requests_for_dmif_size,
++ bw_div(results->data_buffer_size[i],
++ results->useful_bytes_per_request[i]));
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i] != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma
++ && dceip->limit_excessive_outstanding_dmif_requests
++ && (mode_data->number_of_displays > 1
++ || gtn(
++ results->total_requests_for_dmif_size,
++ dceip->dmif_request_buffer_size))) {
++ results->adjusted_data_buffer_size[i] =
++ bw_min(results->data_buffer_size[i],
++ bw_ceil(
++ mul(
++ results->min_dmif_size_in_time,
++ results->display_bandwidth[i]),
++ results->memory_chunk_size_in_bytes[i]));
++ } else {
++ results->adjusted_data_buffer_size[i] =
++ results->data_buffer_size[i];
++ }
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if ((mode_data->number_of_displays == 1
++ && equ(results->number_of_underlay_surfaces,
++ int_to_fixed(0)))) {
++ results->outstanding_chunk_request_limit[i] =
++ int_to_fixed(255);
++ } else {
++ results->outstanding_chunk_request_limit[i] =
++ bw_ceil(
++ bw_div(
++ results->adjusted_data_buffer_size[i],
++ results->pipe_chunk_size_in_bytes[i]),
++ int_to_fixed(1));
++ }
++ }
++ }
++ if (mode_data->number_of_displays > 1
++ || (neq(mode_data->graphics_rotation_angle, int_to_fixed(0))
++ && neq(mode_data->graphics_rotation_angle,
++ int_to_fixed(180)))) {
++ results->peak_pte_request_to_eviction_ratio_limiting =
++ dceip->peak_pte_request_to_eviction_ratio_limiting_multiple_displays_or_single_rotated_display;
++ } else {
++ results->peak_pte_request_to_eviction_ratio_limiting =
++ dceip->peak_pte_request_to_eviction_ratio_limiting_single_display_no_rotation;
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]
++ && results->scatter_gather_enable_for_pipe[i] == true) {
++ if (tiling_mode[i] == def_linear) {
++ results->useful_pte_per_pte_request =
++ int_to_fixed(8);
++ results->scatter_gather_page_width[i] = bw_div(
++ int_to_fixed(4096),
++ results->bytes_per_pixel[i]);
++ results->scatter_gather_page_height[i] =
++ int_to_fixed(1);
++ results->scatter_gather_pte_request_rows =
++ int_to_fixed(1);
++ results->scatter_gather_row_height =
++ dceip->scatter_gather_lines_of_pte_prefetching_in_linear_mode;
++ } else if (equ(results->rotation_angle[i],
++ int_to_fixed(0))
++ || equ(results->rotation_angle[i],
++ int_to_fixed(180))) {
++ results->useful_pte_per_pte_request =
++ int_to_fixed(8);
++ if (equ(results->bytes_per_pixel[i],
++ int_to_fixed(4))) {
++ results->scatter_gather_page_width[i] =
++ int_to_fixed(32);
++ results->scatter_gather_page_height[i] =
++ int_to_fixed(32);
++ } else if (equ(results->bytes_per_pixel[i],
++ int_to_fixed(2))) {
++ results->scatter_gather_page_width[i] =
++ int_to_fixed(64);
++ results->scatter_gather_page_height[i] =
++ int_to_fixed(32);
++ } else {
++ results->scatter_gather_page_width[i] =
++ int_to_fixed(64);
++ results->scatter_gather_page_height[i] =
++ int_to_fixed(64);
++ }
++ results->scatter_gather_pte_request_rows =
++ dceip->scatter_gather_pte_request_rows_in_tiling_mode;
++ results->scatter_gather_row_height =
++ results->scatter_gather_page_height[i];
++ } else {
++ results->useful_pte_per_pte_request =
++ int_to_fixed(1);
++ if (equ(results->bytes_per_pixel[i],
++ int_to_fixed(4))) {
++ results->scatter_gather_page_width[i] =
++ int_to_fixed(32);
++ results->scatter_gather_page_height[i] =
++ int_to_fixed(32);
++ } else if (equ(results->bytes_per_pixel[i],
++ int_to_fixed(2))) {
++ results->scatter_gather_page_width[i] =
++ int_to_fixed(32);
++ results->scatter_gather_page_height[i] =
++ int_to_fixed(64);
++ } else
++ // case else
++ {
++ results->scatter_gather_page_width[i] =
++ int_to_fixed(64);
++ results->scatter_gather_page_height[i] =
++ int_to_fixed(64);
++ }
++ results->scatter_gather_pte_request_rows =
++ dceip->scatter_gather_pte_request_rows_in_tiling_mode;
++ results->scatter_gather_row_height =
++ results->scatter_gather_page_height[i];
++ }
++ results->pte_request_per_chunk[i] = bw_div(
++ bw_div(dceip->chunk_width,
++ results->scatter_gather_page_width[i]),
++ results->useful_pte_per_pte_request);
++ results->scatter_gather_pte_requests_in_row[i] =
++ bw_div(
++ mul(results->scatter_gather_row_height,
++ bw_ceil(
++ mul(
++ bw_div(
++ results->source_width_rounded_up_to_chunks[i],
++ dceip->chunk_width),
++ results->pte_request_per_chunk[i]),
++ int_to_fixed(1))),
++ results->scatter_gather_page_height[i]);
++ results->scatter_gather_pte_requests_in_vblank = mul(
++ results->scatter_gather_pte_request_rows,
++ results->scatter_gather_pte_requests_in_row[i]);
++ if (equ(
++ results->peak_pte_request_to_eviction_ratio_limiting,
++ int_to_fixed(0))) {
++ results->scatter_gather_pte_request_limit[i] =
++ results->scatter_gather_pte_requests_in_vblank;
++ } else {
++ results->scatter_gather_pte_request_limit[i] =
++ bw_max(
++ dceip->minimum_outstanding_pte_request_limit,
++ bw_min(
++ results->scatter_gather_pte_requests_in_vblank,
++ bw_ceil(
++ mul(
++ mul(
++ bw_div(
++ bw_ceil(
++ results->adjusted_data_buffer_size[i],
++ results->memory_chunk_size_in_bytes[i]),
++ results->memory_chunk_size_in_bytes[i]),
++ results->pte_request_per_chunk[i]),
++ results->peak_pte_request_to_eviction_ratio_limiting),
++ int_to_fixed(
++ 1))));
++ }
++ }
++ }
++ results->inefficient_linear_pitch_in_bytes = mul(
++ mul(vbios->number_of_dram_banks,
++ vbios->number_of_dram_channels), int_to_fixed(256));
++ if (mode_data->underlay_surface_type == yuv_420) {
++ results->inefficient_underlay_pitch_in_pixels =
++ results->inefficient_linear_pitch_in_bytes;
++ } else if (mode_data->underlay_surface_type == yuv_422) {
++ results->inefficient_underlay_pitch_in_pixels = bw_div(
++ results->inefficient_linear_pitch_in_bytes,
++ int_to_fixed(2));
++ } else
++ // case else
++ {
++ results->inefficient_underlay_pitch_in_pixels = bw_div(
++ results->inefficient_linear_pitch_in_bytes,
++ int_to_fixed(4));
++ }
++ if (mode_data->underlay_tiling_mode == linear
++ && vbios->scatter_gather_enable == true
++ && mode_data->underlay_pitch_in_pixels.value
++ % results->inefficient_underlay_pitch_in_pixels.value
++ == false) {
++ results->minimum_underlay_pitch_padding_recommended_for_efficiency =
++ int_to_fixed(256);
++ } else {
++ results->minimum_underlay_pitch_padding_recommended_for_efficiency =
++ int_to_fixed(0);
++ }
++ results->cursor_total_data = int_to_fixed(0);
++ results->cursor_total_request_groups = int_to_fixed(0);
++ results->scatter_gather_total_pte_requests = int_to_fixed(0);
++ results->scatter_gather_total_pte_request_groups = int_to_fixed(0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->cursor_total_data = add(
++ results->cursor_total_data,
++ mul(results->cursor_width_pixels[i],
++ int_to_fixed(8)));
++ results->cursor_total_request_groups = add(
++ results->cursor_total_request_groups,
++ bw_ceil(
++ bw_div(results->cursor_width_pixels[i],
++ dceip->cursor_chunk_width),
++ int_to_fixed(1)));
++ if (results->scatter_gather_enable_for_pipe[i]) {
++ results->scatter_gather_total_pte_requests =
++ add(
++ results->scatter_gather_total_pte_requests,
++ results->scatter_gather_pte_request_limit[i]);
++ results->scatter_gather_total_pte_request_groups =
++ add(
++ results->scatter_gather_total_pte_request_groups,
++ bw_ceil(
++ bw_div(
++ results->scatter_gather_pte_request_limit[i],
++ bw_ceil(
++ results->pte_request_per_chunk[i],
++ int_to_fixed(
++ 1))),
++ int_to_fixed(1)));
++ }
++ }
++ }
++ results->tile_width_in_pixels = int_to_fixed(8);
++ results->dmif_total_number_of_data_request_page_close_open =
++ int_to_fixed(0);
++ results->mcifwr_total_number_of_data_request_page_close_open =
++ int_to_fixed(0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (results->scatter_gather_enable_for_pipe[i] == true
++ && tiling_mode[i] != def_linear) {
++ results->bytes_per_page_close_open =
++ mul(
++ results->lines_interleaved_in_mem_access[i],
++ bw_max(
++ mul(
++ mul(
++ mul(
++ results->bytes_per_pixel[i],
++ results->tile_width_in_pixels),
++ vbios->number_of_dram_banks),
++ vbios->number_of_dram_channels),
++ mul(
++ results->bytes_per_pixel[i],
++ results->scatter_gather_page_width[i])));
++ } else if (results->scatter_gather_enable_for_pipe[i]
++ == true && tiling_mode[i] == def_linear
++ && (mul(
++ results->pitch_in_pixels_after_surface_type[i],
++ results->bytes_per_pixel[i])).value
++ % results->inefficient_linear_pitch_in_bytes.value
++ == false) {
++ results->bytes_per_page_close_open =
++ dceip->linear_mode_line_request_alternation_slice;
++ } else {
++ results->bytes_per_page_close_open =
++ results->memory_chunk_size_in_bytes[i];
++ }
++ if (surface_type[i] != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma) {
++ results->dmif_total_number_of_data_request_page_close_open =
++ add(
++ results->dmif_total_number_of_data_request_page_close_open,
++ bw_div(
++ bw_ceil(
++ results->adjusted_data_buffer_size[i],
++ results->memory_chunk_size_in_bytes[i]),
++ results->bytes_per_page_close_open));
++ } else {
++ results->mcifwr_total_number_of_data_request_page_close_open =
++ add(
++ results->mcifwr_total_number_of_data_request_page_close_open,
++ bw_div(
++ bw_ceil(
++ results->adjusted_data_buffer_size[i],
++ results->memory_chunk_size_in_bytes[i]),
++ results->bytes_per_page_close_open));
++ }
++ }
++ }
++ results->dmif_total_page_close_open_time =
++ bw_div(
++ mul(
++ (add(
++ add(
++ results->dmif_total_number_of_data_request_page_close_open,
++ results->scatter_gather_total_pte_request_groups),
++ results->cursor_total_request_groups)),
++ vbios->trc), int_to_fixed(1000));
++ results->mcifwr_total_page_close_open_time =
++ bw_div(
++ mul(
++ results->mcifwr_total_number_of_data_request_page_close_open,
++ vbios->trc), int_to_fixed(1000));
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->adjusted_data_buffer_size_in_memory[i] = bw_div(
++ mul(results->adjusted_data_buffer_size[i],
++ results->bytes_per_request[i]),
++ results->useful_bytes_per_request[i]);
++ }
++ }
++ results->total_requests_for_adjusted_dmif_size = int_to_fixed(0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i] != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma) {
++ results->total_requests_for_adjusted_dmif_size =
++ add(
++ results->total_requests_for_adjusted_dmif_size,
++ bw_div(
++ results->adjusted_data_buffer_size[i],
++ results->useful_bytes_per_request[i]));
++ }
++ }
++ }
++ if (equ(dceip->dcfclk_request_generation, int_to_fixed(1))) {
++ results->total_dmifmc_urgent_trips = int_to_fixed(1);
++ } else {
++ results->total_dmifmc_urgent_trips =
++ bw_ceil(
++ bw_div(
++ results->total_requests_for_adjusted_dmif_size,
++ (add(dceip->dmif_request_buffer_size,
++ mul(
++ vbios->number_of_request_slots_gmc_reserves_for_dmif_per_channel,
++ vbios->number_of_dram_channels)))),
++ int_to_fixed(1));
++ }
++ results->total_dmifmc_urgent_latency = mul(vbios->dmifmc_urgent_latency,
++ results->total_dmifmc_urgent_trips);
++ results->total_display_reads_required_data = int_to_fixed(0);
++ results->total_display_reads_required_dram_access_data = int_to_fixed(
++ 0);
++ results->total_display_writes_required_data = int_to_fixed(0);
++ results->total_display_writes_required_dram_access_data = int_to_fixed(
++ 0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i] != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma) {
++ results->display_reads_required_data =
++ results->adjusted_data_buffer_size_in_memory[i];
++ results->display_reads_required_dram_access_data =
++ mul(
++ results->adjusted_data_buffer_size_in_memory[i],
++ bw_ceil(
++ bw_div(
++ vbios->dram_channel_width_in_bits,
++ results->bytes_per_request[i]),
++ int_to_fixed(1)));
++ if (results->access_one_channel_only[i]) {
++ results->display_reads_required_dram_access_data =
++ mul(
++ results->display_reads_required_dram_access_data,
++ vbios->number_of_dram_channels);
++ }
++ results->total_display_reads_required_data =
++ add(
++ results->total_display_reads_required_data,
++ results->display_reads_required_data);
++ results->total_display_reads_required_dram_access_data =
++ add(
++ results->total_display_reads_required_dram_access_data,
++ results->display_reads_required_dram_access_data);
++ } else {
++ results->total_display_writes_required_data =
++ add(
++ results->total_display_writes_required_data,
++ results->adjusted_data_buffer_size_in_memory[i]);
++ results->total_display_writes_required_dram_access_data =
++ add(
++ results->total_display_writes_required_dram_access_data,
++ mul(
++ results->adjusted_data_buffer_size_in_memory[i],
++ bw_ceil(
++ bw_div(
++ vbios->dram_channel_width_in_bits,
++ results->bytes_per_request[i]),
++ int_to_fixed(
++ 1))));
++ }
++ }
++ }
++ results->total_display_reads_required_data = add(
++ add(results->total_display_reads_required_data,
++ results->cursor_total_data),
++ mul(results->scatter_gather_total_pte_requests,
++ int_to_fixed(64)));
++ results->total_display_reads_required_dram_access_data = add(
++ add(results->total_display_reads_required_dram_access_data,
++ results->cursor_total_data),
++ mul(results->scatter_gather_total_pte_requests,
++ int_to_fixed(64)));
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (gtn(results->v_filter_init[i], int_to_fixed(4))) {
++ results->src_pixels_for_first_output_pixel[i] =
++ mul(
++ results->source_width_rounded_up_to_chunks[i],
++ int_to_fixed(4));
++ } else {
++ if (gtn(results->v_filter_init[i],
++ int_to_fixed(2))) {
++ results->src_pixels_for_first_output_pixel[i] =
++ int_to_fixed(512);
++ } else {
++ results->src_pixels_for_first_output_pixel[i] =
++ int_to_fixed(0);
++ }
++ }
++ results->src_data_for_first_output_pixel[i] =
++ bw_div(
++ mul(
++ mul(
++ results->src_pixels_for_first_output_pixel[i],
++ results->bytes_per_pixel[i]),
++ results->bytes_per_request[i]),
++ results->useful_bytes_per_request[i]);
++ results->src_pixels_for_last_output_pixel[i] =
++ mul(
++ results->source_width_rounded_up_to_chunks[i],
++ bw_max(
++ bw_ceil(
++ results->v_filter_init[i],
++ dceip->lines_interleaved_into_lb),
++ mul(
++ results->horizontal_blank_and_chunk_granularity_factor[i],
++ bw_ceil(results->vsr[i],
++ dceip->lines_interleaved_into_lb))));
++ results->src_data_for_last_output_pixel[i] =
++ bw_div(
++ mul(
++ mul(
++ mul(
++ results->source_width_rounded_up_to_chunks[i],
++ bw_max(
++ bw_ceil(
++ results->v_filter_init[i],
++ dceip->lines_interleaved_into_lb),
++ results->lines_interleaved_in_mem_access[i])),
++ results->bytes_per_pixel[i]),
++ results->bytes_per_request[i]),
++ results->useful_bytes_per_request[i]);
++ results->active_time[i] =
++ bw_div(
++ bw_div(
++ results->source_width_rounded_up_to_chunks[i],
++ results->hsr[i]),
++ results->pixel_rate[i]);
++ }
++ }
++ for (i = 0; i <= 2; i += 1) {
++ for (j = 0; j <= 2; j += 1) {
++ results->dmif_burst_time[i][j] =
++ bw_max3(
++ results->dmif_total_page_close_open_time,
++ bw_div(
++ results->total_display_reads_required_dram_access_data,
++ (mul(
++ bw_div(
++ mul(yclk[i],
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(
++ 8)),
++ vbios->number_of_dram_channels))),
++ bw_div(
++ results->total_display_reads_required_data,
++ (mul(sclk[j],
++ vbios->data_return_bus_width))));
++ if (mode_data->d1_display_write_back_dwb_enable
++ == true) {
++ results->mcifwr_burst_time[i][j] =
++ bw_max3(
++ results->mcifwr_total_page_close_open_time,
++ bw_div(
++ results->total_display_writes_required_dram_access_data,
++ (mul(
++ bw_div(
++ mul(
++ yclk[i],
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(
++ 8)),
++ vbios->number_of_dram_channels))),
++ bw_div(
++ results->total_display_writes_required_data,
++ (mul(sclk[j],
++ vbios->data_return_bus_width))));
++ }
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ for (j = 0; j <= 2; j += 1) {
++ for (k = 0; k <= 2; k += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i]
++ != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma) {
++ results->line_source_transfer_time[i][j][k] =
++ bw_max(
++ mul(
++ (add(
++ results->total_dmifmc_urgent_latency,
++ results->dmif_burst_time[j][k])),
++ bw_floor(
++ bw_div(
++ results->src_data_for_first_output_pixel[i],
++ results->adjusted_data_buffer_size_in_memory[i]),
++ int_to_fixed(
++ 1))),
++ sub(
++ mul(
++ (add(
++ results->total_dmifmc_urgent_latency,
++ results->dmif_burst_time[j][k])),
++ bw_floor(
++ bw_div(
++ results->src_data_for_last_output_pixel[i],
++ results->adjusted_data_buffer_size_in_memory[i]),
++ int_to_fixed(
++ 1))),
++ results->active_time[i]));
++ } else {
++ results->line_source_transfer_time[i][j][k] =
++ bw_max(
++ mul(
++ (add(
++ vbios->mcifwrmc_urgent_latency,
++ results->mcifwr_burst_time[j][k])),
++ bw_floor(
++ bw_div(
++ results->src_data_for_first_output_pixel[i],
++ results->adjusted_data_buffer_size_in_memory[i]),
++ int_to_fixed(
++ 1))),
++ sub(
++ mul(
++ (add(
++ vbios->mcifwrmc_urgent_latency,
++ results->mcifwr_burst_time[j][k])),
++ bw_floor(
++ bw_div(
++ results->src_data_for_last_output_pixel[i],
++ results->adjusted_data_buffer_size_in_memory[i]),
++ int_to_fixed(
++ 1))),
++ results->active_time[i]));
++ }
++ }
++ }
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (equ(
++ dceip->stutter_and_dram_clock_state_change_gated_before_cursor,
++ int_to_fixed(0))
++ && gtn(results->cursor_width_pixels[i],
++ int_to_fixed(0))) {
++ if (ltn(results->vsr[i], int_to_fixed(2))) {
++ results->cursor_latency_hiding[i] =
++ bw_div(
++ bw_div(
++ mul(
++ (sub(
++ dceip->cursor_dcp_buffer_lines,
++ int_to_fixed(
++ 1))),
++ results->h_total[i]),
++ results->vsr[i]),
++ results->pixel_rate[i]);
++ } else {
++ results->cursor_latency_hiding[i] =
++ bw_div(
++ bw_div(
++ mul(
++ (sub(
++ dceip->cursor_dcp_buffer_lines,
++ int_to_fixed(
++ 3))),
++ results->h_total[i]),
++ results->vsr[i]),
++ results->pixel_rate[i]);
++ }
++ } else {
++ results->cursor_latency_hiding[i] =
++ int_to_fixed(9999);
++ }
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (dceip->graphics_lb_nodownscaling_multi_line_prefetching
++ == true
++ && (equ(results->vsr[i], int_to_fixed(1))
++ || (leq(results->vsr[i],
++ frc_to_fixed(8, 10))
++ && leq(results->v_taps[i],
++ int_to_fixed(2))
++ && equ(results->lb_bpc[i],
++ int_to_fixed(8))))
++ && surface_type[i] == def_graphics) {
++ results->minimum_latency_hiding[i] =
++ sub(
++ sub(
++ add(
++ bw_div(
++ mul(
++ bw_div(
++ (bw_div(
++ bw_div(
++ results->data_buffer_size[i],
++ results->bytes_per_pixel[i]),
++ results->source_width_pixels[i])),
++ results->vsr[i]),
++ results->h_total[i]),
++ results->pixel_rate[i]),
++ results->lb_partitions[i]),
++ int_to_fixed(1)),
++ results->total_dmifmc_urgent_latency);
++ } else {
++ results->minimum_latency_hiding[i] =
++ sub(
++ bw_div(
++ mul(
++ (add(
++ add(
++ results->line_buffer_prefetch[i],
++ int_to_fixed(
++ 1)),
++ bw_div(
++ bw_div(
++ bw_div(
++ results->data_buffer_size[i],
++ results->bytes_per_pixel[i]),
++ results->source_width_pixels[i]),
++ results->vsr[i]))),
++ results->h_total[i]),
++ results->pixel_rate[i]),
++ results->total_dmifmc_urgent_latency);
++ }
++ results->minimum_latency_hiding_with_cursor[i] = bw_min(
++ results->minimum_latency_hiding[i],
++ results->cursor_latency_hiding[i]);
++ }
++ }
++ for (i = 0; i <= 2; i += 1) {
++ for (j = 0; j <= 2; j += 1) {
++ results->blackout_duration_margin[i][j] = int_to_fixed(
++ 9999);
++ results->dispclk_required_for_blackout_duration[i][j] =
++ int_to_fixed(0);
++ results->dispclk_required_for_blackout_recovery[i][j] =
++ int_to_fixed(0);
++ for (k = 0; k <= maximum_number_of_surfaces - 1; k +=
++ 1) {
++ if (results->enable[k]
++ && gtn(vbios->blackout_duration,
++ int_to_fixed(0))) {
++ if (surface_type[k]
++ != def_display_write_back420_luma
++ && surface_type[k]
++ != def_display_write_back420_chroma) {
++ results->blackout_duration_margin[i][j] =
++ bw_min(
++ results->blackout_duration_margin[i][j],
++ sub(
++ sub(
++ sub(
++ results->minimum_latency_hiding_with_cursor[k],
++ vbios->blackout_duration),
++ results->dmif_burst_time[i][j]),
++ results->line_source_transfer_time[k][i][j]));
++ results->dispclk_required_for_blackout_duration[i][j] =
++ bw_max3(
++ results->dispclk_required_for_blackout_duration[i][j],
++ bw_div(
++ bw_div(
++ mul(
++ results->src_pixels_for_first_output_pixel[k],
++ dceip->display_pipe_throughput_factor),
++ dceip->lb_write_pixels_per_dispclk),
++ (sub(
++ sub(
++ results->minimum_latency_hiding_with_cursor[k],
++ vbios->blackout_duration),
++ results->dmif_burst_time[i][j]))),
++ bw_div(
++ bw_div(
++ mul(
++ results->src_pixels_for_last_output_pixel[k],
++ dceip->display_pipe_throughput_factor),
++ dceip->lb_write_pixels_per_dispclk),
++ (add(
++ sub(
++ sub(
++ results->minimum_latency_hiding_with_cursor[k],
++ vbios->blackout_duration),
++ results->dmif_burst_time[i][j]),
++ results->active_time[k]))));
++ if (leq(
++ vbios->maximum_blackout_recovery_time,
++ add(
++ mul(
++ results->total_dmifmc_urgent_latency,
++ int_to_fixed(
++ 2)),
++ results->dmif_burst_time[i][j]))) {
++ results->dispclk_required_for_blackout_recovery[i][j] =
++ int_to_fixed(
++ 9999);
++ } else if (ltn(
++ results->adjusted_data_buffer_size[k],
++ mul(
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k]),
++ (add(
++ add(
++ vbios->blackout_duration,
++ mul(
++ results->total_dmifmc_urgent_latency,
++ int_to_fixed(
++ 2))),
++ results->dmif_burst_time[i][j]))))) {
++ results->dispclk_required_for_blackout_recovery[i][j] =
++ bw_max(
++ results->dispclk_required_for_blackout_recovery[i][j],
++ bw_div(
++ mul(
++ bw_div(
++ bw_div(
++ (sub(
++ mul(
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k]),
++ (add(
++ vbios->blackout_duration,
++ vbios->maximum_blackout_recovery_time))),
++ results->adjusted_data_buffer_size[k])),
++ results->bytes_per_pixel[k]),
++ (sub(
++ sub(
++ vbios->maximum_blackout_recovery_time,
++ mul(
++ results->total_dmifmc_urgent_latency,
++ int_to_fixed(
++ 2))),
++ results->dmif_burst_time[i][j]))),
++ results->latency_hiding_lines[k]),
++ results->lines_interleaved_in_mem_access[k]));
++ }
++ } else {
++ results->blackout_duration_margin[i][j] =
++ bw_min(
++ results->blackout_duration_margin[i][j],
++ sub(
++ sub(
++ sub(
++ sub(
++ results->minimum_latency_hiding_with_cursor[k],
++ vbios->blackout_duration),
++ results->dmif_burst_time[i][j]),
++ results->mcifwr_burst_time[i][j]),
++ results->line_source_transfer_time[k][i][j]));
++ results->dispclk_required_for_blackout_duration[i][j] =
++ bw_max3(
++ results->dispclk_required_for_blackout_duration[i][j],
++ bw_div(
++ bw_div(
++ mul(
++ results->src_pixels_for_first_output_pixel[k],
++ dceip->display_pipe_throughput_factor),
++ dceip->lb_write_pixels_per_dispclk),
++ (sub(
++ sub(
++ sub(
++ results->minimum_latency_hiding_with_cursor[k],
++ vbios->blackout_duration),
++ results->dmif_burst_time[i][j]),
++ results->mcifwr_burst_time[i][j]))),
++ bw_div(
++ bw_div(
++ mul(
++ results->src_pixels_for_last_output_pixel[k],
++ dceip->display_pipe_throughput_factor),
++ dceip->lb_write_pixels_per_dispclk),
++ (add(
++ sub(
++ sub(
++ sub(
++ results->minimum_latency_hiding_with_cursor[k],
++ vbios->blackout_duration),
++ results->dmif_burst_time[i][j]),
++ results->mcifwr_burst_time[i][j]),
++ results->active_time[k]))));
++ if (ltn(
++ vbios->maximum_blackout_recovery_time,
++ add(
++ add(
++ mul(
++ vbios->mcifwrmc_urgent_latency,
++ int_to_fixed(
++ 2)),
++ results->dmif_burst_time[i][j]),
++ results->mcifwr_burst_time[i][j]))) {
++ results->dispclk_required_for_blackout_recovery[i][j] =
++ int_to_fixed(
++ 9999);
++ } else if (ltn(
++ results->adjusted_data_buffer_size[k],
++ mul(
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k]),
++ (add(
++ add(
++ vbios->blackout_duration,
++ mul(
++ results->total_dmifmc_urgent_latency,
++ int_to_fixed(
++ 2))),
++ results->dmif_burst_time[i][j]))))) {
++ results->dispclk_required_for_blackout_recovery[i][j] =
++ bw_max(
++ results->dispclk_required_for_blackout_recovery[i][j],
++ bw_div(
++ mul(
++ bw_div(
++ bw_div(
++ (sub(
++ mul(
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k]),
++ (add(
++ vbios->blackout_duration,
++ vbios->maximum_blackout_recovery_time))),
++ results->adjusted_data_buffer_size[k])),
++ results->bytes_per_pixel[k]),
++ (sub(
++ vbios->maximum_blackout_recovery_time,
++ (add(
++ mul(
++ results->total_dmifmc_urgent_latency,
++ int_to_fixed(
++ 2)),
++ results->dmif_burst_time[i][j]))))),
++ results->latency_hiding_lines[k]),
++ results->lines_interleaved_in_mem_access[k]));
++ }
++ }
++ }
++ }
++ }
++ }
++ if (gtn(results->blackout_duration_margin[high][high], int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_blackout_duration[high][high],
++ vbios->high_voltage_max_dispclk)) {
++ results->cpup_state_change_enable = true;
++ if (ltn(
++ results->dispclk_required_for_blackout_recovery[high][high],
++ vbios->high_voltage_max_dispclk)) {
++ results->cpuc_state_change_enable = true;
++ } else {
++ results->cpuc_state_change_enable = false;
++ }
++ } else {
++ results->cpup_state_change_enable = false;
++ results->cpuc_state_change_enable = false;
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (mode_data->number_of_displays <= 1
++ || mode_data->display_synchronization_enabled
++ == true) {
++ results->maximum_latency_hiding[i] =
++ int_to_fixed(450);
++ } else {
++ results->maximum_latency_hiding[i] =
++ add(
++ add(
++ results->minimum_latency_hiding[i],
++ bw_div(
++ mul(
++ bw_div(
++ int_to_fixed(
++ 1),
++ results->vsr[i]),
++ results->h_total[i]),
++ results->pixel_rate[i])),
++ mul(frc_to_fixed(1, 2),
++ results->total_dmifmc_urgent_latency));
++ }
++ results->maximum_latency_hiding_with_cursor[i] = bw_min(
++ results->maximum_latency_hiding[i],
++ results->cursor_latency_hiding[i]);
++ }
++ }
++ for (i = 0; i <= 2; i += 1) {
++ for (j = 0; j <= 2; j += 1) {
++ results->dram_speed_change_margin[i][j] = int_to_fixed(
++ 9999);
++ results->dispclk_required_for_dram_speed_change[i][j] =
++ int_to_fixed(0);
++ for (k = 0; k <= maximum_number_of_surfaces - 1; k +=
++ 1) {
++ if (results->enable[k]) {
++ if (surface_type[k]
++ != def_display_write_back420_luma
++ && surface_type[k]
++ != def_display_write_back420_chroma) {
++ results->dram_speed_change_margin[i][j] =
++ bw_min(
++ results->dram_speed_change_margin[i][j],
++ sub(
++ sub(
++ sub(
++ results->maximum_latency_hiding_with_cursor[k],
++ vbios->nbp_state_change_latency),
++ results->dmif_burst_time[i][j]),
++ results->line_source_transfer_time[k][i][j]));
++ results->dispclk_required_for_dram_speed_change[i][j] =
++ bw_max3(
++ results->dispclk_required_for_dram_speed_change[i][j],
++ bw_div(
++ bw_div(
++ mul(
++ results->src_pixels_for_first_output_pixel[k],
++ dceip->display_pipe_throughput_factor),
++ dceip->lb_write_pixels_per_dispclk),
++ (sub(
++ sub(
++ results->maximum_latency_hiding_with_cursor[k],
++ vbios->nbp_state_change_latency),
++ results->dmif_burst_time[i][j]))),
++ bw_div(
++ bw_div(
++ mul(
++ results->src_pixels_for_last_output_pixel[k],
++ dceip->display_pipe_throughput_factor),
++ dceip->lb_write_pixels_per_dispclk),
++ (add(
++ sub(
++ sub(
++ results->maximum_latency_hiding_with_cursor[k],
++ vbios->nbp_state_change_latency),
++ results->dmif_burst_time[i][j]),
++ results->active_time[k]))));
++ } else {
++ results->dram_speed_change_margin[i][j] =
++ bw_min(
++ results->dram_speed_change_margin[i][j],
++ sub(
++ sub(
++ sub(
++ sub(
++ results->maximum_latency_hiding_with_cursor[k],
++ vbios->nbp_state_change_latency),
++ results->dmif_burst_time[i][j]),
++ results->mcifwr_burst_time[i][j]),
++ results->line_source_transfer_time[k][i][j]));
++ results->dispclk_required_for_dram_speed_change[i][j] =
++ bw_max3(
++ results->dispclk_required_for_dram_speed_change[i][j],
++ bw_div(
++ bw_div(
++ mul(
++ results->src_pixels_for_first_output_pixel[k],
++ dceip->display_pipe_throughput_factor),
++ dceip->lb_write_pixels_per_dispclk),
++ (sub(
++ sub(
++ sub(
++ results->maximum_latency_hiding_with_cursor[k],
++ vbios->nbp_state_change_latency),
++ results->dmif_burst_time[i][j]),
++ results->mcifwr_burst_time[i][j]))),
++ bw_div(
++ bw_div(
++ mul(
++ results->src_pixels_for_last_output_pixel[k],
++ dceip->display_pipe_throughput_factor),
++ dceip->lb_write_pixels_per_dispclk),
++ (add(
++ sub(
++ sub(
++ sub(
++ results->maximum_latency_hiding_with_cursor[k],
++ vbios->nbp_state_change_latency),
++ results->dmif_burst_time[i][j]),
++ results->mcifwr_burst_time[i][j]),
++ results->active_time[k]))));
++ }
++ }
++ }
++ }
++ }
++ if (gtn(results->dram_speed_change_margin[high][high], int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_dram_speed_change[high][high],
++ vbios->high_voltage_max_dispclk)) {
++ results->nbp_state_change_enable = true;
++ } else {
++ results->nbp_state_change_enable = false;
++ }
++ results->min_cursor_memory_interface_buffer_size_in_time = int_to_fixed(
++ 9999);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (gtn(results->cursor_width_pixels[i],
++ int_to_fixed(0))) {
++ results->min_cursor_memory_interface_buffer_size_in_time =
++ bw_min(
++ results->min_cursor_memory_interface_buffer_size_in_time,
++ bw_div(
++ mul(
++ bw_div(
++ bw_div(
++ dceip->cursor_memory_interface_buffer_pixels,
++ results->cursor_width_pixels[i]),
++ results->vsr[i]),
++ results->h_total[i]),
++ results->pixel_rate[i]));
++ }
++ }
++ }
++ results->min_read_buffer_size_in_time = bw_min(
++ results->min_cursor_memory_interface_buffer_size_in_time,
++ results->min_dmif_size_in_time);
++ results->display_reads_time_for_data_transfer = sub(
++ results->min_read_buffer_size_in_time,
++ results->total_dmifmc_urgent_latency);
++ results->display_writes_time_for_data_transfer = sub(
++ results->min_mcifwr_size_in_time,
++ vbios->mcifwrmc_urgent_latency);
++ results->dmif_required_dram_bandwidth = bw_div(
++ results->total_display_reads_required_dram_access_data,
++ results->display_reads_time_for_data_transfer);
++ results->mcifwr_required_dram_bandwidth = bw_div(
++ results->total_display_writes_required_dram_access_data,
++ results->display_writes_time_for_data_transfer);
++ results->required_dmifmc_urgent_latency_for_page_close_open = bw_div(
++ (sub(results->min_read_buffer_size_in_time,
++ results->dmif_total_page_close_open_time)),
++ results->total_dmifmc_urgent_trips);
++ results->required_mcifmcwr_urgent_latency = sub(
++ results->min_mcifwr_size_in_time,
++ results->mcifwr_total_page_close_open_time);
++ if (gtn(results->scatter_gather_total_pte_requests,
++ dceip->maximum_total_outstanding_pte_requests_allowed_by_saw)) {
++ results->required_dram_bandwidth_gbyte_per_second =
++ int_to_fixed(9999);
++ yclk_message =
++ def_exceeded_allowed_outstanding_pte_req_queue_size;
++ y_clk_level = high;
++ results->dram_bandwidth = mul(
++ bw_div(
++ mul(vbios->high_yclk,
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(8)),
++ vbios->number_of_dram_channels);
++ } else if (gtn(vbios->dmifmc_urgent_latency,
++ results->required_dmifmc_urgent_latency_for_page_close_open)
++ || gtn(vbios->mcifwrmc_urgent_latency,
++ results->required_mcifmcwr_urgent_latency)) {
++ results->required_dram_bandwidth_gbyte_per_second =
++ int_to_fixed(9999);
++ yclk_message = def_exceeded_allowed_page_close_open;
++ y_clk_level = high;
++ results->dram_bandwidth = mul(
++ bw_div(
++ mul(vbios->high_yclk,
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(8)),
++ vbios->number_of_dram_channels);
++ } else {
++ results->required_dram_bandwidth_gbyte_per_second = bw_div(
++ bw_max(results->dmif_required_dram_bandwidth,
++ results->mcifwr_required_dram_bandwidth),
++ int_to_fixed(1000));
++ if (ltn(
++ mul(results->required_dram_bandwidth_gbyte_per_second,
++ int_to_fixed(1000)),
++ mul(
++ bw_div(
++ mul(vbios->low_yclk,
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(8)),
++ vbios->number_of_dram_channels))
++ && (results->cpup_state_change_enable == false
++ || (gtn(
++ results->blackout_duration_margin[low][high],
++ int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_blackout_duration[low][high],
++ vbios->high_voltage_max_dispclk)))
++ && (results->cpuc_state_change_enable == false
++ || (gtn(
++ results->blackout_duration_margin[low][high],
++ int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_blackout_duration[low][high],
++ vbios->high_voltage_max_dispclk)
++ && ltn(
++ results->dispclk_required_for_blackout_recovery[low][high],
++ vbios->high_voltage_max_dispclk)))
++ && gtn(results->dram_speed_change_margin[low][high],
++ int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_dram_speed_change[low][high],
++ vbios->high_voltage_max_dispclk)) {
++ yclk_message = def_low;
++ y_clk_level = low;
++ results->dram_bandwidth =
++ mul(
++ bw_div(
++ mul(vbios->low_yclk,
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(8)),
++ vbios->number_of_dram_channels);
++ } else if (ltn(
++ mul(results->required_dram_bandwidth_gbyte_per_second,
++ int_to_fixed(1000)),
++ mul(
++ bw_div(
++ mul(vbios->high_yclk,
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(8)),
++ vbios->number_of_dram_channels))) {
++ yclk_message = def_high;
++ y_clk_level = high;
++ results->dram_bandwidth =
++ mul(
++ bw_div(
++ mul(vbios->high_yclk,
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(8)),
++ vbios->number_of_dram_channels);
++ } else {
++ yclk_message = def_exceeded_allowed_maximum_bw;
++ y_clk_level = high;
++ results->dram_bandwidth =
++ mul(
++ bw_div(
++ mul(vbios->high_yclk,
++ vbios->dram_channel_width_in_bits),
++ int_to_fixed(8)),
++ vbios->number_of_dram_channels);
++ }
++ }
++ results->dmif_required_sclk = bw_div(
++ bw_div(results->total_display_reads_required_data,
++ results->display_reads_time_for_data_transfer),
++ vbios->data_return_bus_width);
++ results->mcifwr_required_sclk = bw_div(
++ bw_div(results->total_display_writes_required_data,
++ results->display_writes_time_for_data_transfer),
++ vbios->data_return_bus_width);
++ if (gtn(results->scatter_gather_total_pte_requests,
++ dceip->maximum_total_outstanding_pte_requests_allowed_by_saw)) {
++ results->required_sclk = int_to_fixed(9999);
++ sclk_message =
++ def_exceeded_allowed_outstanding_pte_req_queue_size;
++ sclk_level = high;
++ } else if (gtn(vbios->dmifmc_urgent_latency,
++ results->required_dmifmc_urgent_latency_for_page_close_open)
++ || gtn(vbios->mcifwrmc_urgent_latency,
++ results->required_mcifmcwr_urgent_latency)) {
++ results->required_sclk = int_to_fixed(9999);
++ sclk_message = def_exceeded_allowed_page_close_open;
++ sclk_level = high;
++ } else {
++ results->required_sclk = bw_max(results->dmif_required_sclk,
++ results->mcifwr_required_sclk);
++ if (ltn(results->required_sclk, vbios->low_sclk)
++ && (results->cpup_state_change_enable == false
++ || (gtn(
++ results->blackout_duration_margin[y_clk_level][low],
++ int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_blackout_duration[y_clk_level][low],
++ vbios->high_voltage_max_dispclk)))
++ && (results->cpuc_state_change_enable == false
++ || (gtn(
++ results->blackout_duration_margin[y_clk_level][low],
++ int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_blackout_duration[y_clk_level][low],
++ vbios->high_voltage_max_dispclk)
++ && ltn(
++ results->dispclk_required_for_blackout_recovery[y_clk_level][low],
++ vbios->high_voltage_max_dispclk)))
++ && (results->nbp_state_change_enable == false
++ || (gtn(
++ results->dram_speed_change_margin[y_clk_level][low],
++ int_to_fixed(0))
++ && leq(
++ results->dispclk_required_for_dram_speed_change[y_clk_level][low],
++ vbios->high_voltage_max_dispclk)))) {
++ sclk_message = def_low;
++ sclk_level = low;
++ } else if (ltn(results->required_sclk, vbios->mid_sclk)
++ && (results->cpup_state_change_enable == false
++ || (gtn(
++ results->blackout_duration_margin[y_clk_level][mid],
++ int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_blackout_duration[y_clk_level][mid],
++ vbios->high_voltage_max_dispclk)))
++ && (results->cpuc_state_change_enable == false
++ || (gtn(
++ results->blackout_duration_margin[y_clk_level][mid],
++ int_to_fixed(0))
++ && ltn(
++ results->dispclk_required_for_blackout_duration[y_clk_level][mid],
++ vbios->high_voltage_max_dispclk)
++ && ltn(
++ results->dispclk_required_for_blackout_recovery[y_clk_level][mid],
++ vbios->high_voltage_max_dispclk)))
++ && (results->nbp_state_change_enable == false
++ || (gtn(
++ results->dram_speed_change_margin[y_clk_level][mid],
++ int_to_fixed(0))
++ && leq(
++ results->dispclk_required_for_dram_speed_change[y_clk_level][mid],
++ vbios->high_voltage_max_dispclk)))) {
++ sclk_message = def_mid;
++ sclk_level = mid;
++ } else if (ltn(results->required_sclk, vbios->high_sclk)) {
++ sclk_message = def_high;
++ sclk_level = high;
++ } else {
++ sclk_message = def_exceeded_allowed_maximum_sclk;
++ sclk_level = high;
++ }
++ }
++ results->downspread_factor = add(
++ bw_div(vbios->down_spread_percentage, int_to_fixed(100)),
++ int_to_fixed(1));
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i] == def_graphics) {
++ if (equ(results->lb_bpc[i], int_to_fixed(6))) {
++ results->v_scaler_efficiency =
++ dceip->graphics_vscaler_efficiency6_bit_per_component;
++ } else if (equ(results->lb_bpc[i],
++ int_to_fixed(8))) {
++ results->v_scaler_efficiency =
++ dceip->graphics_vscaler_efficiency8_bit_per_component;
++ } else if (equ(results->lb_bpc[i],
++ int_to_fixed(10))) {
++ results->v_scaler_efficiency =
++ dceip->graphics_vscaler_efficiency10_bit_per_component;
++ } else {
++ results->v_scaler_efficiency =
++ dceip->graphics_vscaler_efficiency12_bit_per_component;
++ }
++ if (results->use_alpha[i] == true) {
++ results->v_scaler_efficiency =
++ bw_min(
++ results->v_scaler_efficiency,
++ dceip->alpha_vscaler_efficiency);
++ }
++ } else {
++ if (equ(results->lb_bpc[i], int_to_fixed(6))) {
++ results->v_scaler_efficiency =
++ dceip->underlay_vscaler_efficiency6_bit_per_component;
++ } else if (equ(results->lb_bpc[i],
++ int_to_fixed(8))) {
++ results->v_scaler_efficiency =
++ dceip->underlay_vscaler_efficiency8_bit_per_component;
++ } else if (equ(results->lb_bpc[i],
++ int_to_fixed(10))) {
++ results->v_scaler_efficiency =
++ dceip->underlay_vscaler_efficiency10_bit_per_component;
++ } else {
++ results->v_scaler_efficiency =
++ dceip->underlay_vscaler_efficiency12_bit_per_component;
++ }
++ }
++ if (dceip->pre_downscaler_enabled
++ && gtn(results->hsr[i], int_to_fixed(1))) {
++ results->scaler_limits_factor =
++ bw_max(
++ bw_div(results->v_taps[i],
++ results->v_scaler_efficiency),
++ bw_div(
++ results->source_width_rounded_up_to_chunks[i],
++ results->h_total[i]));
++ } else {
++ results->scaler_limits_factor =
++ bw_max3(int_to_fixed(1),
++ bw_ceil(
++ bw_div(results->h_taps[i],
++ int_to_fixed(
++ 4)),
++ int_to_fixed(1)),
++ mul(results->hsr[i],
++ bw_max(
++ bw_div(
++ results->v_taps[i],
++ results->v_scaler_efficiency),
++ int_to_fixed(
++ 1))));
++ }
++ results->display_pipe_pixel_throughput =
++ bw_div(
++ bw_div(
++ mul(
++ bw_max(
++ results->lb_lines_in_per_line_out_in_beginning_of_frame[i],
++ mul(
++ results->lb_lines_in_per_line_out_in_middle_of_frame[i],
++ results->horizontal_blank_and_chunk_granularity_factor[i])),
++ results->source_width_rounded_up_to_chunks[i]),
++ (bw_div(results->h_total[i],
++ results->pixel_rate[i]))),
++ dceip->lb_write_pixels_per_dispclk);
++ results->dispclk_required_without_ramping[i] =
++ mul(results->downspread_factor,
++ bw_max(
++ mul(results->pixel_rate[i],
++ results->scaler_limits_factor),
++ mul(
++ dceip->display_pipe_throughput_factor,
++ results->display_pipe_pixel_throughput)));
++ results->dispclk_required_with_ramping[i] =
++ mul(dceip->dispclk_ramping_factor,
++ bw_max(
++ mul(results->pixel_rate[i],
++ results->scaler_limits_factor),
++ results->display_pipe_pixel_throughput));
++ }
++ }
++ results->total_dispclk_required_with_ramping = int_to_fixed(0);
++ results->total_dispclk_required_without_ramping = int_to_fixed(0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (ltn(results->total_dispclk_required_with_ramping,
++ results->dispclk_required_with_ramping[i])) {
++ results->total_dispclk_required_with_ramping =
++ results->dispclk_required_with_ramping[i];
++ }
++ if (ltn(results->total_dispclk_required_without_ramping,
++ results->dispclk_required_without_ramping[i])) {
++ results->total_dispclk_required_without_ramping =
++ results->dispclk_required_without_ramping[i];
++ }
++ }
++ }
++ results->total_read_request_bandwidth = int_to_fixed(0);
++ results->total_write_request_bandwidth = int_to_fixed(0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i] != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma) {
++ results->total_read_request_bandwidth = add(
++ results->total_read_request_bandwidth,
++ results->request_bandwidth[i]);
++ } else {
++ results->total_write_request_bandwidth = add(
++ results->total_write_request_bandwidth,
++ results->request_bandwidth[i]);
++ }
++ }
++ }
++ results->dispclk_required_for_total_read_request_bandwidth = bw_div(
++ mul(results->total_read_request_bandwidth,
++ dceip->dispclk_per_request), dceip->request_efficiency);
++ if (equ(dceip->dcfclk_request_generation, int_to_fixed(0))) {
++ results->total_dispclk_required_with_ramping_with_request_bandwidth =
++ bw_max(results->total_dispclk_required_with_ramping,
++ results->dispclk_required_for_total_read_request_bandwidth);
++ results->total_dispclk_required_without_ramping_with_request_bandwidth =
++ bw_max(results->total_dispclk_required_without_ramping,
++ results->dispclk_required_for_total_read_request_bandwidth);
++ } else {
++ results->total_dispclk_required_with_ramping_with_request_bandwidth =
++ results->total_dispclk_required_with_ramping;
++ results->total_dispclk_required_without_ramping_with_request_bandwidth =
++ results->total_dispclk_required_without_ramping;
++ }
++ if (results->cpuc_state_change_enable == true) {
++ results->total_dispclk_required_with_ramping_with_request_bandwidth =
++ bw_max3(
++ results->total_dispclk_required_with_ramping_with_request_bandwidth,
++ results->dispclk_required_for_blackout_duration[y_clk_level][sclk_level],
++ results->dispclk_required_for_blackout_recovery[y_clk_level][sclk_level]);
++ results->total_dispclk_required_without_ramping_with_request_bandwidth =
++ bw_max3(
++ results->total_dispclk_required_without_ramping_with_request_bandwidth,
++ results->dispclk_required_for_blackout_duration[y_clk_level][sclk_level],
++ results->dispclk_required_for_blackout_recovery[y_clk_level][sclk_level]);
++ }
++ if (results->cpup_state_change_enable == true) {
++ results->total_dispclk_required_with_ramping_with_request_bandwidth =
++ bw_max(
++ results->total_dispclk_required_with_ramping_with_request_bandwidth,
++ results->dispclk_required_for_blackout_duration[y_clk_level][sclk_level]);
++ results->total_dispclk_required_without_ramping_with_request_bandwidth =
++ bw_max(
++ results->total_dispclk_required_without_ramping_with_request_bandwidth,
++ results->dispclk_required_for_blackout_duration[y_clk_level][sclk_level]);
++ }
++ if (results->nbp_state_change_enable == true) {
++ results->total_dispclk_required_with_ramping_with_request_bandwidth =
++ bw_max(
++ results->total_dispclk_required_with_ramping_with_request_bandwidth,
++ results->dispclk_required_for_dram_speed_change[y_clk_level][sclk_level]);
++ results->total_dispclk_required_without_ramping_with_request_bandwidth =
++ bw_max(
++ results->total_dispclk_required_without_ramping_with_request_bandwidth,
++ results->dispclk_required_for_dram_speed_change[y_clk_level][sclk_level]);
++ }
++ if (ltn(
++ results->total_dispclk_required_with_ramping_with_request_bandwidth,
++ vbios->high_voltage_max_dispclk)) {
++ results->dispclk =
++ results->total_dispclk_required_with_ramping_with_request_bandwidth;
++ } else if (ltn(
++ results->total_dispclk_required_without_ramping_with_request_bandwidth,
++ vbios->high_voltage_max_dispclk)) {
++ results->dispclk = vbios->high_voltage_max_dispclk;
++ } else {
++ results->dispclk =
++ results->total_dispclk_required_without_ramping_with_request_bandwidth;
++ }
++ if (pipe_check == def_notok) {
++ voltage = def_na;
++ mode_background_color = def_na_color;
++ mode_font_color = def_vb_white;
++ } else if (mode_check == def_notok) {
++ voltage = def_notok;
++ mode_background_color = def_notok_color;
++ mode_font_color = def_vb_black;
++ } else if (yclk_message == def_low && sclk_message == def_low
++ && ltn(results->dispclk, vbios->low_voltage_max_dispclk)) {
++ voltage = def_low;
++ mode_background_color = def_low_color;
++ mode_font_color = def_vb_black;
++ } else if (yclk_message == def_low
++ && (sclk_message == def_low || sclk_message == def_mid)
++ && ltn(results->dispclk, vbios->mid_voltage_max_dispclk)) {
++ voltage = def_mid;
++ mode_background_color = def_mid_color;
++ mode_font_color = def_vb_black;
++ } else if ((yclk_message == def_low || yclk_message == def_high)
++ && (sclk_message == def_low || sclk_message == def_mid
++ || sclk_message == def_high)
++ && leq(results->dispclk, vbios->high_voltage_max_dispclk)) {
++ if (results->nbp_state_change_enable == true) {
++ voltage = def_high;
++ mode_background_color = def_high_color;
++ mode_font_color = def_vb_black;
++ } else {
++ voltage = def_high_no_nbp_state_change;
++ mode_background_color =
++ def_high_no_nbp_state_change_color;
++ mode_font_color = def_vb_black;
++ }
++ } else {
++ voltage = def_notok;
++ mode_background_color = def_notok_color;
++ mode_font_color = def_vb_black;
++ }
++ if (mode_background_color == def_na_color
++ || mode_background_color == def_notok_color) {
++ mode_pattern = def_xl_pattern_solid;
++ } else if (results->cpup_state_change_enable == false) {
++ mode_pattern = def_xl_pattern_checker;
++ } else if (results->cpuc_state_change_enable == false) {
++ mode_pattern = def_xl_pattern_light_horizontal;
++ } else {
++ mode_pattern = def_xl_pattern_solid;
++ }
++ results->blackout_recovery_time = int_to_fixed(0);
++ for (k = 0; k <= maximum_number_of_surfaces - 1; k += 1) {
++ if (results->enable[k]
++ && gtn(vbios->blackout_duration, int_to_fixed(0))
++ && results->cpup_state_change_enable == true) {
++ if (surface_type[k] != def_display_write_back420_luma
++ && surface_type[k]
++ != def_display_write_back420_chroma) {
++ results->blackout_recovery_time =
++ bw_max(results->blackout_recovery_time,
++ add(
++ mul(
++ results->total_dmifmc_urgent_latency,
++ int_to_fixed(
++ 2)),
++ results->dmif_burst_time[y_clk_level][sclk_level]));
++ if (ltn(results->adjusted_data_buffer_size[k],
++ mul(
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k]),
++ (add(
++ add(
++ vbios->blackout_duration,
++ mul(
++ results->total_dmifmc_urgent_latency,
++ int_to_fixed(
++ 2))),
++ results->dmif_burst_time[y_clk_level][sclk_level]))))) {
++ results->blackout_recovery_time =
++ bw_max(
++ results->blackout_recovery_time,
++ bw_div(
++ (sub(
++ add(
++ mul(
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k]),
++ vbios->blackout_duration),
++ bw_div(
++ mul(
++ mul(
++ mul(
++ (add(
++ mul(
++ results->total_dmifmc_urgent_latency,
++ int_to_fixed(
++ 2)),
++ results->dmif_burst_time[y_clk_level][sclk_level])),
++ results->dispclk),
++ results->bytes_per_pixel[k]),
++ results->lines_interleaved_in_mem_access[k]),
++ results->latency_hiding_lines[k])),
++ results->adjusted_data_buffer_size[k])),
++ (sub(
++ bw_div(
++ mul(
++ mul(
++ results->dispclk,
++ results->bytes_per_pixel[k]),
++ results->lines_interleaved_in_mem_access[k]),
++ results->latency_hiding_lines[k]),
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k])))));
++ }
++ } else {
++ results->blackout_recovery_time =
++ bw_max(results->blackout_recovery_time,
++ add(
++ mul(
++ vbios->mcifwrmc_urgent_latency,
++ int_to_fixed(
++ 2)),
++ results->mcifwr_burst_time[y_clk_level][sclk_level]));
++ if (ltn(results->adjusted_data_buffer_size[k],
++ mul(
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k]),
++ (add(
++ add(
++ vbios->blackout_duration,
++ mul(
++ vbios->mcifwrmc_urgent_latency,
++ int_to_fixed(
++ 2))),
++ results->mcifwr_burst_time[y_clk_level][sclk_level]))))) {
++ results->blackout_recovery_time =
++ bw_max(
++ results->blackout_recovery_time,
++ bw_div(
++ (sub(
++ add(
++ mul(
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k]),
++ vbios->blackout_duration),
++ bw_div(
++ mul(
++ mul(
++ mul(
++ (add(
++ add(
++ mul(
++ vbios->mcifwrmc_urgent_latency,
++ int_to_fixed(
++ 2)),
++ results->dmif_burst_time[i][j]),
++ results->mcifwr_burst_time[y_clk_level][sclk_level])),
++ results->dispclk),
++ results->bytes_per_pixel[k]),
++ results->lines_interleaved_in_mem_access[k]),
++ results->latency_hiding_lines[k])),
++ results->adjusted_data_buffer_size[k])),
++ (sub(
++ bw_div(
++ mul(
++ mul(
++ results->dispclk,
++ results->bytes_per_pixel[k]),
++ results->lines_interleaved_in_mem_access[k]),
++ results->latency_hiding_lines[k]),
++ bw_div(
++ mul(
++ results->display_bandwidth[k],
++ results->useful_bytes_per_request[k]),
++ results->bytes_per_request[k])))));
++ }
++ }
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (surface_type[i] == def_display_write_back420_luma
++ || surface_type[i]
++ == def_display_write_back420_chroma) {
++ results->pixels_per_data_fifo_entry[i] =
++ int_to_fixed(16);
++ } else if (surface_type[i] == def_graphics) {
++ results->pixels_per_data_fifo_entry[i] = bw_div(
++ int_to_fixed(64),
++ results->bytes_per_pixel[i]);
++ } else if (results->orthogonal_rotation[i] == false) {
++ results->pixels_per_data_fifo_entry[i] =
++ int_to_fixed(16);
++ } else {
++ results->pixels_per_data_fifo_entry[i] = bw_div(
++ int_to_fixed(16),
++ results->bytes_per_pixel[i]);
++ }
++ }
++ }
++ results->min_pixels_per_data_fifo_entry = int_to_fixed(9999);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (gtn(results->min_pixels_per_data_fifo_entry,
++ results->pixels_per_data_fifo_entry[i])) {
++ results->min_pixels_per_data_fifo_entry =
++ results->pixels_per_data_fifo_entry[i];
++ }
++ }
++ }
++ results->sclk_deep_sleep = bw_max(
++ bw_div(mul(results->dispclk, frc_to_fixed(115, 100)),
++ results->min_pixels_per_data_fifo_entry),
++ results->total_read_request_bandwidth);
++ results->chunk_request_time = int_to_fixed(0);
++ results->cursor_request_time = int_to_fixed(0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->chunk_request_time =
++ add(results->chunk_request_time,
++ bw_div(
++ bw_div(
++ mul(pixels_per_chunk,
++ results->bytes_per_pixel[i]),
++ results->useful_bytes_per_request[i]),
++ bw_min(sclk[sclk_level],
++ bw_div(results->dispclk,
++ int_to_fixed(
++ 2)))));
++ }
++ }
++ results->cursor_request_time = (bw_div(results->cursor_total_data,
++ (mul(sclk[sclk_level], int_to_fixed(32)))));
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->line_source_pixels_transfer_time =
++ bw_max(
++ bw_div(
++ bw_div(
++ results->src_pixels_for_first_output_pixel[i],
++ dceip->lb_write_pixels_per_dispclk),
++ (bw_div(results->dispclk,
++ dceip->display_pipe_throughput_factor))),
++ sub(
++ bw_div(
++ bw_div(
++ results->src_pixels_for_last_output_pixel[i],
++ dceip->lb_write_pixels_per_dispclk),
++ (bw_div(results->dispclk,
++ dceip->display_pipe_throughput_factor))),
++ results->active_time[i]));
++ if (surface_type[i] != def_display_write_back420_luma
++ && surface_type[i]
++ != def_display_write_back420_chroma) {
++ results->urgent_watermark[i] =
++ add(
++ add(
++ add(
++ add(
++ add(
++ results->total_dmifmc_urgent_latency,
++ results->dmif_burst_time[y_clk_level][sclk_level]),
++ bw_max(
++ results->line_source_pixels_transfer_time,
++ results->line_source_transfer_time[i][y_clk_level][sclk_level])),
++ vbios->blackout_duration),
++ results->chunk_request_time),
++ results->cursor_request_time);
++ results->stutter_exit_watermark[i] =
++ add(
++ sub(
++ vbios->stutter_self_refresh_exit_latency,
++ results->total_dmifmc_urgent_latency),
++ results->urgent_watermark[i]);
++ results->nbp_state_change_watermark[i] =
++ sub(
++ add(
++ sub(
++ vbios->nbp_state_change_latency,
++ results->total_dmifmc_urgent_latency),
++ results->urgent_watermark[i]),
++ vbios->blackout_duration);
++ } else {
++ results->urgent_watermark[i] =
++ add(
++ add(
++ add(
++ add(
++ add(
++ vbios->mcifwrmc_urgent_latency,
++ results->mcifwr_burst_time[y_clk_level][sclk_level]),
++ bw_max(
++ results->line_source_pixels_transfer_time,
++ results->line_source_transfer_time[i][y_clk_level][sclk_level])),
++ vbios->blackout_duration),
++ results->chunk_request_time),
++ results->cursor_request_time);
++ results->stutter_exit_watermark[i] =
++ int_to_fixed(0);
++ results->nbp_state_change_watermark[i] =
++ add(
++ sub(
++ add(
++ vbios->nbp_state_change_latency,
++ results->dmif_burst_time[y_clk_level][sclk_level]),
++ vbios->mcifwrmc_urgent_latency),
++ results->urgent_watermark[i]);
++ }
++ }
++ }
++ results->stutter_mode_enable = results->cpuc_state_change_enable;
++ if (mode_data->number_of_displays > 1) {
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (gtn(results->stutter_exit_watermark[i],
++ results->cursor_latency_hiding[i])) {
++ results->stutter_mode_enable = false;
++ }
++ }
++ }
++ }
++ results->dmifdram_access_efficiency =
++ bw_min(
++ bw_div(
++ bw_div(
++ results->total_display_reads_required_dram_access_data,
++ results->dram_bandwidth),
++ results->dmif_total_page_close_open_time),
++ int_to_fixed(1));
++ if (gtn(results->total_display_writes_required_dram_access_data,
++ int_to_fixed(0))) {
++ results->mcifwrdram_access_efficiency =
++ bw_min(
++ bw_div(
++ bw_div(
++ results->total_display_writes_required_dram_access_data,
++ results->dram_bandwidth),
++ results->mcifwr_total_page_close_open_time),
++ int_to_fixed(1));
++ } else {
++ results->mcifwrdram_access_efficiency = int_to_fixed(0);
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->average_bandwidth_no_compression[i] =
++ bw_div(
++ mul(
++ mul(
++ bw_div(
++ mul(
++ results->source_width_rounded_up_to_chunks[i],
++ results->bytes_per_pixel[i]),
++ (bw_div(
++ results->h_total[i],
++ results->pixel_rate[i]))),
++ results->vsr[i]),
++ results->bytes_per_request[i]),
++ results->useful_bytes_per_request[i]);
++ results->average_bandwidth[i] = bw_div(
++ results->average_bandwidth_no_compression[i],
++ results->compression_rate[i]);
++ }
++ }
++ results->total_average_bandwidth_no_compression = int_to_fixed(0);
++ results->total_average_bandwidth = int_to_fixed(0);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->total_average_bandwidth_no_compression = add(
++ results->total_average_bandwidth_no_compression,
++ results->average_bandwidth_no_compression[i]);
++ results->total_average_bandwidth = add(
++ results->total_average_bandwidth,
++ results->average_bandwidth[i]);
++ }
++ }
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->stutter_cycle_duration[i] =
++ sub(
++ mul(
++ bw_div(
++ bw_div(
++ mul(
++ bw_div(
++ bw_div(
++ results->adjusted_data_buffer_size[i],
++ results->bytes_per_pixel[i]),
++ results->source_width_rounded_up_to_chunks[i]),
++ results->h_total[i]),
++ results->vsr[i]),
++ results->pixel_rate[i]),
++ results->compression_rate[i]),
++ bw_max(int_to_fixed(0),
++ sub(
++ results->stutter_exit_watermark[i],
++ bw_div(
++ mul(
++ (add(
++ results->line_buffer_prefetch[i],
++ int_to_fixed(
++ 2))),
++ results->h_total[i]),
++ results->pixel_rate[i]))));
++ }
++ }
++ results->total_stutter_cycle_duration = int_to_fixed(9999);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ if (gtn(results->total_stutter_cycle_duration,
++ results->stutter_cycle_duration[i])) {
++ results->total_stutter_cycle_duration =
++ results->stutter_cycle_duration[i];
++ }
++ }
++ }
++ results->stutter_burst_time = bw_div(
++ mul(results->total_stutter_cycle_duration,
++ results->total_average_bandwidth),
++ bw_min(
++ (mul(results->dram_bandwidth,
++ results->dmifdram_access_efficiency)),
++ mul(sclk[sclk_level], vbios->data_return_bus_width)));
++ results->time_in_self_refresh = sub(
++ sub(results->total_stutter_cycle_duration,
++ vbios->stutter_self_refresh_exit_latency),
++ results->stutter_burst_time);
++ if (mode_data->d1_display_write_back_dwb_enable == true) {
++ results->stutter_efficiency = int_to_fixed(0);
++ } else if (ltn(results->time_in_self_refresh, int_to_fixed(0))) {
++ results->stutter_efficiency = int_to_fixed(0);
++ } else {
++ results->stutter_efficiency = mul(
++ bw_div(results->time_in_self_refresh,
++ results->total_stutter_cycle_duration),
++ int_to_fixed(100));
++ }
++ results->worst_number_of_trips_to_memory = int_to_fixed(1);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]
++ && results->scatter_gather_enable_for_pipe[i] == true) {
++ results->number_of_trips_to_memory_for_getting_apte_row[i] =
++ bw_ceil(
++ bw_div(
++ results->scatter_gather_pte_requests_in_row[i],
++ results->scatter_gather_pte_request_limit[i]),
++ int_to_fixed(1));
++ if (ltn(results->worst_number_of_trips_to_memory,
++ results->number_of_trips_to_memory_for_getting_apte_row[i])) {
++ results->worst_number_of_trips_to_memory =
++ results->number_of_trips_to_memory_for_getting_apte_row[i];
++ }
++ }
++ }
++ results->immediate_flip_time = mul(
++ results->worst_number_of_trips_to_memory,
++ results->total_dmifmc_urgent_latency);
++ results->latency_for_non_dmif_clients = add(
++ results->total_dmifmc_urgent_latency,
++ results->dmif_burst_time[y_clk_level][sclk_level]);
++ if (mode_data->d1_display_write_back_dwb_enable == true) {
++ results->latency_for_non_mcifwr_clients = add(
++ vbios->mcifwrmc_urgent_latency,
++ dceip->mcifwr_all_surfaces_burst_time);
++ } else {
++ results->latency_for_non_mcifwr_clients = int_to_fixed(0);
++ }
++ results->dmifmc_urgent_latency_supported_in_high_sclk_and_yclk = bw_div(
++ (sub(results->min_read_buffer_size_in_time,
++ results->dmif_burst_time[high][high])),
++ results->total_dmifmc_urgent_trips);
++ results->nbp_state_dram_speed_change_margin = int_to_fixed(9999);
++ for (i = 0; i <= maximum_number_of_surfaces - 1; i += 1) {
++ if (results->enable[i]) {
++ results->nbp_state_dram_speed_change_margin =
++ bw_min(
++ results->nbp_state_dram_speed_change_margin,
++ sub(
++ results->maximum_latency_hiding_with_cursor[i],
++ results->nbp_state_change_watermark[i]));
++ }
++ }
++ for (i = 1; i <= 5; i += 1) {
++ results->display_reads_time_for_data_transfer_and_urgent_latency =
++ sub(results->min_read_buffer_size_in_time,
++ mul(results->total_dmifmc_urgent_trips,
++ int_to_fixed(i)));
++ if (pipe_check == def_ok
++ && (gtn(
++ results->display_reads_time_for_data_transfer_and_urgent_latency,
++ results->dmif_total_page_close_open_time))) {
++ results->dmif_required_sclk_for_urgent_latency[i] =
++ bw_div(
++ bw_div(
++ results->total_display_reads_required_data,
++ results->display_reads_time_for_data_transfer_and_urgent_latency),
++ vbios->data_return_bus_width);
++ } else {
++ results->dmif_required_sclk_for_urgent_latency[i] =
++ int_to_fixed(0);
++ }
++ }
++
++}
++
++/*******************************************************************************
++ * Public functions
++ ******************************************************************************/
++
++void bw_calcs_init(struct bw_calcs_input_dceip *bw_dceip,
++ struct bw_calcs_input_vbios *bw_vbios)
++{
++ struct bw_calcs_input_dceip dceip;
++ struct bw_calcs_input_vbios vbios;
++
++ vbios.number_of_dram_channels = int_to_fixed(2);
++ vbios.dram_channel_width_in_bits = int_to_fixed(64);
++ vbios.number_of_dram_banks = int_to_fixed(8);
++ vbios.high_yclk = int_to_fixed(1600);
++ vbios.low_yclk = frc_to_fixed(66666, 100);
++ vbios.low_sclk = int_to_fixed(200);
++ vbios.mid_sclk = int_to_fixed(300);
++ vbios.high_sclk = frc_to_fixed(62609, 100);
++ vbios.low_voltage_max_dispclk = int_to_fixed(352);
++ vbios.mid_voltage_max_dispclk = int_to_fixed(467);
++ vbios.high_voltage_max_dispclk = int_to_fixed(643);
++ vbios.data_return_bus_width = int_to_fixed(32);
++ vbios.trc = int_to_fixed(50);
++ vbios.dmifmc_urgent_latency = int_to_fixed(4);
++ vbios.stutter_self_refresh_exit_latency = frc_to_fixed(153, 10);
++ vbios.nbp_state_change_latency = frc_to_fixed(19649, 1000);
++ vbios.mcifwrmc_urgent_latency = int_to_fixed(10);
++ vbios.scatter_gather_enable = true;
++ vbios.down_spread_percentage = frc_to_fixed(5, 10);
++ vbios.cursor_width = int_to_fixed(32);
++ vbios.average_compression_rate = int_to_fixed(4);
++ vbios.number_of_request_slots_gmc_reserves_for_dmif_per_channel =
++ int_to_fixed(256);
++ vbios.blackout_duration = int_to_fixed(18); /* us */
++ vbios.maximum_blackout_recovery_time = int_to_fixed(20);
++ dceip.dmif_request_buffer_size = int_to_fixed(768);
++ dceip.de_tiling_buffer = int_to_fixed(0);
++ dceip.dcfclk_request_generation = int_to_fixed(0);
++ dceip.lines_interleaved_into_lb = int_to_fixed(2);
++ dceip.chunk_width = int_to_fixed(256);
++ dceip.number_of_graphics_pipes = int_to_fixed(3);
++ dceip.number_of_underlay_pipes = int_to_fixed(1);
++ dceip.display_write_back_supported = false;
++ dceip.argb_compression_support = false;
++ dceip.underlay_vscaler_efficiency6_bit_per_component = frc_to_fixed(
++ 35556, 10000);
++ dceip.underlay_vscaler_efficiency8_bit_per_component = frc_to_fixed(
++ 34286, 10000);
++ dceip.underlay_vscaler_efficiency10_bit_per_component = frc_to_fixed(32,
++ 10);
++ dceip.underlay_vscaler_efficiency12_bit_per_component = int_to_fixed(3);
++ dceip.graphics_vscaler_efficiency6_bit_per_component = frc_to_fixed(35,
++ 10);
++ dceip.graphics_vscaler_efficiency8_bit_per_component = frc_to_fixed(
++ 34286, 10000);
++ dceip.graphics_vscaler_efficiency10_bit_per_component = frc_to_fixed(32,
++ 10);
++ dceip.graphics_vscaler_efficiency12_bit_per_component = int_to_fixed(3);
++ dceip.alpha_vscaler_efficiency = int_to_fixed(3);
++ dceip.max_dmif_buffer_allocated = int_to_fixed(2);
++ dceip.graphics_dmif_size = int_to_fixed(12288);
++ dceip.underlay_luma_dmif_size = int_to_fixed(19456);
++ dceip.underlay_chroma_dmif_size = int_to_fixed(23552);
++ dceip.pre_downscaler_enabled = true;
++ dceip.underlay_downscale_prefetch_enabled = true;
++ dceip.lb_write_pixels_per_dispclk = int_to_fixed(1);
++ dceip.lb_size_per_component444 = int_to_fixed(82176);
++ dceip.graphics_lb_nodownscaling_multi_line_prefetching = false;
++ dceip.stutter_and_dram_clock_state_change_gated_before_cursor =
++ int_to_fixed(0);
++ dceip.underlay420_luma_lb_size_per_component = int_to_fixed(82176);
++ dceip.underlay420_chroma_lb_size_per_component = int_to_fixed(164352);
++ dceip.underlay422_lb_size_per_component = int_to_fixed(82176);
++ dceip.cursor_chunk_width = int_to_fixed(64);
++ dceip.cursor_dcp_buffer_lines = int_to_fixed(4);
++ dceip.cursor_memory_interface_buffer_pixels = int_to_fixed(64);
++ dceip.underlay_maximum_width_efficient_for_tiling = int_to_fixed(1920);
++ dceip.underlay_maximum_height_efficient_for_tiling = int_to_fixed(1080);
++ dceip.peak_pte_request_to_eviction_ratio_limiting_multiple_displays_or_single_rotated_display =
++ frc_to_fixed(3, 10);
++ dceip.peak_pte_request_to_eviction_ratio_limiting_single_display_no_rotation =
++ int_to_fixed(25);
++ dceip.minimum_outstanding_pte_request_limit = int_to_fixed(2);
++ dceip.maximum_total_outstanding_pte_requests_allowed_by_saw =
++ int_to_fixed(128);
++ dceip.limit_excessive_outstanding_dmif_requests = true;
++ dceip.linear_mode_line_request_alternation_slice = int_to_fixed(64);
++ dceip.scatter_gather_lines_of_pte_prefetching_in_linear_mode =
++ int_to_fixed(32);
++ dceip.display_write_back420_luma_mcifwr_buffer_size = int_to_fixed(
++ 12288);
++ dceip.display_write_back420_chroma_mcifwr_buffer_size = int_to_fixed(
++ 8192);
++ dceip.request_efficiency = frc_to_fixed(8, 10);
++ dceip.dispclk_per_request = int_to_fixed(2);
++ dceip.dispclk_ramping_factor = frc_to_fixed(11, 10);
++ dceip.display_pipe_throughput_factor = frc_to_fixed(105, 100);
++ dceip.scatter_gather_pte_request_rows_in_tiling_mode = int_to_fixed(2);
++ dceip.mcifwr_all_surfaces_burst_time = int_to_fixed(0); /* todo: this is a bug*/
++
++ *bw_dceip = dceip;
++ *bw_vbios = vbios;
++}
++
++/**
++ * Return:
++ * true - Display(s) configuration supported.
++ * In this case 'calcs_output' contains data for HW programming
++ * false - Display(s) configuration not supported (not enough bandwidth).
++ */
++
++bool bw_calcs(struct dc_context *ctx, const struct bw_calcs_input_dceip *dceip,
++ const struct bw_calcs_input_vbios *vbios,
++ const struct bw_calcs_input_mode_data *mode_data,
++ struct bw_calcs_output *calcs_output)
++{
++ struct bw_results_internal *bw_results_internal = dc_service_alloc(
++ ctx, sizeof(struct bw_results_internal));
++ struct bw_calcs_input_mode_data_internal *bw_data_internal =
++ dc_service_alloc(
++ ctx, sizeof(struct bw_calcs_input_mode_data_internal));
++ switch (mode_data->number_of_displays) {
++ case (3):
++ bw_data_internal->d2_htotal = int_to_fixed(
++ mode_data->displays_data[2].h_total);
++ bw_data_internal->d2_pixel_rate =
++ mode_data->displays_data[2].pixel_rate;
++ bw_data_internal->d2_graphics_src_width = int_to_fixed(
++ mode_data->displays_data[2].graphics_src_width);
++ bw_data_internal->d2_graphics_src_height = int_to_fixed(
++ mode_data->displays_data[2].graphics_src_height);
++ bw_data_internal->d2_graphics_scale_ratio =
++ mode_data->displays_data[2].graphics_scale_ratio;
++ bw_data_internal->d2_graphics_stereo_mode =
++ mode_data->displays_data[2].graphics_stereo_mode;
++ case (2):
++ bw_data_internal->d1_display_write_back_dwb_enable = false;
++ bw_data_internal->d1_underlay_mode = ul_none;
++ bw_data_internal->d1_underlay_scale_ratio = int_to_fixed(0);
++ bw_data_internal->d1_htotal = int_to_fixed(
++ mode_data->displays_data[1].h_total);
++ bw_data_internal->d1_pixel_rate =
++ mode_data->displays_data[1].pixel_rate;
++ bw_data_internal->d1_graphics_src_width = int_to_fixed(
++ mode_data->displays_data[1].graphics_src_width);
++ bw_data_internal->d1_graphics_src_height = int_to_fixed(
++ mode_data->displays_data[1].graphics_src_height);
++ bw_data_internal->d1_graphics_scale_ratio =
++ mode_data->displays_data[1].graphics_scale_ratio;
++ bw_data_internal->d1_graphics_stereo_mode =
++ mode_data->displays_data[1].graphics_stereo_mode;
++
++ case (1):
++ bw_data_internal->d0_fbc_enable =
++ mode_data->displays_data[0].fbc_enable;
++ bw_data_internal->d0_lpt_enable =
++ mode_data->displays_data[0].lpt_enable;
++ bw_data_internal->d0_underlay_mode =
++ mode_data->displays_data[0].underlay_mode;
++ bw_data_internal->d0_underlay_scale_ratio = int_to_fixed(0);
++ bw_data_internal->d0_htotal = int_to_fixed(
++ mode_data->displays_data[0].h_total);
++ bw_data_internal->d0_pixel_rate =
++ mode_data->displays_data[0].pixel_rate;
++ bw_data_internal->d0_graphics_src_width = int_to_fixed(
++ mode_data->displays_data[0].graphics_src_width);
++ bw_data_internal->d0_graphics_src_height = int_to_fixed(
++ mode_data->displays_data[0].graphics_src_height);
++ bw_data_internal->d0_graphics_scale_ratio =
++ mode_data->displays_data[0].graphics_scale_ratio;
++ bw_data_internal->d0_graphics_stereo_mode =
++ mode_data->displays_data[0].graphics_stereo_mode;
++
++ default:
++ /* data for all displays */
++ bw_data_internal->number_of_displays =
++ mode_data->number_of_displays;
++ bw_data_internal->graphics_rotation_angle = int_to_fixed(
++ mode_data->displays_data[0].graphics_rotation_angle);
++ bw_data_internal->underlay_rotation_angle = int_to_fixed(
++ mode_data->displays_data[0].underlay_rotation_angle);
++ bw_data_internal->underlay_surface_type =
++ mode_data->displays_data[0].underlay_surface_type;
++ bw_data_internal->panning_and_bezel_adjustment =
++ mode_data->displays_data[0].panning_and_bezel_adjustment;
++ bw_data_internal->graphics_tiling_mode =
++ mode_data->displays_data[0].graphics_tiling_mode;
++ bw_data_internal->graphics_interlace_mode =
++ mode_data->displays_data[0].graphics_interlace_mode;
++ bw_data_internal->graphics_bytes_per_pixel = int_to_fixed(
++ mode_data->displays_data[0].graphics_bytes_per_pixel);
++ bw_data_internal->graphics_htaps = int_to_fixed(
++ mode_data->displays_data[0].graphics_h_taps);
++ bw_data_internal->graphics_vtaps = int_to_fixed(
++ mode_data->displays_data[0].graphics_v_taps);
++ bw_data_internal->graphics_lb_bpc = int_to_fixed(
++ mode_data->displays_data[0].graphics_lb_bpc);
++ bw_data_internal->underlay_lb_bpc = int_to_fixed(
++ mode_data->displays_data[0].underlay_lb_bpc);
++ bw_data_internal->underlay_tiling_mode =
++ mode_data->displays_data[0].underlay_tiling_mode;
++ bw_data_internal->underlay_htaps = int_to_fixed(
++ mode_data->displays_data[0].underlay_h_taps);
++ bw_data_internal->underlay_vtaps = int_to_fixed(
++ mode_data->displays_data[0].underlay_v_taps);
++ bw_data_internal->underlay_src_width = int_to_fixed(
++ mode_data->displays_data[0].underlay_src_width);
++ bw_data_internal->underlay_src_height = int_to_fixed(
++ mode_data->displays_data[0].underlay_src_height);
++ bw_data_internal->underlay_pitch_in_pixels = int_to_fixed(
++ mode_data->displays_data[0].underlay_pitch_in_pixels);
++ bw_data_internal->underlay_stereo_mode =
++ mode_data->displays_data[0].underlay_stereo_mode;
++ bw_data_internal->display_synchronization_enabled =
++ mode_data->display_synchronization_enabled;
++ }
++
++ if (bw_data_internal->number_of_displays != 0) {
++ struct bw_fixed high_sclk = vbios->high_sclk;
++ struct bw_fixed low_sclk = vbios->low_sclk;
++ struct bw_fixed high_yclk = vbios->high_yclk;
++ struct bw_fixed low_yclk = vbios->low_yclk;
++
++ ((struct bw_calcs_input_vbios *)vbios)->low_yclk = low_yclk;
++ ((struct bw_calcs_input_vbios *)vbios)->high_yclk = low_yclk;
++ ((struct bw_calcs_input_vbios *)vbios)->low_sclk = low_sclk;
++ ((struct bw_calcs_input_vbios *)vbios)->mid_sclk = low_sclk;
++ ((struct bw_calcs_input_vbios *)vbios)->high_sclk = low_sclk;
++ calculate_bandwidth(dceip, vbios, bw_data_internal,
++ bw_results_internal);
++
++ /* units: nanosecond, 16bit storage. */
++ calcs_output->nbp_state_change_watermark[0].b_mark =
++ mul(bw_results_internal->nbp_state_change_watermark[4],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->nbp_state_change_watermark[1].b_mark =
++ mul(bw_results_internal->nbp_state_change_watermark[5],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->nbp_state_change_watermark[2].b_mark =
++ mul(bw_results_internal->nbp_state_change_watermark[6],
++ int_to_fixed(1000)).value >> 24;
++
++ calcs_output->stutter_exit_watermark[0].b_mark =
++ mul(bw_results_internal->stutter_exit_watermark[4],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->stutter_exit_watermark[1].b_mark =
++ mul(bw_results_internal->stutter_exit_watermark[5],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->stutter_exit_watermark[2].b_mark =
++ mul(bw_results_internal->stutter_exit_watermark[6],
++ int_to_fixed(1000)).value >> 24;
++
++ calcs_output->urgent_watermark[0].b_mark =
++ mul(bw_results_internal->urgent_watermark[4],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->urgent_watermark[1].b_mark =
++ mul(bw_results_internal->urgent_watermark[5],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->urgent_watermark[2].b_mark =
++ mul(bw_results_internal->urgent_watermark[6],
++ int_to_fixed(1000)).value >> 24;
++
++ ((struct bw_calcs_input_vbios *)vbios)->low_yclk = high_yclk;
++ ((struct bw_calcs_input_vbios *)vbios)->high_yclk = high_yclk;
++ ((struct bw_calcs_input_vbios *)vbios)->low_sclk = high_sclk;
++ ((struct bw_calcs_input_vbios *)vbios)->mid_sclk = high_sclk;
++ ((struct bw_calcs_input_vbios *)vbios)->high_sclk = high_sclk;
++
++ calculate_bandwidth(dceip, vbios, bw_data_internal,
++ bw_results_internal);
++
++ calcs_output->nbp_state_change_watermark[0].a_mark =
++ mul(bw_results_internal->nbp_state_change_watermark[4],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->nbp_state_change_watermark[1].a_mark =
++ mul(bw_results_internal->nbp_state_change_watermark[5],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->nbp_state_change_watermark[2].a_mark =
++ mul(bw_results_internal->nbp_state_change_watermark[6],
++ int_to_fixed(1000)).value >> 24;
++
++ calcs_output->stutter_exit_watermark[0].a_mark =
++ mul(bw_results_internal->stutter_exit_watermark[4],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->stutter_exit_watermark[1].a_mark =
++ mul(bw_results_internal->stutter_exit_watermark[5],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->stutter_exit_watermark[2].a_mark =
++ mul(bw_results_internal->stutter_exit_watermark[6],
++ int_to_fixed(1000)).value >> 24;
++
++ calcs_output->urgent_watermark[0].a_mark =
++ mul(bw_results_internal->urgent_watermark[4],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->urgent_watermark[1].a_mark =
++ mul(bw_results_internal->urgent_watermark[5],
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->urgent_watermark[2].a_mark =
++ mul(bw_results_internal->urgent_watermark[6],
++ int_to_fixed(1000)).value >> 24;
++
++ calcs_output->nbp_state_change_enable =
++ bw_results_internal->nbp_state_change_enable;
++ calcs_output->cpuc_state_change_enable =
++ bw_results_internal->cpuc_state_change_enable;
++ calcs_output->cpup_state_change_enable =
++ bw_results_internal->cpup_state_change_enable;
++ calcs_output->stutter_mode_enable =
++ bw_results_internal->stutter_mode_enable;
++ calcs_output->dispclk =
++ mul(bw_results_internal->dispclk,
++ int_to_fixed(1000)).value >> 24;
++ calcs_output->required_sclk =
++ mul(bw_results_internal->required_sclk,
++ int_to_fixed(1000)).value >> 24;
++
++ ((struct bw_calcs_input_vbios *)vbios)->low_yclk = low_yclk;
++ ((struct bw_calcs_input_vbios *)vbios)->high_yclk = high_yclk;
++ ((struct bw_calcs_input_vbios *)vbios)->low_sclk = low_sclk;
++ ((struct bw_calcs_input_vbios *)vbios)->mid_sclk = high_sclk;
++ ((struct bw_calcs_input_vbios *)vbios)->high_sclk = high_sclk;
++ } else {
++ calcs_output->nbp_state_change_enable = true;
++ calcs_output->cpuc_state_change_enable = true;
++ calcs_output->cpup_state_change_enable = true;
++ calcs_output->stutter_mode_enable = true;
++ calcs_output->dispclk = 0;
++ calcs_output->required_sclk = 0;
++ }
++
++ dc_service_free(ctx, bw_data_internal);
++ dc_service_free(ctx, bw_results_internal);
++ return true;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/calcs/bw_fixed.c b/drivers/gpu/drm/amd/dal/dc/calcs/bw_fixed.c
+new file mode 100644
+index 0000000..6bad7c6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/calcs/bw_fixed.c
+@@ -0,0 +1,278 @@
++/*
++ * Copyright 2015 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#include "dc_services.h"
++#include "bw_fixed.h"
++
++
++#define BITS_PER_FRACTIONAL_PART 24
++
++#define MIN_I32 \
++ (long long)(-(1LL << (63 - BITS_PER_FRACTIONAL_PART)))
++
++#define MAX_I32 \
++ (long long)((1ULL << (63 - BITS_PER_FRACTIONAL_PART)) - 1)
++
++#define MIN_I64 \
++ (long long)(-(1LL << 63))
++
++#define MAX_I64 \
++ (long long)((1ULL << 63) - 1)
++
++
++#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))
++
++static unsigned long long abs_i64(long long arg)
++{
++ if (arg >= 0)
++ return (unsigned long long)(arg);
++ else
++ return (unsigned long long)(-arg);
++}
++
++struct bw_fixed bw_min3(struct bw_fixed v1, struct bw_fixed v2, struct bw_fixed v3)
++{
++ return bw_min(bw_min(v1, v2), v3);
++}
++
++struct bw_fixed bw_max3(struct bw_fixed v1, struct bw_fixed v2, struct bw_fixed v3)
++{
++ return bw_max(bw_max(v1, v2), v3);
++}
++
++struct bw_fixed int_to_fixed(long long value)
++{
++ struct bw_fixed res;
++ ASSERT(value < MAX_I32 && value > MIN_I32);
++ res.value = value << BITS_PER_FRACTIONAL_PART;
++ return res;
++}
++
++struct bw_fixed frc_to_fixed(long long numerator, long long denominator)
++{
++ struct bw_fixed res;
++ bool arg1_negative = numerator < 0;
++ bool arg2_negative = denominator < 0;
++ unsigned long long arg1_value;
++ unsigned long long arg2_value;
++ unsigned long long remainder;
++
++ /* determine integer part */
++ unsigned long long res_value;
++
++ ASSERT(denominator != 0);
++
++ arg1_value = abs_i64(numerator);
++ arg2_value = abs_i64(denominator);
++ remainder = arg1_value % arg2_value;
++ res_value = arg1_value / arg2_value;
++
++ ASSERT(res_value <= MAX_I32);
++
++ /* determine fractional part */
++ {
++ unsigned int 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 */
++ {
++ unsigned long long summand = (remainder << 1) >= arg2_value;
++
++ ASSERT(res_value <= MAX_I64 - summand);
++
++ res_value += summand;
++ }
++
++ res.value = (signed long long)(res_value);
++
++ if (arg1_negative ^ arg2_negative)
++ res.value = -res.value;
++ return res;
++}
++
++struct bw_fixed bw_min(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ return (arg1.value <= arg2.value) ? arg1 : arg2;
++}
++
++struct bw_fixed bw_max(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ return (arg2.value <= arg1.value) ? arg1 : arg2;
++}
++
++struct bw_fixed bw_floor(const struct bw_fixed arg, const struct bw_fixed significance)
++{
++ struct bw_fixed result;
++ signed long long multiplicand = arg.value / abs_i64(significance.value);
++ result.value = abs_i64(significance.value) * multiplicand;
++ ASSERT(abs_i64(result.value) <= abs_i64(arg.value));
++ return result;
++}
++
++struct bw_fixed bw_ceil(const struct bw_fixed arg, const struct bw_fixed significance)
++{
++ struct bw_fixed result;
++ result.value = arg.value + arg.value % abs_i64(significance.value);
++ if (result.value < significance.value)
++ result.value = significance.value;
++ return result;
++}
++
++struct bw_fixed add(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ struct bw_fixed res;
++
++ res.value = arg1.value + arg2.value;
++
++ return res;
++}
++
++struct bw_fixed sub(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ struct bw_fixed res;
++
++ res.value = arg1.value - arg2.value;
++
++ return res;
++}
++
++struct bw_fixed mul(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ struct bw_fixed res;
++
++ bool arg1_negative = arg1.value < 0;
++ bool arg2_negative = arg2.value < 0;
++
++ unsigned long long arg1_value = abs_i64(arg1.value);
++ unsigned long long arg2_value = abs_i64(arg2.value);
++
++ unsigned long long arg1_int = GET_INTEGER_PART(arg1_value);
++ unsigned long long arg2_int = GET_INTEGER_PART(arg2_value);
++
++ unsigned long long arg1_fra = GET_FRACTIONAL_PART(arg1_value);
++ unsigned long long arg2_fra = GET_FRACTIONAL_PART(arg2_value);
++
++ unsigned long long tmp;
++
++ res.value = arg1_int * arg2_int;
++
++ ASSERT(res.value <= MAX_I32);
++
++ res.value <<= BITS_PER_FRACTIONAL_PART;
++
++ tmp = arg1_int * arg2_fra;
++
++ ASSERT(tmp <= (unsigned long long)(MAX_I64 - res.value));
++
++ res.value += tmp;
++
++ tmp = arg2_int * arg1_fra;
++
++ ASSERT(tmp <= (unsigned long long)(MAX_I64 - res.value));
++
++ res.value += tmp;
++
++ tmp = arg1_fra * arg2_fra;
++
++ tmp = (tmp >> BITS_PER_FRACTIONAL_PART) +
++ (tmp >= (unsigned long long)(frc_to_fixed(1, 2).value));
++
++ ASSERT(tmp <= (unsigned long long)(MAX_I64 - res.value));
++
++ res.value += tmp;
++
++ if (arg1_negative ^ arg2_negative)
++ res.value = -res.value;
++ return res;
++}
++
++struct bw_fixed bw_div(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ struct bw_fixed res = frc_to_fixed(arg1.value, arg2.value);
++ return res;
++}
++
++struct bw_fixed fixed31_32_to_bw_fixed(long long raw)
++{
++ struct bw_fixed result = { 0 };
++
++ if (raw < 0) {
++ raw = -raw;
++ result.value = -(raw >> (32 - BITS_PER_FRACTIONAL_PART));
++ } else {
++ result.value = raw >> (32 - BITS_PER_FRACTIONAL_PART);
++ }
++
++ return result;
++}
++
++bool equ(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ return arg1.value == arg2.value;
++}
++
++bool neq(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ return arg1.value != arg2.value;
++}
++
++bool leq(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ return arg1.value <= arg2.value;
++}
++
++bool geq(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ return arg1.value >= arg2.value;
++}
++
++bool ltn(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ return arg1.value < arg2.value;
++}
++
++bool gtn(const struct bw_fixed arg1, const struct bw_fixed arg2)
++{
++ return arg1.value > arg2.value;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.c b/drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.c
+new file mode 100644
+index 0000000..f8ee65e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.c
+@@ -0,0 +1,1992 @@
++/* 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 "dal_services.h"
++#include "include/fixed31_32.h"
++
++#include "scaler_filter.h"
++
++enum {
++ DOWN_DB_SCALES = 8,
++ DOWN_DB_POINTS = 11,
++
++ UP_DB_SCALES = 1,
++ UP_DB_POINTS = 7,
++
++ MIN_SHARPNESS = -50,
++ MAX_SHARPNESS = 50,
++
++ CONST_DIVIDER = 10000000,
++
++ MAX_HOR_DOWNSCALE = 1666000, /* 1:6 */
++ MAX_VER_DOWNSCALE = 1666000, /* 1:6 */
++
++ MAX_HOR_UPSCALE = 160000000, /* 16:1 */
++ MAX_VER_UPSCALE = 160000000, /* 16:1 */
++
++ THRESHOLDRATIOLOW = 8000000, /* 0.8 */
++ THRESHOLDRATIOUP = 10000000, /* 1.0 */
++
++ DOWN_DB_FUZZY = -120411996, /* -12.041200 */
++ DOWN_DB_FLAT = -60205998, /* -6.020600 */
++ DOWN_DB_SHARP = -10000000, /* -1.000000 */
++
++ UP_DB_FUZZY = -60205998, /* -6.020600 */
++ UP_DB_FLAT = 0,
++ UP_DB_SHARP = 60205998 /* 6.020600 */
++};
++
++static inline struct fixed31_32 max_hor_downscale(void)
++{
++ return dal_fixed31_32_from_fraction(MAX_HOR_DOWNSCALE, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 max_ver_downscale(void)
++{
++ return dal_fixed31_32_from_fraction(MAX_VER_DOWNSCALE, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 max_hor_upscale(void)
++{
++ return dal_fixed31_32_from_fraction(MAX_HOR_UPSCALE, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 max_ver_upscale(void)
++{
++ return dal_fixed31_32_from_fraction(MAX_VER_UPSCALE, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 threshold_ratio_low(void)
++{
++ return dal_fixed31_32_from_fraction(THRESHOLDRATIOLOW, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 threshold_ratio_up(void)
++{
++ return dal_fixed31_32_from_fraction(THRESHOLDRATIOUP, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 down_db_fuzzy(void)
++{
++ return dal_fixed31_32_from_fraction(DOWN_DB_FUZZY, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 down_db_flat(void)
++{
++ return dal_fixed31_32_from_fraction(DOWN_DB_FLAT, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 down_db_sharp(void)
++{
++ return dal_fixed31_32_from_fraction(DOWN_DB_SHARP, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 up_db_fuzzy(void)
++{
++ return dal_fixed31_32_from_fraction(UP_DB_FUZZY, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 up_db_flat(void)
++{
++ return dal_fixed31_32_from_fraction(UP_DB_FLAT, CONST_DIVIDER);
++}
++
++static inline struct fixed31_32 up_db_sharp(void)
++{
++ return dal_fixed31_32_from_fraction(UP_DB_SHARP, CONST_DIVIDER);
++}
++
++static const int32_t
++ downscaling_db_table[][DOWN_DB_SCALES + 1][DOWN_DB_POINTS] = {
++ /* 3 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 14302719, 14302719, 14302719,
++ 10000000, 99999, 99999,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 14302339, 14302339, 14302339,
++ 10000000, 4452010, 99999,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 14302760, 14302760, 14302760,
++ 10000000, 7826979, 5258399,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 14302819, 14302819, 14302819,
++ 10000000, 8669400, 7414469,
++ 4422729, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 14302730, 14302730, 12791190,
++ 10000000, 9045640, 8180170,
++ 6477950, 4599249, 2019010,
++ 99999, 99999
++ },
++ {
++ 14302699, 14302699, 12067849,
++ 10000000, 9236029, 8541280,
++ 7252740, 6021010, 4820120,
++ 3511950, 1769340
++ },
++ {
++ 14302710, 14302710, 11783510,
++ 10000000, 9325690, 8704419,
++ 7595670, 6583020, 5652850,
++ 4749999, 3847680
++ },
++ {
++ 14302920, 14302920, 11709250,
++ 10000000, 9345560, 8754609,
++ 7692559, 6738259, 5878239,
++ 5057529, 4264070
++ }
++ },
++ /* 4 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 14308999, 14308999, 14308999,
++ 10000000, 99999, 99999,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 14308999, 14308999, 14308999,
++ 10000000, 6311039, 99999,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 14308999, 14308999, 14308999,
++ 10000000, 8526669, 6832849,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 14308999, 14308999, 12110630,
++ 10000000, 9117940, 8230940,
++ 6320130, 3719770, 99999,
++ 99999, 99999
++ },
++ {
++ 14308999, 14308999, 11474980,
++ 10000000, 9370139, 8771979,
++ 7601270, 6440780, 5249999,
++ 3887520, 2039040
++ },
++ {
++ 14308999, 13084859, 11179579,
++ 10000000, 9495180, 9016919,
++ 8134520, 7311699, 6560329,
++ 5845720, 5155519
++ },
++ {
++ 14308999, 12576600, 11048669,
++ 10000000, 9550499, 9132360,
++ 8368729, 7679399, 7073119,
++ 6520900, 6015530
++ },
++ {
++ 14308999, 12448530, 11007410,
++ 10000000, 9566799, 9165279,
++ 8435800, 7785279, 7215780,
++ 6701470, 6240640
++ }
++ },
++ /* 5 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 8971139, 8971139, 8971139,
++ 10000000, 99999, 99999,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 9466379, 9466379, 9466379,
++ 10000000, 5648760, 3834280,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 15000000, 15000000, 14550110,
++ 10000000, 7121120, 5994579,
++ 4314630, 2606149, 99999,
++ 99999, 99999
++ },
++ {
++ 15000000, 15000000, 13047469,
++ 10000000, 8368809, 7343569,
++ 5970299, 4924620, 4029389,
++ 3171139, 2276369
++ },
++ {
++ 15000000, 14157199, 11897679,
++ 10000000, 9166659, 8444600,
++ 7287240, 6374719, 5615460,
++ 4949580, 4350199
++ },
++ {
++ 15000000, 12877819, 11224579,
++ 10000000, 9488620, 9016109,
++ 8203780, 7500000, 6883730,
++ 6326839, 5818459
++ },
++ {
++ 14733040, 12233200, 10939040,
++ 10000000, 9608929, 9250000,
++ 8623390, 8076940, 7606369,
++ 7177749, 6785169
++ },
++ {
++ 14627330, 12046170, 10862360,
++ 10000000, 9639260, 9312710,
++ 8737679, 8242470, 7815709,
++ 7432209, 7082970
++ }
++ },
++ /* 6 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 8231559, 8231559, 8231559,
++ 10000000, 99999, 99999,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 8353310, 8353310, 8353310,
++ 10000000, 5504879, 4310710,
++ 870359, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 8643479, 8643479, 8643479,
++ 10000000, 6483510, 5768150,
++ 4630779, 3580690, 2501940,
++ 1015309, 99999
++ },
++ {
++ 15000000, 15000000, 13493930,
++ 10000000, 7516040, 6802409,
++ 5824409, 5080109, 4454280,
++ 3896749, 3386510
++ },
++ {
++ 15000000, 14055930, 12321079,
++ 10000000, 8872389, 8090410,
++ 7035570, 6281229, 5676810,
++ 5165010, 4717260
++ },
++ {
++ 15000000, 12915290, 11311399,
++ 10000000, 9460610, 8988440,
++ 8202149, 7548679, 6999999,
++ 6510639, 6065719
++ },
++ {
++ 14310129, 12140829, 10901659,
++ 10000000, 9635019, 9307180,
++ 8740929, 8263260, 7858849,
++ 7499330, 7170130
++ },
++ {
++ 13815449, 11911309, 10801299,
++ 10000000, 9669629, 9380580,
++ 8878319, 8452050, 8097199,
++ 7785030, 7504299
++ }
++ },
++ /* 7 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 10616660, 10616660, 10616660,
++ 10000000, 2646020, 99999,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 10099999, 10099999, 10099999,
++ 10000000, 4936839, 4112670,
++ 2729740, 896539, 99999,
++ 99999, 99999
++ },
++ {
++ 8345860, 8345860, 8345860,
++ 10000000, 6034079, 5371739,
++ 4466759, 3763799, 3155870,
++ 2588019, 2026730
++ },
++ {
++ 9298499, 9298499, 13768420,
++ 10000000, 7174239, 6524270,
++ 5670250, 5052099, 4549089,
++ 4115279, 3722150
++ },
++ {
++ 15000000, 14116940, 12563209,
++ 10000000, 8542140, 7782419,
++ 6865050, 6239479, 5758860,
++ 5351870, 4992800
++ },
++ {
++ 15000000, 12913750, 11306079,
++ 10000000, 9452580, 8969209,
++ 8168810, 7538409, 7029479,
++ 6603180, 6227809
++ },
++ {
++ 14390859, 11862809, 10757420,
++ 10000000, 9688709, 9404249,
++ 8904439, 8472480, 8099079,
++ 7765330, 7459110
++ },
++ {
++ 13752900, 11554559, 10637769,
++ 10000000, 9736120, 9499999,
++ 9079759, 8718389, 8408790,
++ 8134469, 7886120
++ }
++ },
++ /* 8 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 11277090, 11277090, 11277090,
++ 10000000, 2949059, 99999,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 11196039, 11196039, 11196039,
++ 10000000, 4627540, 4018869,
++ 3018769, 2000000, 250770,
++ 99999, 99999
++ },
++ {
++ 10878369, 10878369, 10878369,
++ 10000000, 5657230, 5118110,
++ 4372630, 3809120, 3337709,
++ 2919510, 2535369
++ },
++ {
++ 9090089, 9090089, 13961290,
++ 10000000, 6929969, 6334999,
++ 5569829, 5019649, 4584150,
++ 4208610, 3876540
++ },
++ {
++ 15000000, 14173229, 12732659,
++ 10000000, 8267070, 7575380,
++ 6764540, 6218209, 5803539,
++ 5454990, 5146239
++ },
++ {
++ 15000000, 12928279, 11292259,
++ 10000000, 9447429, 8954229,
++ 8141599, 7516989, 7039459,
++ 6649519, 6316819
++ },
++ {
++ 14661350, 11638879, 10665880,
++ 10000000, 9722669, 9464690,
++ 9013469, 8613470, 8266339,
++ 7949870, 7663450
++ },
++ {
++ 13861900, 11311980, 10543940,
++ 10000000, 9772019, 9565100,
++ 9198870, 8881340, 8609200,
++ 8365769, 8147500
++ }
++ },
++ /* 9 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ { 10099999, 10099999, 10099999,
++ 10000000, 2939159, 1526470,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 11726609, 11726609, 11726609,
++ 10000000, 4329420, 3805609,
++ 3030480, 2363760, 1732099,
++ 980139, 99999
++ },
++ {
++ 10949269, 10949269, 10949269,
++ 10000000, 5452589, 4946640,
++ 4277969, 3790729, 3392640,
++ 3048950, 2750000
++ },
++ {
++ 8830279, 8830279, 14084529,
++ 10000000, 6743149, 6182519,
++ 5482980, 5000000, 4622060,
++ 4303340, 4022600
++ },
++ {
++ 9709150, 14111399, 12800760,
++ 10000000, 7989749, 7445629,
++ 6741260, 6241980, 5857459,
++ 5534989, 5255370
++ },
++ {
++ 15000000, 12830289, 11489900,
++ 10000000, 9302089, 8767340,
++ 8025540, 7500000, 7100800,
++ 6768149, 6481850
++ },
++ {
++ 14873609, 11576000, 10650579,
++ 10000000, 9731360, 9483649,
++ 9054650, 8680559, 8358049,
++ 8066400, 7802420
++ },
++ {
++ 12981410, 11185950, 10491620,
++ 10000000, 9795730, 9611030,
++ 9286710, 9007279, 8768100,
++ 8553469, 8361340
++ }
++ },
++ /* 10 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 8993279, 8993279, 8993279,
++ 10000000, 2921360, 1905619,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 9064850, 9064850, 9064850,
++ 10000000, 4095619, 3655839,
++ 3021000, 2500000, 2031680,
++ 1566990, 1055440
++ },
++ {
++ 11043460, 11043460, 11043460,
++ 10000000, 5287479, 4816150,
++ 4208439, 3769229, 3418970,
++ 3117449, 2850320
++ },
++ {
++ 8651900, 8651900, 14169909,
++ 10000000, 6596950, 6071490,
++ 5423219, 4980779, 4644620,
++ 4362219, 4114899
++ },
++ {
++ 9246050, 14055370, 12832759,
++ 10000000, 7831320, 7369570,
++ 6731680, 6262450, 5897690,
++ 5592269, 5328789
++ },
++ {
++ 15000000, 12770450, 11642129,
++ 10000000, 9120929, 8601920,
++ 7946630, 7490440, 7140589,
++ 6847490, 6593719
++ },
++ {
++ 14062479, 11541219, 10644329,
++ 10000000, 9736120, 9495139,
++ 9080520, 8724340, 8419489,
++ 8146359, 7899820
++ },
++ {
++ 12507469, 11102950, 10457479,
++ 10000000, 9811149, 9641249,
++ 9344969, 9090980, 8875219,
++ 8684499, 8513180
++ }
++ },
++ /* 11 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 10099509, 10099509, 10099509,
++ 10000000, 2788810, 2054850,
++ 99999, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 8872069, 8872069, 8872069,
++ 10000000, 3929649, 3522840,
++ 2963230, 2527720, 2157579,
++ 1823610, 1500000
++ },
++ {
++ 10099999, 10099999, 10099999,
++ 10000000, 5155599, 4712319,
++ 4154500, 3759450, 3448629,
++ 3183139, 2948490
++ },
++ {
++ 10511649, 10511649, 14216580,
++ 10000000, 6445930, 5988820,
++ 5401239, 4988409, 4673399,
++ 4410479, 4181599
++ },
++ {
++ 9170889, 14003310, 12949769,
++ 10000000, 7684900, 7250000,
++ 6670129, 6255810, 5934680,
++ 5664110, 5427970
++ },
++ {
++ 15000000, 12763030, 11734730,
++ 10000000, 8958870, 8478559,
++ 7893459, 7489529, 7179200,
++ 6917790, 6688359
++ },
++ {
++ 14634610, 11491880, 10619130,
++ 10000000, 9744859, 9509819,
++ 9102900, 8760340, 8463050,
++ 8202620, 7968729
++ },
++ {
++ 12415319, 10980290, 10405089,
++ 10000000, 9831910, 9680110,
++ 9413710, 9184579, 8987190,
++ 8813819, 8655819
++ }
++ },
++ /* 12 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 10832400, 10832400, 10832400,
++ 10000000, 2700819, 2115820,
++ 750000, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 10747549, 10747549, 10747549,
++ 10000000, 3781630, 3415020,
++ 2914879, 2537429, 2221180,
++ 1943199, 1688420
++ },
++ {
++ 11630790, 11630790, 11630790,
++ 10000000, 5047429, 4631519,
++ 4113860, 3750000, 3469760,
++ 3229379, 3016360
++ },
++ {
++ 10780229, 10780229, 10780229,
++ 10000000, 6340010, 5935009,
++ 5387600, 4995940, 4695929,
++ 4446829, 4231610
++ },
++ {
++ 9055669, 13968739, 13037070,
++ 10000000, 7556660, 7149490,
++ 6625509, 6250000, 5958870,
++ 5713790, 5500869
++ },
++ {
++ 14614900, 12760740, 11806739,
++ 10000000, 8824530, 8388419,
++ 7857400, 7489010, 7206150,
++ 6968010, 6759889
++ },
++ {
++ 14894100, 11451840, 10598870,
++ 10000000, 9750000, 9521099,
++ 9122239, 8784019, 8494700,
++ 8243309, 8018680
++ },
++ {
++ 12298769, 10886880, 10367530,
++ 10000000, 9846829, 9708030,
++ 9464049, 9252949, 9072539,
++ 8910980, 8766649
++ }
++ },
++ /* 13 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 10099999, 10099999, 10099999,
++ 10000000, 2574490, 2099110,
++ 1194889, 99999, 99999,
++ 99999, 99999
++ },
++ {
++ 10099999, 10099999, 10099999,
++ 10000000, 3679780, 3332070,
++ 2869139, 2530030, 2251899,
++ 2010450, 1793050
++ },
++ {
++ 9306690, 9306690, 9306690,
++ 10000000, 4964010, 4573009,
++ 4082309, 3742089, 3481810,
++ 3262990, 3070969
++ },
++ {
++ 10099999, 10099999, 10099999,
++ 10000000, 6217889, 5843269,
++ 5353810, 5000000, 4730190,
++ 4499999, 4301390
++ },
++ {
++ 8819990, 13964320, 13098440,
++ 10000000, 7454770, 7075160,
++ 6591439, 6250000, 5983970,
++ 5760229, 5564339
++ },
++ {
++ 14432849, 12727780, 11847709,
++ 10000000, 8695709, 8322049,
++ 7842620, 7500000, 7234820,
++ 7010849, 6814730
++ },
++ {
++ 15000000, 11440130, 10620100,
++ 10000000, 9742270, 9508739,
++ 9110010, 8782560, 8510140,
++ 8276290, 8069980
++ },
++ {
++ 12039999, 10825289, 10341939,
++ 10000000, 9858080, 9729740,
++ 9505100, 9310669, 9144560,
++ 8996559, 8862569
++ }
++ },
++ /* 14 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 9289590, 9289590, 9289590,
++ 10000000, 2485270, 2084970,
++ 1362659, 250000, 99999,
++ 99999, 99999
++ },
++ {
++ 9484500, 9484500, 9484500,
++ 10000000, 3593840, 3263100,
++ 2833609, 2519409, 2267650,
++ 2050379, 1856749
++ },
++ {
++ 9237130, 9237130, 9237130,
++ 10000000, 4898909, 4527629,
++ 4057880, 3734529, 3490320,
++ 3287230, 3111050
++ },
++ {
++ 9543399, 9543399, 9543399,
++ 10000000, 6110230, 5772359,
++ 5328080, 5007240, 4757330,
++ 4545379, 4359109
++ },
++ {
++ 9032660, 9032660, 9032660,
++ 10000000, 7373520, 7016940,
++ 6565740, 6250000, 6002650,
++ 5794939, 5610830
++ },
++ {
++ 14351329, 12697319, 11875350,
++ 10000000, 8606730, 8275989,
++ 7833449, 7510430, 7257339,
++ 7043970, 6857690
++ },
++ {
++ 13286800, 11436090, 10643019,
++ 10000000, 9729470, 9491149,
++ 9096930, 8778640, 8519319,
++ 8299450, 8104829
++ },
++ {
++ 11838380, 10778709, 10322740,
++ 10000000, 9866499, 9746059,
++ 9535790, 9354810, 9200339,
++ 9063839, 8940430
++ }
++ },
++ /* 15 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 9193199, 9193199, 9193199,
++ 10000000, 2400999, 2042409,
++ 1450179, 789309, 99999,
++ 99999, 99999
++ },
++ {
++ 10755189, 10755189, 10755189,
++ 10000000, 3532319, 3212479,
++ 2803660, 2510200, 2278629,
++ 2078720, 1899970
++ },
++ {
++ 8732669, 8732669, 8732669,
++ 10000000, 4821290, 4483030,
++ 4045079, 3737959, 3505080,
++ 3311960, 3143329
++ },
++ {
++ 9450280, 9450280, 9450280,
++ 10000000, 6040880, 5718960,
++ 5302609, 5004199, 4771710,
++ 4575310, 4404180
++ },
++ {
++ 10520930, 10520930, 10520930,
++ 10000000, 7298259, 6975160,
++ 6552690, 6250000, 6018469,
++ 5822089, 5648869
++ },
++ {
++ 14320160, 12683949, 11917040,
++ 10000000, 8541300, 8228710,
++ 7812070, 7509459, 7272909,
++ 7072560, 6895729
++ },
++ {
++ 15000000, 11434819, 10650700,
++ 10000000, 9723110, 9480339,
++ 9083300, 8771640, 8524850,
++ 8317480, 8135899
++ },
++ {
++ 11750520, 10722860, 10299190,
++ 10000000, 9875990, 9763770,
++ 9567070, 9397709, 9252669,
++ 9124029, 9008929
++ }
++ },
++ /* 16 tap downscaling */
++ {
++ {
++ 60209999, 40000000, 20000000,
++ 0, -10000000, -20000000,
++ -40000000, -60209999, -80000000,
++ -100000000, -120410003
++ },
++ {
++ 10612260, 10612260, 10612260,
++ 10000000, 2308720, 1999289,
++ 1495770, 1009820, 315460,
++ 99999, 99999
++ },
++ {
++ 9394969, 9394969, 9394969,
++ 10000000, 3462660, 3162190,
++ 2780120, 2508420, 2295179,
++ 2109449, 1943989
++ },
++ {
++ 10609409, 10609409, 10609409,
++ 10000000, 4749999, 4447000,
++ 4039109, 3746300, 3522360,
++ 3336620, 3177059
++ },
++ {
++ 9435039, 9435039, 9435039,
++ 10000000, 5978109, 5675160,
++ 5282300, 5000000, 4782429,
++ 4598149, 4438050
++ },
++ {
++ 10592620, 10592620, 10592620,
++ 10000000, 7244589, 6940630,
++ 6537730, 6250000, 6027920,
++ 5842260, 5680159
++ },
++ {
++ 14282959, 12678509, 11963449,
++ 10000000, 8484349, 8181620,
++ 7785459, 7500000, 7281309,
++ 7095699, 6932809
++ },
++ {
++ 15000000, 11434919, 10673819,
++ 10000000, 9708179, 9456859,
++ 9060000, 8760929, 8529940,
++ 8338279, 8172209
++ },
++ {
++ 11690390, 10668220, 10277210,
++ 10000000, 9884750, 9780330,
++ 9597110, 9439319, 9304260,
++ 9183580, 9075019
++ }
++ }
++};
++
++static const int32_t upscaling_db_table[][UP_DB_SCALES+1][UP_DB_POINTS] = {
++ /* 3 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 14302920, 14302920, 11709250,
++ 10000000,
++ 8754609, 7692559, 6738259
++ }
++ },
++ /* 4 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 14308999, 12448530, 11007410,
++ 10000000, 9165279, 8435800,
++ 7785279
++ }
++ },
++ /* 5 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 14627330, 12046170, 10862360,
++ 10000000,
++ 9312710, 8737679, 8242470
++ }
++ },
++ /* 6 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 13815449, 11911309, 10801299,
++ 10000000,
++ 9380580, 8878319, 8452050
++ }
++ },
++ /* 7 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 13752900, 11554559, 10637769,
++ 10000000,
++ 9499999, 9079759, 8718389
++ }
++ },
++ /* 8 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 13861900, 11311980, 10543940,
++ 10000000,
++ 9565100, 9198870, 8881340
++ }
++ },
++ /* 9 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 12981410, 11185950, 10491620,
++ 10000000,
++ 9611030, 9286710, 9007279
++ }
++ },
++ /* 10 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 12507469, 11102950, 10457479,
++ 10000000,
++ 9641249, 9344969, 9090980
++ }
++ },
++ /* 11 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 12415319, 10980290, 10405089,
++ 10000000,
++ 9680110, 9413710, 9184579
++ }
++ },
++ /* 12 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 12298769, 10886880, 10367530,
++ 10000000,
++ 9708030, 9464049, 9252949
++ }
++ },
++ /* 13 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 12039999, 10825289, 10341939,
++ 10000000,
++ 9729740, 9505100, 9310669
++ }
++ },
++ /* 14 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 11838380, 10778709, 10322740,
++ 10000000,
++ 9746059, 9535790, 9354810
++ }
++ },
++ /* 15 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 11750520, 10722860, 10299190,
++ 10000000,
++ 9763770, 9567070, 9397709
++ }
++ },
++ /* 16 tap upscaling */
++ {
++ {
++ 60209999, 40000000, 20000000, 0,
++ -20000000, -40000000, -60209999
++ },
++ {
++ 11690390, 10668220, 10277210,
++ 10000000,
++ 9780330, 9597110, 9439319
++ }
++ }
++};
++
++static bool allocate_3d_storage(
++ struct dc_context *ctx,
++ struct fixed31_32 ****ptr,
++ int32_t numberof_tables,
++ int32_t numberof_rows,
++ int32_t numberof_columns)
++{
++ int32_t indexof_table = 0;
++ int32_t indexof_row = 0;
++
++ struct fixed31_32 ***tables = dc_service_alloc(
++ ctx,
++ numberof_tables * sizeof(struct fixed31_32 **));
++
++ if (!tables) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ while (indexof_table != numberof_tables) {
++ struct fixed31_32 **rows = dc_service_alloc(
++ ctx,
++ numberof_rows * sizeof(struct fixed31_32 *));
++
++ if (!rows) {
++ BREAK_TO_DEBUGGER();
++ --indexof_table;
++ goto failure;
++ }
++
++ tables[indexof_table] = rows;
++
++ while (indexof_row != numberof_rows) {
++ struct fixed31_32 *columns = dc_service_alloc(
++ ctx,
++ numberof_columns * sizeof(struct fixed31_32));
++
++ if (!columns) {
++ BREAK_TO_DEBUGGER();
++ --indexof_row;
++ goto failure;
++ }
++
++ rows[indexof_row] = columns;
++
++ ++indexof_row;
++ }
++
++ indexof_row = 0;
++
++ ++indexof_table;
++ }
++
++ *ptr = tables;
++
++ return true;
++
++failure:
++
++ while (indexof_table >= 0) {
++ while (indexof_row >= 0) {
++ dc_service_free(ctx, tables[indexof_table][indexof_row]);
++
++ --indexof_row;
++ }
++
++ indexof_row = numberof_rows - 1;
++
++ dc_service_free(ctx, tables[indexof_table]);
++
++ --indexof_table;
++ }
++
++ dc_service_free(ctx, tables);
++
++ return false;
++}
++
++static void destroy_3d_storage(
++ struct dc_context *ctx,
++ struct fixed31_32 ****ptr,
++ uint32_t numberof_tables,
++ uint32_t numberof_rows)
++{
++ struct fixed31_32 ***tables = *ptr;
++
++ uint32_t indexof_table = 0;
++
++ if (!tables)
++ return;
++
++ while (indexof_table != numberof_tables) {
++ uint32_t indexof_row = 0;
++
++ while (indexof_row != numberof_rows) {
++ dc_service_free(
++ ctx, tables[indexof_table][indexof_row]);
++
++ ++indexof_row;
++ };
++
++ dc_service_free(ctx, tables[indexof_table]);
++
++ ++indexof_table;
++ };
++
++ dc_service_free(ctx, tables);
++
++ *ptr = NULL;
++}
++
++static bool create_downscaling_table(
++ struct scaler_filter *filter)
++{
++ const int32_t numberof_tables =
++ ARRAY_SIZE(downscaling_db_table);
++ const int32_t numberof_rows =
++ ARRAY_SIZE(downscaling_db_table[0]);
++ const int32_t numberof_columns =
++ ARRAY_SIZE(downscaling_db_table[0][0]);
++
++ int32_t indexof_table = 0;
++
++ if (!allocate_3d_storage(filter->ctx, &filter->downscaling_table,
++ numberof_tables, numberof_rows, numberof_columns)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ while (indexof_table != numberof_tables) {
++ struct fixed31_32 **table =
++ filter->downscaling_table[indexof_table];
++
++ int32_t indexof_row = 0;
++
++ while (indexof_row != numberof_rows) {
++ struct fixed31_32 *row = table[indexof_row];
++
++ int32_t indexof_column = 0;
++
++ while (indexof_column != numberof_columns) {
++ row[indexof_column] =
++dal_fixed31_32_from_fraction(
++ downscaling_db_table[indexof_table][indexof_row][indexof_column],
++ CONST_DIVIDER);
++
++ ++indexof_column;
++ }
++
++ ++indexof_row;
++ }
++
++ ++indexof_table;
++ }
++
++ return true;
++}
++
++static inline void destroy_downscaling_table(
++ struct scaler_filter *filter)
++{
++ destroy_3d_storage(
++ filter->ctx,
++ &filter->downscaling_table,
++ ARRAY_SIZE(downscaling_db_table),
++ ARRAY_SIZE(downscaling_db_table[0]));
++}
++
++static bool create_upscaling_table(
++ struct scaler_filter *filter)
++{
++ const int32_t numberof_tables =
++ ARRAY_SIZE(upscaling_db_table);
++ const int32_t numberof_rows =
++ ARRAY_SIZE(upscaling_db_table[0]);
++ const int32_t numberof_columns =
++ ARRAY_SIZE(upscaling_db_table[0][0]);
++
++ int32_t indexof_table = 0;
++
++ if (!allocate_3d_storage(filter->ctx, &filter->upscaling_table,
++ numberof_tables, numberof_rows, numberof_columns)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ while (indexof_table != numberof_tables) {
++ struct fixed31_32 **table =
++ filter->upscaling_table[indexof_table];
++
++ int32_t indexof_row = 0;
++
++ while (indexof_row != numberof_rows) {
++ struct fixed31_32 *row = table[indexof_row];
++
++ int32_t indexof_column = 0;
++
++ while (indexof_column != numberof_columns) {
++ row[indexof_column] =
++dal_fixed31_32_from_fraction(
++ upscaling_db_table[indexof_table][indexof_row][indexof_column],
++ CONST_DIVIDER);
++
++ ++indexof_column;
++ }
++
++ ++indexof_row;
++ }
++
++ ++indexof_table;
++ }
++
++ return true;
++}
++
++static inline void destroy_upscaling_table(
++ struct scaler_filter *filter)
++{
++ destroy_3d_storage(
++ filter->ctx,
++ &filter->upscaling_table,
++ ARRAY_SIZE(upscaling_db_table),
++ ARRAY_SIZE(upscaling_db_table[0]));
++}
++
++static bool same_filter_required(
++ struct scaler_filter *filter,
++ const struct scaler_filter_params *params,
++ uint32_t src_size,
++ uint32_t dst_size)
++{
++ if (!filter->src_size)
++ return false;
++ if (!filter->dst_size)
++ return false;
++ if (filter->src_size != src_size)
++ return false;
++ if (filter->dst_size != dst_size)
++ return false;
++ if (filter->params.taps != params->taps)
++ return false;
++ if (filter->params.phases != params->phases)
++ return false;
++ if (filter->params.sharpness != params->sharpness)
++ return false;
++
++ return true;
++}
++
++/*
++ * @brief
++ * (scale_max - scale_min)
++ * result = scale_min + (value - value_min) * -----------------------
++ * (value_max - value_min)
++ */
++
++static struct fixed31_32 interpolate(
++ struct fixed31_32 value,
++ struct fixed31_32 value_min,
++ struct fixed31_32 value_max,
++ struct fixed31_32 scale_min,
++ struct fixed31_32 scale_max)
++{
++ return dal_fixed31_32_add(
++ scale_min,
++ dal_fixed31_32_div(
++ dal_fixed31_32_mul(
++ dal_fixed31_32_sub(
++ value,
++ value_min),
++ dal_fixed31_32_sub(
++ scale_max,
++ scale_min)),
++ dal_fixed31_32_sub(
++ value_max,
++ value_min)));
++}
++
++static bool map_sharpness(
++ struct scaler_filter *filter,
++ const struct scaler_filter_params *params,
++ uint32_t src_size,
++ uint32_t dst_size,
++ struct fixed31_32 *attenuation,
++ struct fixed31_32 *decibels_at_nyquist)
++{
++ struct fixed31_32 ratio = dal_fixed31_32_from_fraction(
++ dst_size,
++ src_size);
++
++ const struct fixed31_32 sharp_flat =
++ dal_fixed31_32_from_fraction(MIN_SHARPNESS + MAX_SHARPNESS, 2);
++
++ struct fixed31_32 sharp_max =
++ dal_fixed31_32_from_int(MAX_SHARPNESS);
++ struct fixed31_32 sharp_min =
++ dal_fixed31_32_from_int(MIN_SHARPNESS);
++
++ uint32_t index = params->taps - 3;
++
++ struct fixed31_32 ratio_low;
++ struct fixed31_32 ratio_up;
++
++ struct fixed31_32 db_min;
++ struct fixed31_32 db_flat;
++ struct fixed31_32 db_max;
++ struct fixed31_32 db_value;
++
++ uint32_t i0;
++ uint32_t i1;
++ uint32_t row0;
++ uint32_t row1;
++
++ int32_t sharp = params->sharpness;
++
++ if (sharp < MIN_SHARPNESS)
++ sharp = MIN_SHARPNESS;
++ else if (sharp > MAX_SHARPNESS)
++ sharp = MAX_SHARPNESS;
++
++ if (params->flags.bits.HORIZONTAL) {
++ if (dal_fixed31_32_lt(ratio, max_hor_downscale())) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ } else if (dal_fixed31_32_lt(
++ max_hor_upscale(), ratio)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++ } else {
++ if (dal_fixed31_32_lt(ratio, max_ver_downscale())) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ } else if (dal_fixed31_32_lt(
++ max_ver_upscale(), ratio)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++ }
++
++ if (dst_size >= src_size) {
++ if (sharp < 0) {
++ db_max = up_db_flat();
++ db_min = up_db_fuzzy();
++
++ sharp_max = sharp_flat;
++ } else {
++ db_max = up_db_sharp();
++ db_min = up_db_flat();
++
++ sharp_min = sharp_flat;
++ }
++
++ db_value = interpolate(
++ dal_fixed31_32_from_int(sharp),
++ sharp_min, sharp_max,
++ db_min, db_max);
++
++ i0 = 0;
++
++ while (dal_fixed31_32_lt(
++ db_value, filter->upscaling_table[index][0][i0]) &&
++ (i0 < UP_DB_POINTS - 1))
++ ++i0;
++
++ i1 = i0 + 1;
++
++ if (i0 == UP_DB_POINTS - 1)
++ i1 = i0--;
++
++ sharp_max = filter->upscaling_table[index][1][i0];
++ sharp_min = filter->upscaling_table[index][1][i1];
++
++ db_max = filter->upscaling_table[index][0][i0];
++ db_min = filter->upscaling_table[index][0][i1];
++
++ *attenuation = interpolate(
++ db_value,
++ db_max, db_min,
++ sharp_max, sharp_min);
++
++ *decibels_at_nyquist = db_value;
++
++ return true;
++ } else if ((5 * dst_size) < (src_size << 2)) {
++ if (sharp < 0) {
++ db_max = down_db_flat();
++ db_min = down_db_fuzzy();
++
++ sharp_max = sharp_flat;
++ } else {
++ db_max = down_db_sharp();
++ db_min = down_db_flat();
++
++ sharp_min = sharp_flat;
++ }
++
++ db_value = interpolate(
++ dal_fixed31_32_from_int(sharp),
++ sharp_min, sharp_max,
++ db_min, db_max);
++ } else {
++ struct fixed31_32 db_value_min =
++ filter->downscaling_table[index][0][0];
++
++ struct fixed31_32 db_value_max =
++ filter->downscaling_table[index][0][DOWN_DB_POINTS - 1];
++
++ db_min = interpolate(
++ ratio,
++ threshold_ratio_low(), threshold_ratio_up(),
++ down_db_fuzzy(), up_db_fuzzy());
++
++ db_flat = interpolate(
++ ratio,
++ threshold_ratio_low(), threshold_ratio_up(),
++ down_db_flat(), up_db_flat());
++
++ db_max = interpolate(
++ ratio,
++ threshold_ratio_low(), threshold_ratio_up(),
++ down_db_sharp(), up_db_sharp());
++
++ if (sharp < 0) {
++ db_max = db_flat;
++
++ db_value = interpolate(
++ dal_fixed31_32_from_int(sharp),
++ sharp_min, dal_fixed31_32_zero,
++ db_min, db_max);
++ } else {
++ db_min = db_flat;
++
++ db_value = interpolate(
++ dal_fixed31_32_from_int(sharp),
++ dal_fixed31_32_zero, sharp_max,
++ db_min, db_max);
++ }
++
++ if (dal_fixed31_32_lt(db_value_min, db_value))
++ db_value = db_value_min;
++ else if (dal_fixed31_32_lt(db_value, db_value_max))
++ db_value = db_value_max;
++ }
++
++ i1 = 0;
++
++ while (dal_fixed31_32_lt(db_value,
++ filter->downscaling_table[index][0][i1]) &&
++ (i1 < DOWN_DB_POINTS - 1))
++ ++i1;
++
++ if (i1 == 0)
++ i0 = i1++;
++ else
++ i0 = i1 - 1;
++
++ row0 = dal_fixed31_32_round(
++ dal_fixed31_32_mul_int(ratio, DOWN_DB_SCALES));
++
++ if (dal_fixed31_32_lt(
++ dal_fixed31_32_from_fraction(row0, DOWN_DB_SCALES), ratio)) {
++ row1 = row0 + 1;
++
++ if (row1 > DOWN_DB_SCALES) {
++ row1 = DOWN_DB_SCALES;
++ row0 = row1 - 1;
++ }
++ } else {
++ row1 = row0--;
++
++ if (row0 < 1) {
++ row0 = 1;
++ row1 = 2;
++ }
++ }
++
++ ratio_low = dal_fixed31_32_from_fraction(row0, DOWN_DB_SCALES);
++ ratio_up = dal_fixed31_32_from_fraction(row1, DOWN_DB_SCALES);
++
++ sharp_max = interpolate(
++ ratio,
++ ratio_low, ratio_up,
++ filter->downscaling_table[index][row0][i0],
++ filter->downscaling_table[index][row1][i0]);
++
++ sharp_min = interpolate(
++ ratio,
++ ratio_low, ratio_up,
++ filter->downscaling_table[index][row0][i1],
++ filter->downscaling_table[index][row1][i1]);
++
++ db_max = filter->downscaling_table[index][0][i0];
++ db_min = filter->downscaling_table[index][0][i1];
++
++ *attenuation = interpolate(
++ db_value,
++ db_max, db_min,
++ sharp_max, sharp_min);
++
++ *decibels_at_nyquist = db_value;
++
++ return true;
++}
++
++static inline struct fixed31_32 lanczos(
++ struct fixed31_32 x,
++ struct fixed31_32 a2)
++{
++ return dal_fixed31_32_mul(
++ dal_fixed31_32_sinc(x),
++ dal_fixed31_32_sinc(
++ dal_fixed31_32_mul(x, a2)));
++}
++
++static bool generate_filter(
++ struct scaler_filter *filter,
++ const struct scaler_filter_params *params,
++ struct fixed31_32 attenuation,
++ struct fixed31_32 *ringing)
++{
++ uint32_t n = params->phases * params->taps;
++
++ uint32_t coefficients_quantity = n;
++ uint32_t coefficients_sum_quantity = params->phases;
++
++ uint32_t i;
++ uint32_t i_limit;
++ uint32_t j;
++ uint32_t m;
++
++ struct fixed31_32 attenby2;
++
++ struct fixed31_32 a_max = dal_fixed31_32_zero;
++ struct fixed31_32 a_min = dal_fixed31_32_zero;
++
++ if (filter->coefficients_quantity < coefficients_quantity) {
++ if (filter->coefficients) {
++ dc_service_free(filter->ctx, filter->coefficients);
++
++ filter->coefficients = NULL;
++ filter->coefficients_quantity = 0;
++ }
++
++ filter->coefficients = dc_service_alloc(
++ filter->ctx,
++ coefficients_quantity * sizeof(struct fixed31_32));
++
++ if (!filter->coefficients) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ filter->coefficients_quantity = coefficients_quantity;
++ }
++
++ i = 0;
++
++ while (i != filter->coefficients_quantity) {
++ filter->coefficients[i] = dal_fixed31_32_zero;
++
++ ++i;
++ }
++
++ if (filter->coefficients_sum_quantity < coefficients_sum_quantity) {
++ if (filter->coefficients_sum) {
++ dc_service_free(filter->ctx, filter->coefficients_sum);
++
++ filter->coefficients_sum = NULL;
++ filter->coefficients_sum_quantity = 0;
++ }
++
++ filter->coefficients_sum = dc_service_alloc(
++ filter->ctx,
++ coefficients_sum_quantity * sizeof(struct fixed31_32));
++
++ if (!filter->coefficients_sum) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ filter->coefficients_sum_quantity = coefficients_sum_quantity;
++ }
++
++ i = 0;
++
++ while (i != filter->coefficients_sum_quantity) {
++ filter->coefficients_sum[i] = dal_fixed31_32_zero;
++
++ ++i;
++ }
++
++ m = 0;
++
++ attenby2 = dal_fixed31_32_div_int(
++ dal_fixed31_32_mul_int(attenuation, params->taps), 2);
++
++ i = 1;
++
++ while (i <= params->taps) {
++ j = 0;
++
++ while (j != params->phases) {
++ struct fixed31_32 x = dal_fixed31_32_mul(
++ dal_fixed31_32_pi,
++ dal_fixed31_32_from_fraction(
++ (int64_t)(m << 1) - n, n));
++
++ uint32_t index =
++ (params->taps - i) * params->phases + j;
++
++ filter->coefficients[index] = lanczos(x, attenby2);
++
++ ++m;
++
++ ++j;
++ }
++
++ ++i;
++ }
++
++ i = 0;
++
++ while (i != params->phases) {
++ filter->coefficients_sum[i] = dal_fixed31_32_zero;
++
++ m = i;
++
++ j = 0;
++
++ while (j != params->taps) {
++ filter->coefficients_sum[i] =
++ dal_fixed31_32_add(
++ filter->coefficients_sum[i],
++ filter->coefficients[m]);
++
++ m += params->phases;
++
++ ++j;
++ }
++
++ ++i;
++ }
++
++ i = 0;
++
++ while (i != params->phases) {
++ m = i;
++
++ j = 0;
++
++ while (j != params->taps) {
++ filter->coefficients[m] =
++ dal_fixed31_32_div(
++ filter->coefficients[m],
++ filter->coefficients_sum[i]);
++
++ m += params->phases;
++
++ ++j;
++ }
++
++ ++i;
++ }
++
++ i = 0;
++ i_limit = (params->phases >> 1) + 1;
++
++ while (i != i_limit) {
++ m = i;
++
++ j = 0;
++
++ while (j != params->taps) {
++ struct fixed31_32 tmp = filter->coefficients[m];
++
++ filter->filter[i * params->taps + j] = tmp;
++
++ if (dal_fixed31_32_lt(
++ tmp, dal_fixed31_32_zero) &&
++ dal_fixed31_32_lt(tmp, a_min))
++ a_min = tmp;
++ else if (dal_fixed31_32_lt(
++ dal_fixed31_32_zero, tmp) &&
++ dal_fixed31_32_lt(a_max, tmp))
++ a_max = tmp;
++
++ m += params->phases;
++
++ ++j;
++ }
++
++ ++i;
++ }
++
++ if (dal_fixed31_32_eq(a_min, dal_fixed31_32_zero))
++ *ringing = dal_fixed31_32_from_int(100);
++ else
++ *ringing = dal_fixed31_32_min(
++ dal_fixed31_32_abs(
++ dal_fixed31_32_div(a_max, a_min)),
++ dal_fixed31_32_from_int(100));
++
++ return true;
++}
++
++static bool construct_scaler_filter(
++ struct dc_context *ctx,
++ struct scaler_filter *filter)
++{
++ filter->src_size = 0;
++ filter->dst_size = 0;
++ filter->filter = NULL;
++ filter->integer_filter = NULL;
++ filter->filter_size_allocated = 0;
++ filter->filter_size_effective = 0;
++ filter->coefficients = NULL;
++ filter->coefficients_quantity = 0;
++ filter->coefficients_sum = NULL;
++ filter->coefficients_sum_quantity = 0;
++ filter->downscaling_table = NULL;
++ filter->upscaling_table = NULL;
++ filter->ctx = ctx;
++
++ if (!create_downscaling_table(filter)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!create_upscaling_table(filter)) {
++ BREAK_TO_DEBUGGER();
++ destroy_downscaling_table(filter);
++ return false;
++ }
++
++ return true;
++}
++
++static void destruct_scaler_filter(
++ struct scaler_filter *filter)
++{
++ if (filter->coefficients_sum)
++ dc_service_free(filter->ctx, filter->coefficients_sum);
++
++ if (filter->coefficients)
++ dc_service_free(filter->ctx, filter->coefficients);
++
++ if (filter->integer_filter)
++ dc_service_free(filter->ctx, filter->integer_filter);
++
++ if (filter->filter)
++ dc_service_free(filter->ctx, filter->filter);
++
++ destroy_upscaling_table(filter);
++
++ destroy_downscaling_table(filter);
++}
++
++struct scaler_filter *dal_scaler_filter_create(struct dc_context *ctx)
++{
++ struct scaler_filter *filter =
++ dc_service_alloc(ctx, sizeof(struct scaler_filter));
++
++ if (!filter) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ if (construct_scaler_filter(ctx, filter))
++ return filter;
++
++ BREAK_TO_DEBUGGER();
++
++ dc_service_free(ctx, filter);
++
++ return NULL;
++}
++
++bool dal_scaler_filter_generate(
++ struct scaler_filter *filter,
++ const struct scaler_filter_params *params,
++ uint32_t src_size,
++ uint32_t dst_size)
++{
++ uint32_t filter_size_required;
++
++ struct fixed31_32 attenuation;
++ struct fixed31_32 decibels_at_nyquist;
++ struct fixed31_32 ringing;
++
++ if (!params) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if ((params->taps < 3) || (params->taps > 16)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!src_size || !dst_size) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (same_filter_required(filter, params, src_size, dst_size))
++ return true;
++
++ filter_size_required =
++ params->taps * ((params->phases >> 1) + 1);
++
++ if (filter_size_required > filter->filter_size_allocated) {
++ if (filter->filter) {
++ dc_service_free(filter->ctx, filter->filter);
++
++ filter->filter = 0;
++ filter->filter_size_allocated = 0;
++ }
++
++ filter->filter = dc_service_alloc(
++ filter->ctx,
++ filter_size_required * sizeof(struct fixed31_32));
++
++ if (!filter->filter) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (filter->integer_filter) {
++ dc_service_free(filter->ctx, filter->integer_filter);
++
++ filter->integer_filter = 0;
++ }
++
++ filter->integer_filter = dc_service_alloc(
++ filter->ctx,
++ filter_size_required * sizeof(uint32_t));
++
++ if (!filter->integer_filter) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ filter->filter_size_allocated = filter_size_required;
++ }
++
++ filter->filter_size_effective = filter_size_required;
++
++ if (!map_sharpness(filter, params, src_size, dst_size,
++ &attenuation, &decibels_at_nyquist)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!generate_filter(filter, params, attenuation, &ringing)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ filter->params = *params;
++ filter->src_size = src_size;
++ filter->dst_size = dst_size;
++
++ return true;
++}
++
++const struct fixed31_32 *dal_scaler_filter_get(
++ const struct scaler_filter *filter,
++ uint32_t **data,
++ uint32_t *number)
++{
++ if (!number) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ if (!data) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ *number = filter->filter_size_effective;
++ *data = filter->integer_filter;
++
++ return filter->filter;
++}
++
++void dal_scaler_filter_destroy(
++ struct scaler_filter **filter)
++{
++ if (!filter || !*filter) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ destruct_scaler_filter(*filter);
++
++ dc_service_free((*filter)->ctx, *filter);
++
++ *filter = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.h b/drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.h
+new file mode 100644
+index 0000000..668691d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/calcs/scaler_filter.h
+@@ -0,0 +1,74 @@
++/* 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_SCALER_FILTER_H__
++#define __DAL_SCALER_FILTER_H__
++
++struct scaler_filter_params {
++ uint32_t taps; /* 3...16 */
++ uint32_t phases;
++ int32_t sharpness; /* -50...50 */
++ union {
++ struct {
++ uint32_t HORIZONTAL:1;
++ uint32_t RESERVED:31;
++ } bits;
++ uint32_t value;
++ } flags;
++};
++
++struct q31_32;
++
++struct scaler_filter {
++ struct scaler_filter_params params;
++ uint32_t src_size;
++ uint32_t dst_size;
++ struct fixed31_32 *filter;
++ uint32_t *integer_filter;
++ uint32_t filter_size_allocated;
++ uint32_t filter_size_effective;
++ struct fixed31_32 *coefficients;
++ uint32_t coefficients_quantity;
++ struct fixed31_32 *coefficients_sum;
++ uint32_t coefficients_sum_quantity;
++ struct fixed31_32 ***downscaling_table;
++ struct fixed31_32 ***upscaling_table;
++ struct dc_context *ctx;
++};
++
++struct scaler_filter *dal_scaler_filter_create(struct dc_context *ctx);
++void dal_scaler_filter_destroy(struct scaler_filter **ptr);
++
++bool dal_scaler_filter_generate(
++ struct scaler_filter *filter,
++ const struct scaler_filter_params *params,
++ uint32_t src_size,
++ uint32_t dst_size);
++
++const struct fixed31_32 *dal_scaler_filter_get(
++ const struct scaler_filter *filter,
++ uint32_t **data,
++ uint32_t *number);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/connector/Makefile b/drivers/gpu/drm/amd/dal/dc/connector/Makefile
+new file mode 100644
+index 0000000..ebd4115
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/connector/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the 'connector' sub-component of DAL.
++# It provides the control and status of HW connectors blocks.
++
++
++CONNECTOR = connector_base.o connector_signals.o
++
++AMD_DAL_CONNECTOR = $(addprefix $(AMDDALPATH)/dc/connector/,$(CONNECTOR))
++
++AMD_DAL_FILES += $(AMD_DAL_CONNECTOR)
+diff --git a/drivers/gpu/drm/amd/dal/dc/connector/connector.h b/drivers/gpu/drm/amd/dal/dc/connector/connector.h
+new file mode 100644
+index 0000000..7d6057b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/connector/connector.h
+@@ -0,0 +1,39 @@
++/*
++ * 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_CONNECTOR_H__
++#define __DAL_CONNECTOR_H__
++
++#include "include/connector_interface.h"
++
++extern const uint32_t number_of_default_signals;
++extern const uint32_t number_of_signals;
++
++/* Indexed by enum connector_id */
++extern const struct connector_signals default_signals[];
++/* Indexed by enum connector_id */
++extern const struct connector_signals supported_signals[];
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/connector/connector_base.c b/drivers/gpu/drm/amd/dal/dc/connector/connector_base.c
+new file mode 100644
+index 0000000..34005fd
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/connector/connector_base.c
+@@ -0,0 +1,421 @@
++/*
++ * 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 "dal_services.h"
++
++#include "connector.h"
++#include "include/irq_interface.h"
++#include "include/ddc_interface.h"
++#include "include/connector_interface.h"
++
++struct connector {
++ struct graphics_object_id id;
++ uint32_t input_signals;
++ uint32_t output_signals;
++ struct adapter_service *as;
++ struct connector_feature_support features;
++ struct connector_signals default_signals;
++ struct dc_context *ctx;
++};
++
++static bool connector_construct(
++ struct connector *connector,
++ struct dc_context *ctx,
++ struct adapter_service *as,
++ struct graphics_object_id go_id)
++{
++ bool hw_ddc_polling = false;
++ struct ddc *ddc;
++ struct irq *hpd;
++ enum connector_id connector_id;
++ uint32_t signals_vector = 0;
++ uint32_t signals_num = 0;
++ uint32_t i;
++
++ if (!as) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ connector->as = as;
++ connector->id = go_id;
++ connector->features.ddc_line = CHANNEL_ID_UNKNOWN;
++ connector->features.hpd_line = HPD_SOURCEID_UNKNOWN;
++ connector->ctx = ctx;
++
++ ddc = dal_adapter_service_obtain_ddc(as, connector->id);
++ hpd = dal_adapter_service_obtain_hpd_irq(as, connector->id);
++
++ connector_id = dal_graphics_object_id_get_connector_id(go_id);
++
++ /* Initialize DDC line */
++ if (ddc) {
++ switch (dal_ddc_get_line(ddc)) {
++ case GPIO_DDC_LINE_DDC1:
++ connector->features.ddc_line = CHANNEL_ID_DDC1;
++ break;
++ case GPIO_DDC_LINE_DDC2:
++ connector->features.ddc_line = CHANNEL_ID_DDC2;
++ break;
++ case GPIO_DDC_LINE_DDC3:
++ connector->features.ddc_line = CHANNEL_ID_DDC3;
++ break;
++ case GPIO_DDC_LINE_DDC4:
++ connector->features.ddc_line = CHANNEL_ID_DDC4;
++ break;
++ case GPIO_DDC_LINE_DDC5:
++ connector->features.ddc_line = CHANNEL_ID_DDC5;
++ break;
++ case GPIO_DDC_LINE_DDC6:
++ connector->features.ddc_line = CHANNEL_ID_DDC6;
++ break;
++ case GPIO_DDC_LINE_DDC_VGA:
++ connector->features.ddc_line = CHANNEL_ID_DDC_VGA;
++ break;
++ case GPIO_DDC_LINE_I2C_PAD:
++ connector->features.ddc_line = CHANNEL_ID_I2C_PAD;
++ break;
++ default:
++ BREAK_TO_DEBUGGER();
++ break;
++ }
++
++ /* Initialize HW DDC polling support
++ * On DCE6.0 only DDC lines support HW polling (I2cPad does not)
++ */
++
++ if (dal_adapter_service_is_feature_supported(
++ FEATURE_ENABLE_HW_EDID_POLLING)) {
++ switch (dal_ddc_get_line(ddc)) {
++ case GPIO_DDC_LINE_DDC1:
++ case GPIO_DDC_LINE_DDC2:
++ case GPIO_DDC_LINE_DDC3:
++ case GPIO_DDC_LINE_DDC4:
++ case GPIO_DDC_LINE_DDC5:
++ case GPIO_DDC_LINE_DDC6:
++ case GPIO_DDC_LINE_DDC_VGA:
++ hw_ddc_polling = true;
++ break;
++ default:
++ break;
++ }
++ }
++
++ dal_adapter_service_release_ddc(as, ddc);
++ }
++
++ /* Initialize HPD line */
++ if (hpd) {
++ switch (dal_irq_get_source(hpd)) {
++ case DC_IRQ_SOURCE_HPD1:
++ connector->features.hpd_line = HPD_SOURCEID1;
++ break;
++ case DC_IRQ_SOURCE_HPD2:
++ connector->features.hpd_line = HPD_SOURCEID2;
++ break;
++ case DC_IRQ_SOURCE_HPD3:
++ connector->features.hpd_line = HPD_SOURCEID3;
++ break;
++ case DC_IRQ_SOURCE_HPD4:
++ connector->features.hpd_line = HPD_SOURCEID4;
++ break;
++ case DC_IRQ_SOURCE_HPD5:
++ connector->features.hpd_line = HPD_SOURCEID5;
++ break;
++ case DC_IRQ_SOURCE_HPD6:
++ connector->features.hpd_line = HPD_SOURCEID6;
++ break;
++ default:
++ BREAK_TO_DEBUGGER();
++ break;
++ }
++
++ dal_adapter_service_release_irq(as, hpd);
++ }
++
++ if ((uint32_t)connector_id >= number_of_default_signals &&
++ (uint32_t)connector_id >= number_of_signals)
++ return false;
++
++ /* Initialize default signals */
++ connector->default_signals = default_signals[connector_id];
++
++ /* Fill supported signals */
++ signals_num = supported_signals[connector_id].number_of_signals;
++ for (i = 0; i < signals_num; i++)
++ signals_vector |= supported_signals[connector_id].signal[i];
++
++ /* Connector supports same set for input and output signals */
++ connector->input_signals = signals_vector;
++ connector->output_signals = signals_vector;
++
++ switch (connector_id) {
++ case CONNECTOR_ID_VGA:
++ if (hw_ddc_polling
++ && connector->features.ddc_line != CHANNEL_ID_UNKNOWN)
++ connector->features.HW_DDC_POLLING = true;
++ break;
++ case CONNECTOR_ID_SINGLE_LINK_DVII:
++ case CONNECTOR_ID_DUAL_LINK_DVII:
++ if (connector->features.hpd_line != HPD_SOURCEID_UNKNOWN)
++ connector->features.HPD_FILTERING = true;
++ if (hw_ddc_polling
++ && connector->features.ddc_line != CHANNEL_ID_UNKNOWN)
++ connector->features.HW_DDC_POLLING = true;
++ break;
++ case CONNECTOR_ID_SINGLE_LINK_DVID:
++ case CONNECTOR_ID_DUAL_LINK_DVID:
++ case CONNECTOR_ID_HDMI_TYPE_A:
++ case CONNECTOR_ID_LVDS:
++ case CONNECTOR_ID_DISPLAY_PORT:
++ case CONNECTOR_ID_EDP:
++ if (connector->features.hpd_line != HPD_SOURCEID_UNKNOWN)
++ connector->features.HPD_FILTERING = true;
++ break;
++ default:
++ connector->features.HPD_FILTERING = false;
++ connector->features.HW_DDC_POLLING = false;
++ break;
++ }
++
++ return true;
++}
++
++struct connector *dal_connector_create(
++ struct dc_context *ctx,
++ struct adapter_service *as,
++ struct graphics_object_id go_id)
++{
++ struct connector *connector = NULL;
++
++ connector = dc_service_alloc(ctx, sizeof(struct connector));
++
++ if (!connector) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ if (connector_construct(connector, ctx, as, go_id))
++ return connector;
++
++ BREAK_TO_DEBUGGER();
++
++ dc_service_free(ctx, connector);
++
++ return NULL;
++}
++
++void dal_connector_destroy(struct connector **connector)
++{
++ if (!connector || !*connector) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ dc_service_free((*connector)->ctx, *connector);
++
++ *connector = NULL;
++}
++
++uint32_t dal_connector_enumerate_output_signals(
++ const struct connector *connector)
++{
++ return connector->output_signals;
++}
++
++uint32_t dal_connector_enumerate_input_signals(
++ const struct connector *connector)
++{
++ return connector->input_signals;
++}
++
++struct connector_signals dal_connector_get_default_signals(
++ const struct connector *connector)
++{
++ return connector->default_signals;
++}
++
++const struct graphics_object_id dal_connector_get_graphics_object_id(
++ const struct connector *connector)
++{
++ return connector->id;
++}
++
++/*
++ * Function: program_hpd_filter
++ *
++ * @brief
++ * Programs HPD filter on associated HPD line
++ *
++ * @param [in] delay_on_connect_in_ms: Connect filter timeout
++ * @param [in] delay_on_disconnect_in_ms: Disconnect filter timeout
++ *
++ * @return
++ * true on success, false otherwise
++ */
++bool dal_connector_program_hpd_filter(
++ const struct connector *connector,
++ const uint32_t delay_on_connect_in_ms,
++ const uint32_t delay_on_disconnect_in_ms)
++{
++ bool result = false;
++
++ struct irq *hpd;
++
++ /* Verify feature is supported */
++
++ if (!connector->features.HPD_FILTERING)
++ return result;
++
++ /* Obtain HPD handle */
++
++ hpd = dal_adapter_service_obtain_hpd_irq(
++ connector->as, connector->id);
++
++ if (!hpd)
++ return result;
++
++ /* Setup HPD filtering */
++
++ if (GPIO_RESULT_OK == dal_irq_open(hpd)) {
++ struct gpio_hpd_config config;
++
++ config.delay_on_connect = delay_on_connect_in_ms;
++ config.delay_on_disconnect = delay_on_disconnect_in_ms;
++
++ dal_irq_setup_hpd_filter(hpd, &config);
++
++ dal_irq_close(hpd);
++
++ result = true;
++ } else {
++ ASSERT_CRITICAL(false);
++ }
++
++ /* Release HPD handle */
++
++ dal_adapter_service_release_irq(connector->as, hpd);
++
++ return result;
++}
++
++/*
++ * Function: setup_ddc_polling
++ *
++ * @brief
++ * Enables/Disables HW polling on associated DDC line
++ *
++ * @param [in] ddc_config: Specifies polling mode
++ *
++ * @return
++ * true on success, false otherwise
++ */
++static bool setup_ddc_polling(
++ const struct connector *connector,
++ enum gpio_ddc_config_type ddc_config)
++{
++ bool result = false;
++
++ struct ddc *ddc;
++
++ /* Verify feature is supported */
++
++ if (!connector->features.HW_DDC_POLLING)
++ return result;
++
++ /* Obtain DDC handle */
++
++ ddc = dal_adapter_service_obtain_ddc(
++ connector->as, connector->id);
++
++ if (!ddc) {
++ BREAK_TO_DEBUGGER();
++ return result;
++ }
++
++ /* Setup DDC polling */
++
++ if (GPIO_RESULT_OK == dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
++ GPIO_DDC_CONFIG_TYPE_MODE_I2C)) {
++ dal_ddc_set_config(ddc, ddc_config);
++
++ dal_ddc_close(ddc);
++
++ result = true;
++ } else {
++ BREAK_TO_DEBUGGER();
++ }
++
++ /* Release DDC handle */
++
++ dal_adapter_service_release_ddc(connector->as, ddc);
++
++ return result;
++}
++
++/*
++ * Function: enable_ddc_polling
++ *
++ * @brief
++ * Enables HW polling on associated DDC line
++ *
++ * @param [in] is_poll_for_connect: Specifies polling mode
++ *
++ * @return
++ * true on success, false otherwise
++ */
++bool dal_connector_enable_ddc_polling(
++ const struct connector *connector,
++ const bool is_poll_for_connect)
++{
++ enum gpio_ddc_config_type ddc_config = is_poll_for_connect ?
++ GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT :
++ GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT;
++
++ return setup_ddc_polling(connector, ddc_config);
++}
++
++/*
++ * Function: disable_ddc_polling
++ *
++ * @brief
++ * Disables HW polling on associated DDC line
++ *
++ * @return
++ * true on success, false otherwise
++ */
++bool dal_connector_disable_ddc_polling(const struct connector *connector)
++{
++ return setup_ddc_polling(connector,
++ GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING);
++}
++
++void dal_connector_get_features(
++ const struct connector *con,
++ struct connector_feature_support *cfs)
++{
++ dc_service_memmove(cfs, &con->features,
++ sizeof(struct connector_feature_support));
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/connector/connector_signals.c b/drivers/gpu/drm/amd/dal/dc/connector/connector_signals.c
+new file mode 100644
+index 0000000..d1a289d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/connector/connector_signals.c
+@@ -0,0 +1,204 @@
++/*
++ * 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 "dal_services.h"
++
++#include "connector.h"
++
++static const enum signal_type signals_none[] = {
++ SIGNAL_TYPE_NONE
++};
++
++static const enum signal_type signals_single_link_dvii[] = {
++ SIGNAL_TYPE_DVI_SINGLE_LINK,
++ SIGNAL_TYPE_RGB
++};
++
++static const enum signal_type signals_dual_link_dvii[] = {
++ SIGNAL_TYPE_DVI_DUAL_LINK,
++ SIGNAL_TYPE_DVI_SINGLE_LINK,
++ SIGNAL_TYPE_RGB
++};
++
++static const enum signal_type signals_single_link_dvid[] = {
++ SIGNAL_TYPE_DVI_SINGLE_LINK
++};
++
++static const enum signal_type signals_dual_link_dvid[] = {
++ SIGNAL_TYPE_DVI_DUAL_LINK,
++ SIGNAL_TYPE_DVI_SINGLE_LINK,
++};
++
++static const enum signal_type signals_vga[] = {
++ SIGNAL_TYPE_RGB
++};
++
++static const enum signal_type signals_hdmi_type_a[] = {
++ SIGNAL_TYPE_DVI_SINGLE_LINK,
++ SIGNAL_TYPE_HDMI_TYPE_A
++};
++
++static const enum signal_type signals_lvds[] = {
++ SIGNAL_TYPE_LVDS
++};
++
++static const enum signal_type signals_pcie[] = {
++ SIGNAL_TYPE_DVI_SINGLE_LINK,
++ SIGNAL_TYPE_HDMI_TYPE_A,
++ SIGNAL_TYPE_DISPLAY_PORT
++};
++
++static const enum signal_type signals_hardcode_dvi[] = {
++ SIGNAL_TYPE_NONE
++};
++
++static const enum signal_type signals_displayport[] = {
++ SIGNAL_TYPE_DVI_SINGLE_LINK,
++ SIGNAL_TYPE_HDMI_TYPE_A,
++ SIGNAL_TYPE_DISPLAY_PORT,
++ SIGNAL_TYPE_DISPLAY_PORT_MST
++};
++
++static const enum signal_type signals_edp[] = {
++ SIGNAL_TYPE_EDP
++};
++
++static const enum signal_type signals_wireless[] = {
++ SIGNAL_TYPE_WIRELESS
++};
++
++static const enum signal_type signals_miracast[] = {
++ SIGNAL_TYPE_WIRELESS
++};
++
++static const enum signal_type default_signals_none[] = {
++ SIGNAL_TYPE_NONE
++};
++
++static const enum signal_type default_signals_single_link_dvii[] = {
++ SIGNAL_TYPE_DVI_SINGLE_LINK,
++ SIGNAL_TYPE_RGB
++};
++
++static const enum signal_type default_signals_dual_link_dvii[] = {
++ SIGNAL_TYPE_DVI_DUAL_LINK,
++ SIGNAL_TYPE_RGB
++};
++
++static const enum signal_type default_signals_single_link_dvid[] = {
++ SIGNAL_TYPE_DVI_SINGLE_LINK
++};
++
++static const enum signal_type default_signals_dual_link_dvid[] = {
++ SIGNAL_TYPE_DVI_DUAL_LINK,
++};
++
++static const enum signal_type default_signals_vga[] = {
++ SIGNAL_TYPE_RGB
++};
++
++static const enum signal_type default_signals_hdmi_type_a[] = {
++ SIGNAL_TYPE_HDMI_TYPE_A
++};
++
++static const enum signal_type default_signals_lvds[] = {
++ SIGNAL_TYPE_LVDS
++};
++
++static const enum signal_type default_signals_pcie[] = {
++ SIGNAL_TYPE_DISPLAY_PORT
++};
++
++static const enum signal_type default_signals_hardcode_dvi[] = {
++ SIGNAL_TYPE_NONE
++};
++
++static const enum signal_type default_signals_displayport[] = {
++ SIGNAL_TYPE_DISPLAY_PORT
++};
++
++static const enum signal_type default_signals_edp[] = {
++ SIGNAL_TYPE_EDP
++};
++
++static const enum signal_type default_signals_wireless[] = {
++ SIGNAL_TYPE_WIRELESS
++};
++
++static const enum signal_type default_signals_miracast[] = {
++ SIGNAL_TYPE_WIRELESS
++};
++
++/*
++ * Signal arrays
++ */
++
++#define SIGNALS_ARRAY_ELEM(a) {a, ARRAY_SIZE(a)}
++
++/* Indexed by enum connector_id */
++const struct connector_signals default_signals[] = {
++ SIGNALS_ARRAY_ELEM(default_signals_none),
++ SIGNALS_ARRAY_ELEM(default_signals_single_link_dvii),
++ SIGNALS_ARRAY_ELEM(default_signals_dual_link_dvii),
++ SIGNALS_ARRAY_ELEM(default_signals_single_link_dvid),
++ SIGNALS_ARRAY_ELEM(default_signals_dual_link_dvid),
++ SIGNALS_ARRAY_ELEM(default_signals_vga),
++ SIGNALS_ARRAY_ELEM(default_signals_hdmi_type_a),
++ SIGNALS_ARRAY_ELEM(default_signals_none),
++ SIGNALS_ARRAY_ELEM(default_signals_lvds),
++ SIGNALS_ARRAY_ELEM(default_signals_pcie),
++ SIGNALS_ARRAY_ELEM(default_signals_hardcode_dvi),
++ SIGNALS_ARRAY_ELEM(default_signals_displayport),
++ SIGNALS_ARRAY_ELEM(default_signals_edp),
++ /* MXM dummy connector */
++ SIGNALS_ARRAY_ELEM(default_signals_none),
++ SIGNALS_ARRAY_ELEM(default_signals_wireless),
++ SIGNALS_ARRAY_ELEM(default_signals_miracast)
++};
++
++const uint32_t number_of_default_signals = ARRAY_SIZE(default_signals);
++
++/* Indexed by enum connector_id */
++const struct connector_signals supported_signals[] = {
++ SIGNALS_ARRAY_ELEM(signals_none),
++ SIGNALS_ARRAY_ELEM(signals_single_link_dvii),
++ SIGNALS_ARRAY_ELEM(signals_dual_link_dvii),
++ SIGNALS_ARRAY_ELEM(signals_single_link_dvid),
++ SIGNALS_ARRAY_ELEM(signals_dual_link_dvid),
++ SIGNALS_ARRAY_ELEM(signals_vga),
++ SIGNALS_ARRAY_ELEM(signals_hdmi_type_a),
++ SIGNALS_ARRAY_ELEM(signals_none),
++ SIGNALS_ARRAY_ELEM(signals_lvds),
++ SIGNALS_ARRAY_ELEM(signals_pcie),
++ SIGNALS_ARRAY_ELEM(signals_hardcode_dvi),
++ SIGNALS_ARRAY_ELEM(signals_displayport),
++ SIGNALS_ARRAY_ELEM(signals_edp),
++ /* MXM dummy connector */
++ SIGNALS_ARRAY_ELEM(signals_none),
++ SIGNALS_ARRAY_ELEM(signals_wireless),
++ SIGNALS_ARRAY_ELEM(signals_miracast)
++};
++
++const uint32_t number_of_signals = ARRAY_SIZE(supported_signals);
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc.c b/drivers/gpu/drm/amd/dal/dc/core/dc.c
+new file mode 100644
+index 0000000..e13ce4e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc.c
+@@ -0,0 +1,849 @@
++/*
++ * Copyright 2015 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ */
++
++#include "dc_services.h"
++
++#include "dc.h"
++
++#include "core_status.h"
++#include "core_types.h"
++#include "hw_sequencer.h"
++
++#include "resource.h"
++
++#include "adapter_service_interface.h"
++#include "clock_source_interface.h"
++
++#include "include/irq_service_interface.h"
++#include "bandwidth_calcs.h"
++#include "include/irq_service_interface.h"
++
++#include "link_hwss.h"
++
++/*******************************************************************************
++ * Private structures
++ ******************************************************************************/
++
++struct dc_target_sync_report {
++ uint32_t h_count;
++ uint32_t v_count;
++};
++
++struct dc_sync_report {
++ uint32_t targets_num;
++ struct dc_target_sync_report trg_reports[MAX_TARGET_NUM];
++};
++
++/*******************************************************************************
++ * Private functions
++ ******************************************************************************/
++static void destroy_links(struct dc *dc)
++{
++ uint32_t i;
++
++ for (i = 0; i < dc->link_count; i++) {
++
++ if (NULL != dc->links[i])
++ link_destroy(&dc->links[i]);
++ }
++}
++
++
++static bool create_links(struct dc *dc, const struct dc_init_data *init_params)
++{
++ int i;
++ int connectors_num;
++
++ dc->link_count = 0;
++
++ connectors_num = dal_bios_parser_get_connectors_number(
++ dal_adapter_service_get_bios_parser(
++ init_params->adapter_srv));
++
++ if (0 == connectors_num || connectors_num > ENUM_ID_COUNT) {
++ dal_error("DC: Invalid number of connectors!\n");
++ return false;
++ }
++
++ dal_output_to_console("%s: connectors_num:%d\n", __func__,
++ connectors_num);
++
++ dc->links = dc_service_alloc(
++ init_params->ctx, connectors_num * sizeof(struct core_link *));
++
++ if (NULL == dc->links) {
++ dal_error("DC: failed to allocate 'links' storage!\n");
++ goto allocate_dc_links_storage_fail;
++ }
++
++ for (i = 0; i < connectors_num; i++) {
++ struct link_init_data link_init_params = {0};
++ struct core_link *link;
++
++ link_init_params.ctx = init_params->ctx;
++ link_init_params.adapter_srv = init_params->adapter_srv;
++ link_init_params.connector_index = i;
++ link_init_params.link_index = dc->link_count;
++ link_init_params.dc = dc;
++ link = link_create(&link_init_params);
++
++ if (link) {
++ dc->links[dc->link_count] = link;
++ link->dc = dc;
++ ++dc->link_count;
++ }
++ else {
++ dal_error("DC: failed to create link!\n");
++ }
++ }
++
++ if (!dc->link_count) {
++ dal_error("DC: no 'links' were created!\n");
++ goto allocate_dc_links_storage_fail;
++ }
++
++ return true;
++
++allocate_dc_links_storage_fail:
++ return false;
++}
++
++static void init_hw(struct dc *dc)
++{
++ int i;
++ struct bios_parser *bp;
++ struct transform *xfm;
++
++ bp = dal_adapter_service_get_bios_parser(dc->res_pool.adapter_srv);
++ for(i = 0; i < dc->res_pool.controller_count; i++) {
++ xfm = dc->res_pool.transforms[i];
++
++ dc->hwss.enable_display_power_gating(
++ dc->ctx, i, bp,
++ PIPE_GATING_CONTROL_INIT);
++ dc->hwss.enable_display_power_gating(
++ dc->ctx, i, bp,
++ PIPE_GATING_CONTROL_DISABLE);
++
++ dc->hwss.transform_power_up(xfm);
++ dc->hwss.enable_display_pipe_clock_gating(
++ dc->ctx,
++ true);
++ }
++
++ dc->hwss.clock_gating_power_up(dc->ctx, false);
++ dal_bios_parser_power_up(bp);
++ /***************************************/
++
++ for (i = 0; i < dc->link_count; i++) {
++ /****************************************/
++ /* Power up AND update implementation according to the
++ * required signal (which may be different from the
++ * default signal on connector). */
++ struct core_link *link = dc->links[i];
++ if (dc->hwss.encoder_power_up(link->link_enc) != ENCODER_RESULT_OK) {
++ dal_error("Failed link encoder power up!\n");
++ return;
++ }
++ }
++
++ dal_bios_parser_set_scratch_acc_mode_change(bp);
++
++ for(i = 0; i < dc->res_pool.controller_count; i++) {
++ struct timing_generator *tg = dc->res_pool.timing_generators[i];
++
++ dc->hwss.disable_vga(tg);
++
++ /* Blank controller using driver code instead of
++ * command table. */
++ dc->hwss.disable_memory_requests(tg);
++ }
++
++ for(i = 0; i < dc->res_pool.audio_count; i++) {
++ struct audio *audio = dc->res_pool.audios[i];
++
++ if (dal_audio_power_up(audio) != AUDIO_RESULT_OK)
++ dal_error("Failed audio power up!\n");
++ }
++
++}
++
++static struct adapter_service *create_as(
++ struct dc_init_data *dc_init_data,
++ const struct dal_init_data *init)
++{
++ struct adapter_service *as = NULL;
++ struct as_init_data init_data;
++
++ dc_service_memset(&init_data, 0, sizeof(init_data));
++
++ init_data.ctx = dc_init_data->ctx;
++
++ /* BIOS parser init data */
++ init_data.bp_init_data.ctx = dc_init_data->ctx;
++ init_data.bp_init_data.bios = init->asic_id.atombios_base_address;
++
++ /* HW init data */
++ init_data.hw_init_data.chip_id = init->asic_id.chip_id;
++ init_data.hw_init_data.chip_family = init->asic_id.chip_family;
++ init_data.hw_init_data.pci_revision_id = init->asic_id.pci_revision_id;
++ init_data.hw_init_data.fake_paths_num = init->asic_id.fake_paths_num;
++ init_data.hw_init_data.feature_flags = init->asic_id.feature_flags;
++ init_data.hw_init_data.hw_internal_rev = init->asic_id.hw_internal_rev;
++ init_data.hw_init_data.runtime_flags = init->asic_id.runtime_flags;
++ init_data.hw_init_data.vram_width = init->asic_id.vram_width;
++ init_data.hw_init_data.vram_type = init->asic_id.vram_type;
++
++ /* bdf is BUS,DEVICE,FUNCTION*/
++ init_data.bdf_info = init->bdf_info;
++
++ init_data.display_param = &init->display_param;
++
++ as = dal_adapter_service_create(&init_data);
++
++ return as;
++}
++
++static void bw_calcs_data_update_from_pplib(struct dc *dc)
++{
++ struct dal_system_clock_range clk_range = { 0 };
++
++ dc_service_get_system_clocks_range(dc->ctx, &clk_range);
++
++ /* on CZ Gardenia from PPLib we get:
++ * clk_range.max_mclk:80000
++ * clk_range.min_mclk:80000
++ * clk_range.max_sclk:80000
++ * clk_range.min_sclk:30000 */
++
++ /* The values for calcs are stored in units of MHz, so for example
++ * 80000 will be stored as 800. */
++ dc->bw_vbios.high_sclk = frc_to_fixed(clk_range.max_sclk, 100);
++ dc->bw_vbios.low_sclk = frc_to_fixed(clk_range.min_sclk, 100);
++
++ dc->bw_vbios.high_yclk = frc_to_fixed(clk_range.max_mclk, 100);
++ dc->bw_vbios.low_yclk = frc_to_fixed(clk_range.min_mclk, 100);
++}
++
++static bool construct(struct dc *dc, const struct dal_init_data *init_params)
++{
++ struct dal_logger *logger;
++ /* Tempory code
++ * TODO: replace dal_init_data with dc_init_data when dal is removed
++ */
++ struct dc_init_data dc_init_data = {0};
++
++ /* Create dc context */
++ /* A temp dc context is used only to allocate the memory for actual
++ * dc context */
++ struct dc_context ctx = {0};
++ ctx.cgs_device = init_params->cgs_device;
++ ctx.dc = dc;
++
++ dc_init_data.ctx = dc_service_alloc(&ctx, sizeof(*dc_init_data.ctx));
++ if (!dc_init_data.ctx) {
++ dal_error("%s: failed to create ctx\n", __func__);
++ goto ctx_fail;
++ }
++ dc_init_data.ctx->driver_context = init_params->driver;
++ dc_init_data.ctx->cgs_device = init_params->cgs_device;
++ dc_init_data.ctx->dc = dc;
++
++ /* Create logger */
++ logger = dal_logger_create(dc_init_data.ctx);
++
++ if (!logger) {
++ /* can *not* call logger. call base driver 'print error' */
++ dal_error("%s: failed to create Logger!\n", __func__);
++ goto logger_fail;
++ }
++ dc_init_data.ctx->logger = logger;
++
++ /* Create adapter service */
++ dc_init_data.adapter_srv = create_as(&dc_init_data, init_params);
++
++ if (!dc_init_data.adapter_srv) {
++ dal_error("%s: create_as() failed!\n", __func__);
++ goto as_fail;
++ }
++
++ /* Initialize HW controlled by Adapter Service */
++ if (false == dal_adapter_service_initialize_hw_data(
++ dc_init_data.adapter_srv)) {
++ dal_error("%s: dal_adapter_service_initialize_hw_data()"\
++ " failed!\n", __func__);
++ /* Note that AS exist, so have to destroy it.*/
++ goto as_fail;
++ }
++
++ dc->ctx = dc_init_data.ctx;
++
++ /* Create hardware sequencer */
++ if (!dc_construct_hw_sequencer(dc_init_data.adapter_srv, dc))
++ goto hwss_fail;
++
++
++ /* TODO: create all the sub-objects of DC. */
++ if (false == create_links(dc, &dc_init_data))
++ goto create_links_fail;
++
++ if (!dc->hwss.construct_resource_pool(
++ dc_init_data.adapter_srv,
++ dc,
++ &dc->res_pool))
++ goto construct_resource_fail;
++
++
++ bw_calcs_init(&dc->bw_dceip, &dc->bw_vbios);
++
++ bw_calcs_data_update_from_pplib(dc);
++
++ return true;
++
++ /**** error handling here ****/
++construct_resource_fail:
++create_links_fail:
++as_fail:
++ dal_logger_destroy(&dc_init_data.ctx->logger);
++logger_fail:
++hwss_fail:
++ dc_service_free(&ctx, dc_init_data.ctx);
++ctx_fail:
++ return false;
++}
++
++static void destruct(struct dc *dc)
++{
++ destroy_links(dc);
++ dc_service_free(dc->ctx, dc->links);
++ dc->hwss.destruct_resource_pool(&dc->res_pool);
++ dal_logger_destroy(&dc->ctx->logger);
++ dc_service_free(dc->ctx, dc->ctx);
++}
++
++/*******************************************************************************
++ * Public functions
++ ******************************************************************************/
++
++struct dc *dc_create(const struct dal_init_data *init_params)
++ {
++ struct dc_context ctx = {
++ .driver_context = init_params->driver,
++ .cgs_device = init_params->cgs_device
++ };
++ struct dc *dc = dc_service_alloc(&ctx, sizeof(*dc));
++
++ if (NULL == dc)
++ goto alloc_fail;
++
++ ctx.dc = dc;
++ if (false == construct(dc, init_params))
++ goto construct_fail;
++
++ /*TODO: separate HW and SW initialization*/
++ init_hw(dc);
++
++ return dc;
++
++construct_fail:
++ dc_service_free(&ctx, dc);
++
++alloc_fail:
++ return NULL;
++}
++
++void dc_destroy(struct dc **dc)
++{
++ destruct(*dc);
++ dc_service_free((*dc)->ctx, *dc);
++ *dc = NULL;
++}
++
++bool dc_validate_resources(
++ const struct dc *dc,
++ const struct dc_validation_set set[],
++ uint8_t set_count)
++{
++ enum dc_status result = DC_ERROR_UNEXPECTED;
++ struct validate_context *context;
++
++ context = dc_service_alloc(dc->ctx, sizeof(struct validate_context));
++ if(context == NULL)
++ goto context_alloc_fail;
++
++ result = dc->hwss.validate_with_context(dc, set, set_count, context);
++
++ dc_service_free(dc->ctx, context);
++context_alloc_fail:
++
++ return (result == DC_OK);
++
++}
++
++static void program_timing_sync(
++ struct dc_context *dc_ctx,
++ struct validate_context *ctx)
++{
++ uint8_t i;
++ uint8_t j;
++ uint8_t group_size = 0;
++ uint8_t tg_count = ctx->res_ctx.pool.controller_count;
++ struct timing_generator *tg_set[3];
++
++ for (i = 0; i < tg_count; i++) {
++ if (!ctx->res_ctx.controller_ctx[i].stream)
++ continue;
++
++ tg_set[0] = ctx->res_ctx.pool.timing_generators[i];
++ group_size = 1;
++
++ /* Add tg to the set, search rest of the tg's for ones with
++ * same timing, add all tgs with same timing to the group
++ */
++ for (j = i + 1; j < tg_count; j++) {
++ if (!ctx->res_ctx.controller_ctx[j].stream)
++ continue;
++
++ if (is_same_timing(
++ &ctx->res_ctx.controller_ctx[j].stream->public
++ .timing,
++ &ctx->res_ctx.controller_ctx[i].stream->public
++ .timing)) {
++ tg_set[group_size] =
++ ctx->res_ctx.pool.timing_generators[j];
++ group_size++;
++ }
++ }
++
++ /* Right now we limit to one timing sync group so if one is
++ * found we break. A group has to be more than one tg.*/
++ if (group_size > 1)
++ break;
++ }
++
++ if(group_size > 1) {
++ dc_ctx->dc->hwss.enable_timing_synchronization(dc_ctx, group_size, tg_set);
++ }
++}
++
++static bool targets_changed(
++ struct dc *dc,
++ struct dc_target *targets[],
++ uint8_t target_count)
++{
++ uint8_t i;
++
++ if (target_count != dc->current_context.target_count)
++ return true;
++
++ for (i = 0; i < dc->current_context.target_count; i++) {
++ if (&dc->current_context.targets[i]->public != targets[i])
++ return true;
++ }
++
++ return false;
++}
++
++static void pplib_post_set_mode(
++ struct dc *dc,
++ const struct validate_context *context)
++{
++ struct dc_pp_display_configuration pp_display_cfg = { 0 };
++
++ pp_display_cfg.nb_pstate_switch_disable =
++ context->bw_results.nbp_state_change_enable == false;
++
++ pp_display_cfg.cpu_cc6_disable =
++ context->bw_results.cpuc_state_change_enable == false;
++
++ pp_display_cfg.cpu_pstate_disable =
++ context->bw_results.cpup_state_change_enable == false;
++
++ /* TODO: get cpu_pstate_separation_time from BW Calcs. */
++ pp_display_cfg.cpu_pstate_separation_time = 0;
++
++ dc_service_pp_post_dce_clock_change(dc->ctx, &pp_display_cfg);
++}
++
++bool dc_commit_targets(
++ struct dc *dc,
++ struct dc_target *targets[],
++ uint8_t target_count)
++{
++ enum dc_status result = DC_ERROR_UNEXPECTED;
++ struct validate_context *context;
++ struct dc_validation_set set[4];
++ uint8_t i;
++
++ if (false == targets_changed(dc, targets, target_count))
++ return DC_OK;
++
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_INTERFACE_TRACE,
++ LOG_MINOR_COMPONENT_DC,
++ "%s: %d targets",
++ __func__,
++ target_count);
++
++ for (i = 0; i < target_count; i++) {
++ struct dc_target *target = targets[i];
++
++ dc_target_log(target,
++ dc->ctx->logger,
++ LOG_MAJOR_INTERFACE_TRACE,
++ LOG_MINOR_COMPONENT_DC);
++
++ set[i].target = targets[i];
++ set[i].surface_count = 0;
++
++ }
++
++ context = dc_service_alloc(dc->ctx, sizeof(struct validate_context));
++ if (context == NULL)
++ goto context_alloc_fail;
++
++ result = dc->hwss.validate_with_context(dc, set, target_count, context);
++ if (result != DC_OK){
++ BREAK_TO_DEBUGGER();
++ goto fail;
++ }
++
++ if (!dal_adapter_service_is_in_accelerated_mode(
++ dc->res_pool.adapter_srv)) {
++ dc->hwss.enable_accelerated_mode(context);
++ }
++
++ for (i = 0; i < dc->current_context.target_count; i++) {
++ /*TODO: optimize this to happen only when necessary*/
++ dc_target_disable_memory_requests(
++ &dc->current_context.targets[i]->public);
++ }
++
++ if (result == DC_OK) {
++ dc->hwss.reset_hw_ctx(dc, context, target_count);
++
++ if (context->target_count > 0)
++ result = dc->hwss.apply_ctx_to_hw(dc, context);
++ }
++
++ for (i = 0; i < context->target_count; i++) {
++ struct dc_target *dc_target = &context->targets[i]->public;
++ if (context->targets[i]->status.surface_count > 0)
++ dc_target_enable_memory_requests(dc_target);
++ }
++
++ /* Release old targets */
++ for (i = 0; i < dc->current_context.target_count; i++) {
++ dc_target_release(
++ &dc->current_context.targets[i]->public);
++ dc->current_context.targets[i] = NULL;
++ }
++ /* Retain new targets*/
++ for (i = 0; i < context->target_count; i++) {
++ dc_target_retain(&context->targets[i]->public);
++ }
++
++ dc->current_context = *context;
++
++ program_timing_sync(dc->ctx, context);
++
++ pplib_post_set_mode(dc, context);
++
++ /* TODO: disable unused plls*/
++fail:
++ dc_service_free(dc->ctx, context);
++
++context_alloc_fail:
++ return (result == DC_OK);
++}
++
++uint8_t dc_get_current_target_count(const struct dc *dc)
++{
++ return dc->current_context.target_count;
++}
++
++struct dc_target *dc_get_target_at_index(const struct dc *dc, uint8_t i)
++{
++ if (i < dc->current_context.target_count)
++ return &dc->current_context.targets[i]->public;
++ return NULL;
++}
++
++const struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_index)
++{
++ return &dc->links[link_index]->public;
++}
++
++const struct graphics_object_id dc_get_link_id_at_index(
++ struct dc *dc, uint32_t link_index)
++{
++ return dc->links[link_index]->link_id;
++}
++
++const struct ddc_service *dc_get_ddc_at_index(
++ struct dc *dc, uint32_t link_index)
++{
++ return dc->links[link_index]->ddc;
++}
++
++const enum dc_irq_source dc_get_hpd_irq_source_at_index(
++ struct dc *dc, uint32_t link_index)
++{
++ return dc->links[link_index]->public.irq_source_hpd;
++}
++
++const struct audio **dc_get_audios(struct dc *dc)
++{
++ return (const struct audio **)dc->res_pool.audios;
++}
++
++void dc_get_caps(const struct dc *dc, struct dc_caps *caps)
++{
++ caps->max_targets = dal_min(dc->res_pool.controller_count, dc->link_count);
++ caps->max_links = dc->link_count;
++ caps->max_audios = dc->res_pool.audio_count;
++}
++
++void dc_flip_surface_addrs(struct dc* dc,
++ const struct dc_surface *const surfaces[],
++ struct dc_flip_addrs flip_addrs[],
++ uint32_t count)
++{
++ uint8_t i;
++ for (i = 0; i < count; i++) {
++ struct core_surface *surface = DC_SURFACE_TO_CORE(surfaces[i]);
++ /*
++ * TODO figure out a good way to keep track of address. Until
++ * then we'll have to awkwardly bypass the "const" surface.
++ */
++ surface->public.address = flip_addrs[i].address;
++ dc->hwss.update_plane_address(
++ surface,
++ DC_TARGET_TO_CORE(surface->status.dc_target));
++ }
++}
++
++enum dc_irq_source dc_interrupt_to_irq_source(
++ struct dc *dc,
++ uint32_t src_id,
++ uint32_t ext_id)
++{
++ return dal_irq_service_to_irq_source(dc->res_pool.irqs, src_id, ext_id);
++}
++
++
++void dc_interrupt_set(const struct dc *dc, enum dc_irq_source src, bool enable)
++{
++ dal_irq_service_set(dc->res_pool.irqs, src, enable);
++}
++
++void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src)
++{
++ dal_irq_service_ack(dc->res_pool.irqs, src);
++}
++
++const struct dc_target *dc_get_target_on_irq_source(
++ const struct dc *dc,
++ enum dc_irq_source src)
++{
++ uint8_t i, j;
++ uint8_t crtc_idx;
++
++ switch (src) {
++ case DC_IRQ_SOURCE_VUPDATE1:
++ case DC_IRQ_SOURCE_VUPDATE2:
++ case DC_IRQ_SOURCE_VUPDATE3:
++ case DC_IRQ_SOURCE_VUPDATE4:
++ case DC_IRQ_SOURCE_VUPDATE5:
++ case DC_IRQ_SOURCE_VUPDATE6:
++ crtc_idx = src - DC_IRQ_SOURCE_VUPDATE1;
++ break;
++ case DC_IRQ_SOURCE_PFLIP1:
++ case DC_IRQ_SOURCE_PFLIP2:
++ case DC_IRQ_SOURCE_PFLIP3:
++ case DC_IRQ_SOURCE_PFLIP4:
++ case DC_IRQ_SOURCE_PFLIP5:
++ case DC_IRQ_SOURCE_PFLIP6:
++ case DC_IRQ_SOURCE_PFLIP_UNDERLAY0:
++ crtc_idx = src - DC_IRQ_SOURCE_PFLIP1;
++ break;
++ default:
++ dal_error("%s: invalid irq source: %d\n!",__func__, src);
++ goto fail;
++ }
++
++ for (i = 0; i < dc->current_context.target_count; i++) {
++ const struct core_target *target =
++ dc->current_context.targets[i];
++
++ if (NULL == target) {
++ dal_error("%s: 'dc_target' is NULL for irq source: %d\n!",
++ __func__, src);
++ continue;
++ }
++
++ for (j = 0; j < target->stream_count; j++) {
++ const uint8_t controller_idx =
++ target->streams[j]->controller_idx;
++ if (controller_idx == crtc_idx)
++ return &target->public;
++ }
++ }
++fail:
++ return NULL;
++}
++
++void dc_set_power_state(
++ struct dc *dc,
++ enum dc_acpi_cm_power_state power_state,
++ enum dc_video_power_state video_power_state)
++{
++ dc->previous_power_state = dc->current_power_state;
++ dc->current_power_state = video_power_state;
++
++ switch (power_state) {
++ case DC_ACPI_CM_POWER_STATE_D0:
++ init_hw(dc);
++ break;
++ default:
++ /* NULL means "reset/release all DC targets" */
++ dc_commit_targets(dc, NULL, 0);
++
++ dc->hwss.power_down(&dc->current_context);
++ break;
++ }
++
++}
++
++void dc_resume(const struct dc *dc)
++{
++ uint32_t i;
++
++ for (i = 0; i < dc->link_count; i++)
++ core_link_resume(dc->links[i]);
++}
++
++void dc_print_sync_report(
++ const struct dc *dc)
++{
++ uint32_t i;
++ const struct core_target *core_target;
++ struct dc_context *dc_ctx = dc->ctx;
++ struct dc_target_sync_report *target_sync_report;
++ struct dc_sync_report sync_report = { 0 };
++
++ if (dc->current_context.target_count > MAX_TARGET_NUM) {
++ DC_ERROR("Target count: %d > %d!\n",
++ dc->current_context.target_count,
++ MAX_TARGET_NUM);
++ return;
++ }
++
++ sync_report.targets_num = dc->current_context.target_count;
++
++ /* Step 1: get data for sync validation */
++ for (i = 0; i < dc->current_context.target_count; i++) {
++
++ core_target = dc->current_context.targets[i];
++ target_sync_report = &sync_report.trg_reports[i];
++
++ dc->hwss.get_crtc_positions(
++ core_target->streams[0]->tg,
++ &target_sync_report->h_count,
++ &target_sync_report->v_count);
++
++ DC_SYNC_INFO("GSL:target[%d]: h: %d\t v: %d\n",
++ i,
++ target_sync_report->h_count,
++ target_sync_report->v_count);
++ }
++
++ /* Step 2: validate that display pipes are synchronized (based on
++ * data from Step 1). */
++}
++
++bool dc_read_dpcd(
++ struct dc *dc,
++ uint32_t link_index,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size)
++{
++ struct core_link *link =
++ DC_LINK_TO_LINK(dc_get_link_at_index(dc, link_index));
++ enum dc_status r = core_link_read_dpcd(link, address, data, size);
++
++ return r == DC_OK;
++}
++
++bool dc_write_dpcd(
++ struct dc *dc,
++ uint32_t link_index,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size)
++{
++ struct core_link *link =
++ DC_LINK_TO_LINK(dc_get_link_at_index(dc, link_index));
++ enum dc_status r = core_link_write_dpcd(link, address, data, size);
++
++ return r == DC_OK;
++}
++
++bool dc_link_add_sink(
++ struct dc_link *link,
++ struct dc_sink *sink)
++{
++ if (link->sink_count >= MAX_SINKS_PER_LINK) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ link->sink[link->sink_count] = sink;
++ link->sink_count++;
++
++ return true;
++}
++
++
++void dc_link_remove_sink(struct dc_link *link, const struct dc_sink *sink)
++{
++ int i;
++
++ if (!link->sink_count) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ for (i = 0; i < link->sink_count; i++) {
++ if (link->sink[i] == sink) {
++ dc_sink_release(sink);
++ link->sink[i] = NULL;
++ link->sink_count--;
++ return;
++ }
++ }
++
++ BREAK_TO_DEBUGGER();
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
+new file mode 100644
+index 0000000..b9e6ffd
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_hw_sequencer.c
+@@ -0,0 +1,49 @@
++/*
++ * Copyright 2015 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#include "dc_services.h"
++#include "core_types.h"
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/dce110_hw_sequencer.h"
++#endif
++
++bool dc_construct_hw_sequencer(
++ struct adapter_service *adapter_serv,
++ struct dc *dc)
++{
++ enum dce_version dce_ver = dal_adapter_service_get_dce_version(adapter_serv);
++
++ switch (dce_ver)
++ {
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ return dce110_hw_sequencer_construct(dc);
++#endif
++ default:
++ break;
++ }
++
++ return false;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c
+new file mode 100644
+index 0000000..a0a131e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link.c
+@@ -0,0 +1,1081 @@
++/*
++ * 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 "dc_services.h"
++#include "dc_helpers.h"
++#include "dc.h"
++#include "core_dc.h"
++#include "adapter_service_interface.h"
++#include "grph_object_id.h"
++#include "connector_interface.h"
++#include "gpio_service_interface.h"
++#include "ddc_service_interface.h"
++#include "core_status.h"
++#include "dc_link_dp.h"
++#include "link_hwss.h"
++#include "stream_encoder_types.h"
++#include "link_encoder_types.h"
++#include "hw_sequencer.h"
++
++
++#define LINK_INFO(...) \
++ dal_logger_write(dc_ctx->logger, \
++ LOG_MAJOR_HW_TRACE, LOG_MINOR_HW_TRACE_HOTPLUG, \
++ __VA_ARGS__)
++
++/*******************************************************************************
++ * Private structures
++ ******************************************************************************/
++
++
++/*******************************************************************************
++ * Private functions
++ ******************************************************************************/
++static void destruct(struct core_link *link)
++{
++ if (link->connector)
++ dal_connector_destroy(&link->connector);
++
++ if (link->ddc)
++ dal_ddc_service_destroy(&link->ddc);
++
++ if(link->link_enc)
++ link->ctx->dc->hwss.encoder_destroy(&link->link_enc);
++}
++
++static bool detect_sink(struct core_link *link)
++{
++ uint32_t is_hpd_high = 0;
++ struct irq *hpd_pin;
++
++ /* todo: may need to lock gpio access */
++ hpd_pin = dal_adapter_service_obtain_hpd_irq(
++ link->adapter_srv,
++ link->link_id);
++ if (hpd_pin == NULL)
++ goto hpd_gpio_failure;
++
++ dal_irq_open(hpd_pin);
++ dal_irq_get_value(hpd_pin, &is_hpd_high);
++ dal_irq_close(hpd_pin);
++ dal_adapter_service_release_irq(
++ link->adapter_srv,
++ hpd_pin);
++
++ if (is_hpd_high) {
++ link->public.type = dc_connection_single;
++ /* TODO: need to do the actual detection */
++ } else {
++ link->public.type = dc_connection_none;
++ }
++
++ return true;
++
++hpd_gpio_failure:
++ return false;
++}
++
++
++enum ddc_transaction_type get_ddc_transaction_type(
++ enum signal_type sink_signal)
++{
++ enum ddc_transaction_type transaction_type = DDC_TRANSACTION_TYPE_NONE;
++
++
++ switch (sink_signal) {
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ case SIGNAL_TYPE_LVDS:
++ case SIGNAL_TYPE_RGB:
++ transaction_type = DDC_TRANSACTION_TYPE_I2C;
++ break;
++
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_EDP:
++ transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
++ break;
++
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ /* MST does not use I2COverAux, but there is the
++ * SPECIAL use case for "immediate dwnstrm device
++ * access" (EPR#370830). */
++ transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
++ break;
++
++ default:
++ break;
++ }
++
++
++ return transaction_type;
++}
++
++static enum signal_type get_basic_signal_type(
++ struct graphics_object_id encoder,
++ struct graphics_object_id downstream)
++{
++ if (downstream.type == OBJECT_TYPE_CONNECTOR) {
++ switch (downstream.id) {
++ case CONNECTOR_ID_SINGLE_LINK_DVII:
++ switch (encoder.id) {
++ case ENCODER_ID_INTERNAL_DAC1:
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
++ case ENCODER_ID_INTERNAL_DAC2:
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
++ return SIGNAL_TYPE_RGB;
++ default:
++ return SIGNAL_TYPE_DVI_SINGLE_LINK;
++ }
++ break;
++ case CONNECTOR_ID_DUAL_LINK_DVII:
++ {
++ switch (encoder.id) {
++ case ENCODER_ID_INTERNAL_DAC1:
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC1:
++ case ENCODER_ID_INTERNAL_DAC2:
++ case ENCODER_ID_INTERNAL_KLDSCP_DAC2:
++ return SIGNAL_TYPE_RGB;
++ default:
++ return SIGNAL_TYPE_DVI_DUAL_LINK;
++ }
++ }
++ break;
++ case CONNECTOR_ID_SINGLE_LINK_DVID:
++ return SIGNAL_TYPE_DVI_SINGLE_LINK;
++ case CONNECTOR_ID_DUAL_LINK_DVID:
++ return SIGNAL_TYPE_DVI_DUAL_LINK;
++ case CONNECTOR_ID_VGA:
++ return SIGNAL_TYPE_RGB;
++ case CONNECTOR_ID_HDMI_TYPE_A:
++ return SIGNAL_TYPE_HDMI_TYPE_A;
++ case CONNECTOR_ID_LVDS:
++ return SIGNAL_TYPE_LVDS;
++ case CONNECTOR_ID_DISPLAY_PORT:
++ return SIGNAL_TYPE_DISPLAY_PORT;
++ case CONNECTOR_ID_EDP:
++ return SIGNAL_TYPE_EDP;
++ default:
++ return SIGNAL_TYPE_NONE;
++ }
++ } else if (downstream.type == OBJECT_TYPE_ENCODER) {
++ switch (downstream.id) {
++ case ENCODER_ID_EXTERNAL_NUTMEG:
++ case ENCODER_ID_EXTERNAL_TRAVIS:
++ return SIGNAL_TYPE_DISPLAY_PORT;
++ default:
++ return SIGNAL_TYPE_NONE;
++ }
++ }
++
++ return SIGNAL_TYPE_NONE;
++}
++
++/*
++ * @brief
++ * Check whether there is a dongle on DP connector
++ */
++static bool is_dp_sink_present(struct core_link *link)
++{
++ enum gpio_result gpio_result;
++ uint32_t clock_pin = 0;
++ uint32_t data_pin = 0;
++
++ struct ddc *ddc;
++
++ enum connector_id connector_id =
++ dal_graphics_object_id_get_connector_id(link->link_id);
++
++ bool present =
++ ((connector_id == CONNECTOR_ID_DISPLAY_PORT) ||
++ (connector_id == CONNECTOR_ID_EDP));
++
++ ddc = dal_adapter_service_obtain_ddc(link->adapter_srv, link->link_id);
++
++ if (!ddc)
++ return present;
++
++ /* Open GPIO and set it to I2C mode */
++ /* Note: this GpioMode_Input will be converted
++ * to GpioConfigType_I2cAuxDualMode in GPIO component,
++ * which indicates we need additional delay */
++
++ if (GPIO_RESULT_OK != dal_ddc_open(
++ ddc, GPIO_MODE_INPUT, GPIO_DDC_CONFIG_TYPE_MODE_I2C)) {
++ dal_adapter_service_release_ddc(link->adapter_srv, ddc);
++
++ return present;
++ }
++
++ /* Read GPIO: DP sink is present if both clock and data pins are zero */
++ /* [anaumov] in DAL2, there was no check for GPIO failure */
++
++ gpio_result = dal_ddc_get_clock(ddc, &clock_pin);
++ ASSERT(gpio_result == GPIO_RESULT_OK);
++
++ if (gpio_result == GPIO_RESULT_OK)
++ if (link->link_enc->features.flags.bits.
++ DP_SINK_DETECT_POLL_DATA_PIN)
++ gpio_result = dal_ddc_get_data(ddc, &data_pin);
++
++ present = (gpio_result == GPIO_RESULT_OK) && !(clock_pin || data_pin);
++
++ dal_ddc_close(ddc);
++
++ dal_adapter_service_release_ddc(link->adapter_srv, ddc);
++
++ return present;
++}
++
++/*
++ * @brief
++ * Detect output sink type
++ */
++static enum signal_type link_detect_sink(struct core_link *link)
++{
++ enum signal_type result = get_basic_signal_type(
++ link->link_enc->id, link->link_id);
++
++ /* Internal digital encoder will detect only dongles
++ * that require digital signal */
++
++ /* Detection mechanism is different
++ * for different native connectors.
++ * LVDS connector supports only LVDS signal;
++ * PCIE is a bus slot, the actual connector needs to be detected first;
++ * eDP connector supports only eDP signal;
++ * HDMI should check straps for audio */
++
++ /* PCIE detects the actual connector on add-on board */
++
++ if (link->link_id.id == CONNECTOR_ID_PCIE) {
++ /* ZAZTODO implement PCIE add-on card detection */
++ }
++
++ switch (link->link_id.id) {
++ case CONNECTOR_ID_HDMI_TYPE_A: {
++ /* check audio support:
++ * if native HDMI is not supported, switch to DVI */
++ union audio_support audio_support =
++ dal_adapter_service_get_audio_support(
++ link->adapter_srv);
++
++ if (!audio_support.bits.HDMI_AUDIO_NATIVE)
++ if (link->link_id.id == CONNECTOR_ID_HDMI_TYPE_A)
++ result = SIGNAL_TYPE_DVI_SINGLE_LINK;
++ }
++ break;
++ case CONNECTOR_ID_DISPLAY_PORT: {
++
++ /* Check whether DP signal detected: if not -
++ * we assume signal is DVI; it could be corrected
++ * to HDMI after dongle detection */
++ if (!is_dp_sink_present(link))
++ result = SIGNAL_TYPE_DVI_SINGLE_LINK;
++ }
++ break;
++ default:
++ break;
++ }
++
++ return result;
++}
++
++static enum signal_type decide_signal_from_strap_and_dongle_type(
++ enum display_dongle_type dongle_type,
++ union audio_support *audio_support)
++{
++ enum signal_type signal = SIGNAL_TYPE_NONE;
++
++ switch (dongle_type) {
++ case DISPLAY_DONGLE_DP_HDMI_DONGLE:
++ if (audio_support->bits.HDMI_AUDIO_ON_DONGLE)
++ signal = SIGNAL_TYPE_HDMI_TYPE_A;
++ else
++ signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
++ break;
++ case DISPLAY_DONGLE_DP_DVI_DONGLE:
++ signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
++ break;
++ case DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE:
++ if (audio_support->bits.HDMI_AUDIO_NATIVE)
++ signal = SIGNAL_TYPE_HDMI_TYPE_A;
++ else
++ signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
++ break;
++ default:
++ signal = SIGNAL_TYPE_NONE;
++ break;
++ }
++
++ return signal;
++}
++
++static enum signal_type dp_passive_dongle_detection(
++ struct ddc_service *ddc,
++ struct display_sink_capability *sink_cap,
++ union audio_support *audio_support)
++{
++ /* TODO:These 2 functions should be protected for upstreaming purposes
++ * in case hackers want to save 10 cents hdmi license fee
++ */
++ dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
++ ddc, sink_cap);
++ return decide_signal_from_strap_and_dongle_type(
++ sink_cap->dongle_type,
++ audio_support);
++}
++
++static bool is_dp_active_dongle(enum display_dongle_type dongle_type)
++{
++ return (dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER ||
++ dongle_type == DISPLAY_DONGLE_DP_DVI_CONVERTER ||
++ dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER);
++}
++
++/* TODO: To beretired because this call is wrong with
++ * pluging in of active-dongle without display*/
++static void link_unplug(struct core_link *link)
++{
++ int i;
++
++ for (i = 0; i < link->public.sink_count; i++)
++ dc_link_remove_sink(&link->public, link->public.sink[i]);
++}
++
++static enum dc_edid_status read_edid(struct core_link *link)
++{
++ uint32_t edid_retry = 3;
++ enum dc_edid_status edid_status;
++ const struct dc_sink *dc_sink = link->public.sink[0];
++ struct core_sink *sink = DC_SINK_TO_CORE(dc_sink);
++
++ if (link->public.sink[0]->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST) {
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_DETECTION_EDID_PARSER,
++ "MST EDID read is not done here!\n");
++ return EDID_BAD_INPUT;
++ }
++
++ /* some dongles read edid incorrectly the first time,
++ * do check sum and retry to make sure read correct edid.
++ */
++ do {
++ sink->public.dc_edid.length =
++ dal_ddc_service_edid_query(link->ddc);
++
++ if (0 == sink->public.dc_edid.length)
++ return EDID_NO_RESPONSE;
++
++ dal_ddc_service_get_edid_buf(link->ddc,
++ sink->public.dc_edid.raw_edid);
++ edid_status = dc_helpers_parse_edid_caps(
++ link->ctx,
++ &sink->public.dc_edid,
++ &sink->public.edid_caps);
++ --edid_retry;
++ if (edid_status == EDID_BAD_CHECKSUM)
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_DETECTION_EDID_PARSER,
++ "Bad EDID checksum, retry remain: %d\n",
++ edid_retry);
++ } while (edid_status == EDID_BAD_CHECKSUM && edid_retry > 0);
++
++ return edid_status;
++}
++
++void dc_link_detect(const struct dc_link *dc_link)
++{
++ struct core_link *link = DC_LINK_TO_LINK(dc_link);
++ struct sink_init_data sink_init_data = { 0 };
++ enum ddc_transaction_type transaction_type = DDC_TRANSACTION_TYPE_NONE;
++ struct display_sink_capability sink_caps = { 0 };
++ uint8_t i;
++ enum signal_type signal = SIGNAL_TYPE_NONE;
++ bool converter_disable_audio = false;
++ union audio_support audio_support =
++ dal_adapter_service_get_audio_support(
++ link->adapter_srv);
++ enum dc_edid_status edid_status;
++ struct dc_context *dc_ctx = link->ctx;
++ struct dc_sink *dc_sink;
++ struct core_sink *sink = NULL;
++
++ if (false == detect_sink(link)) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ if (link->public.type != dc_connection_none) {
++ /* From Disconnected-to-Connected. */
++ switch (link->public.connector_signal) {
++ case SIGNAL_TYPE_HDMI_TYPE_A: {
++ transaction_type = DDC_TRANSACTION_TYPE_I2C;
++ if (audio_support.bits.HDMI_AUDIO_NATIVE)
++ signal = SIGNAL_TYPE_HDMI_TYPE_A;
++ else
++ signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
++ break;
++ }
++
++ case SIGNAL_TYPE_DVI_SINGLE_LINK: {
++ transaction_type = DDC_TRANSACTION_TYPE_I2C;
++ signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
++ break;
++ }
++
++ case SIGNAL_TYPE_DVI_DUAL_LINK: {
++ transaction_type = DDC_TRANSACTION_TYPE_I2C;
++ signal = SIGNAL_TYPE_DVI_DUAL_LINK;
++ break;
++ }
++
++ case SIGNAL_TYPE_EDP: {
++ detect_dp_sink_caps(link);
++ transaction_type = DDC_TRANSACTION_TYPE_I2C_OVER_AUX;
++ signal = SIGNAL_TYPE_EDP;
++ break;
++ }
++
++ case SIGNAL_TYPE_DISPLAY_PORT: {
++ signal = link_detect_sink(link);
++ transaction_type = get_ddc_transaction_type(
++ signal);
++
++ if (transaction_type ==
++ DDC_TRANSACTION_TYPE_I2C_OVER_AUX) {
++ signal =
++ SIGNAL_TYPE_DISPLAY_PORT;
++ detect_dp_sink_caps(link);
++
++ /* DP active dongles */
++ if (is_dp_active_dongle(
++ link->dpcd_caps.dongle_type)) {
++ if (!link->dpcd_caps.
++ sink_count.bits.SINK_COUNT) {
++ link->public.type =
++ dc_connection_none;
++ /* active dongle unplug
++ * processing for short irq
++ */
++ link_unplug(link);
++ return;
++ }
++
++ if (link->dpcd_caps.dongle_type !=
++ DISPLAY_DONGLE_DP_HDMI_CONVERTER) {
++ converter_disable_audio = true;
++ }
++ }
++ if (is_mst_supported(link)) {
++ signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
++
++ /*
++ * This call will initiate MST topology
++ * discovery. Which will detect
++ * MST ports and add new DRM connector
++ * DRM framework. Then read EDID via
++ * remote i2c over aux.In the end, will
++ * notify DRM detect result and save
++ * EDID into DRM framework.
++ *
++ * .detect is called by .fill_modes.
++ * .fill_modes is called by user mode
++ * ioctl DRM_IOCTL_MODE_GETCONNECTOR.
++ *
++ * .get_modes is called by .fill_modes.
++ *
++ * call .get_modes, AMDGPU DM
++ * implementation will create new
++ * dc_sink and add to dc_link.
++ * For long HPD plug in/out, MST has its
++ * own handle.
++ *
++ * Therefore, just after dc_create,
++ * link->sink is not created for MST
++ * until user mode app calls
++ * DRM_IOCTL_MODE_GETCONNECTOR.
++ *
++ * Need check ->sink usages in case
++ * ->sink = NULL
++ * TODO: s3 resume check*/
++
++ if (dc_helpers_dp_mst_start_top_mgr(link->ctx, &link->public)) {
++ return;
++ } else {
++ /* MST not supported */
++ signal = SIGNAL_TYPE_DISPLAY_PORT;
++ }
++ }
++ }
++ else {
++ /* DP passive dongles */
++ signal = dp_passive_dongle_detection(link->ddc,
++ &sink_caps,
++ &audio_support);
++ }
++ break;
++ }
++
++ default:
++ DC_ERROR("Invalid connector type! signal:%d\n",
++ link->public.connector_signal);
++ return;
++ } /* switch() */
++
++ if (link->dpcd_caps.sink_count.bits.SINK_COUNT)
++ link->dpcd_sink_count = link->dpcd_caps.sink_count.
++ bits.SINK_COUNT;
++ else
++ link->dpcd_sink_count = 1;
++
++
++ dal_ddc_service_set_transaction_type(
++ link->ddc,
++ transaction_type);
++
++ sink_init_data.link = &link->public;
++ sink_init_data.sink_signal = signal;
++ sink_init_data.dongle_max_pix_clk =
++ sink_caps.max_hdmi_pixel_clock;
++ sink_init_data.converter_disable_audio =
++ converter_disable_audio;
++
++ dc_sink = sink_create(&sink_init_data);
++ if (!dc_sink) {
++ DC_ERROR("Failed to create sink!\n");
++ return;
++ }
++
++ sink = DC_SINK_TO_CORE(dc_sink);
++
++ /*AG TODO handle failure */
++ /*Only non MST case here */
++ if (!dc_link_add_sink(&link->public, &sink->public))
++ BREAK_TO_DEBUGGER();
++
++ edid_status = read_edid(link);
++
++ switch (edid_status) {
++ case EDID_BAD_CHECKSUM:
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_DETECTION_EDID_PARSER,
++ "EDID checksum invalid.\n");
++ break;
++ case EDID_NO_RESPONSE:
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_DETECTION_EDID_PARSER,
++ "No EDID read.\n");
++ return;
++
++ default:
++ break;
++ }
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_DETECTION,
++ LOG_MINOR_DETECTION_EDID_PARSER,
++ "%s: "
++ "manufacturer_id = %X, "
++ "product_id = %X, "
++ "serial_number = %X, "
++ "manufacture_week = %d, "
++ "manufacture_year = %d, "
++ "display_name = %s, "
++ "speaker_flag = %d, "
++ "audio_mode_count = %d\n",
++ __func__,
++ sink->public.edid_caps.manufacturer_id,
++ sink->public.edid_caps.product_id,
++ sink->public.edid_caps.serial_number,
++ sink->public.edid_caps.manufacture_week,
++ sink->public.edid_caps.manufacture_year,
++ sink->public.edid_caps.display_name,
++ sink->public.edid_caps.speaker_flags,
++ sink->public.edid_caps.audio_mode_count);
++
++ for (i = 0; i < sink->public.edid_caps.audio_mode_count; i++) {
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_DETECTION,
++ LOG_MINOR_DETECTION_EDID_PARSER,
++ "%s: mode number = %d, "
++ "format_code = %d, "
++ "channel_count = %d, "
++ "sample_rate = %d, "
++ "sample_size = %d\n",
++ __func__,
++ i,
++ sink->public.edid_caps.audio_modes[i].format_code,
++ sink->public.edid_caps.audio_modes[i].channel_count,
++ sink->public.edid_caps.audio_modes[i].sample_rate,
++ sink->public.edid_caps.audio_modes[i].sample_size);
++ }
++
++ } else {
++ /* From Connected-to-Disconnected. */
++ switch (link->public.connector_signal) {
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ dc_helpers_dp_mst_stop_top_mgr(link->ctx, &link->public);
++ break;
++ default:
++ break;
++ }
++ link_unplug(link);
++ }
++
++ LINK_INFO("link=%d, dc_sink_in=%p is now %s\n",
++ link->link_index, &sink->public,
++ (signal == SIGNAL_TYPE_NONE ? "Disconnected":"Connected"));
++
++ /* TODO: */
++
++ return;
++}
++
++static bool construct(
++ struct core_link *link,
++ const struct link_init_data *init_params)
++{
++ struct irq *hpd_gpio = NULL;
++ struct ddc_service_init_data ddc_service_init_data = { 0 };
++ struct dc_context *dc_ctx = init_params->ctx;
++ struct encoder_init_data enc_init_data = { 0 };
++ struct connector_feature_support cfs = { 0 };
++
++ link->dc = init_params->dc;
++ link->adapter_srv = init_params->adapter_srv;
++ link->connector_index = init_params->connector_index;
++ link->ctx = dc_ctx;
++ link->link_index = init_params->link_index;
++
++ link->link_id = dal_adapter_service_get_connector_obj_id(
++ init_params->adapter_srv,
++ init_params->connector_index);
++
++ if (link->link_id.type != OBJECT_TYPE_CONNECTOR) {
++ dal_error("%s: Invalid Connector ObjectID from Adapter Service for connector index:%d!\n",
++ __func__, init_params->connector_index);
++ goto create_fail;
++ }
++
++ switch (link->link_id.id) {
++ case CONNECTOR_ID_HDMI_TYPE_A:
++ link->public.connector_signal = SIGNAL_TYPE_HDMI_TYPE_A;
++ break;
++ case CONNECTOR_ID_SINGLE_LINK_DVID:
++ case CONNECTOR_ID_SINGLE_LINK_DVII:
++ link->public.connector_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
++ break;
++ case CONNECTOR_ID_DUAL_LINK_DVID:
++ case CONNECTOR_ID_DUAL_LINK_DVII:
++ link->public.connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK;
++ break;
++ case CONNECTOR_ID_DISPLAY_PORT:
++ link->public.connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
++ hpd_gpio = dal_adapter_service_obtain_hpd_irq(
++ init_params->adapter_srv,
++ link->link_id);
++
++ if (hpd_gpio != NULL) {
++ link->public.irq_source_hpd_rx =
++ dal_irq_get_rx_source(hpd_gpio);
++ dal_adapter_service_release_irq(
++ init_params->adapter_srv, hpd_gpio);
++ }
++ break;
++ case CONNECTOR_ID_EDP:
++ link->public.connector_signal = SIGNAL_TYPE_EDP;
++ hpd_gpio = dal_adapter_service_obtain_hpd_irq(
++ init_params->adapter_srv,
++ link->link_id);
++
++ if (hpd_gpio != NULL) {
++ link->public.irq_source_hpd_rx =
++ dal_irq_get_rx_source(hpd_gpio);
++ dal_adapter_service_release_irq(
++ init_params->adapter_srv, hpd_gpio);
++ }
++ break;
++ default:
++ dal_logger_write(dc_ctx->logger,
++ LOG_MAJOR_WARNING, LOG_MINOR_TM_LINK_SRV,
++ "Unsupported Connector type:%d!\n", link->link_id.id);
++ goto create_fail;
++ }
++
++ /* TODO: #DAL3 Implement id to str function.*/
++ LINK_INFO("Connector[%d] description:\n",
++ init_params->connector_index);
++
++ link->connector = dal_connector_create(dc_ctx,
++ init_params->adapter_srv,
++ link->link_id);
++ if (NULL == link->connector) {
++ DC_ERROR("Failed to create connector object!\n");
++ goto create_fail;
++ }
++
++
++ hpd_gpio = dal_adapter_service_obtain_hpd_irq(
++ init_params->adapter_srv,
++ link->link_id);
++
++ if (hpd_gpio != NULL) {
++ link->public.irq_source_hpd = dal_irq_get_source(hpd_gpio);
++ dal_adapter_service_release_irq(
++ init_params->adapter_srv, hpd_gpio);
++ }
++
++ ddc_service_init_data.as = link->adapter_srv;
++ ddc_service_init_data.ctx = link->ctx;
++ ddc_service_init_data.id = link->link_id;
++ link->ddc = dal_ddc_service_create(&ddc_service_init_data);
++
++ if (NULL == link->ddc) {
++ DC_ERROR("Failed to create ddc_service!\n");
++ goto create_fail;
++ }
++
++ dal_connector_get_features(link->connector, &cfs);
++
++ enc_init_data.adapter_service = link->adapter_srv;
++ enc_init_data.ctx = dc_ctx;
++ enc_init_data.encoder = dal_adapter_service_get_src_obj(
++ link->adapter_srv, link->link_id, 0);
++ enc_init_data.connector = link->link_id;
++ enc_init_data.channel = cfs.ddc_line;
++ enc_init_data.hpd_source = cfs.hpd_line;
++ link->link_enc = dc_ctx->dc->hwss.encoder_create(&enc_init_data);
++
++ if( link->link_enc == NULL) {
++ DC_ERROR("Failed to create link encoder!\n");
++ goto create_fail;
++ }
++
++ /*
++ * TODO check if GPIO programmed correctly
++ *
++ * If GPIO isn't programmed correctly HPD might not rise or drain
++ * fast enough, leading to bounces.
++ */
++#define DELAY_ON_CONNECT_IN_MS 500
++#define DELAY_ON_DISCONNECT_IN_MS 500
++
++ dal_connector_program_hpd_filter(
++ link->connector,
++ DELAY_ON_CONNECT_IN_MS,
++ DELAY_ON_DISCONNECT_IN_MS);
++
++ return true;
++
++create_fail:
++ return false;
++}
++
++/*******************************************************************************
++ * Public functions
++ ******************************************************************************/
++struct core_link *link_create(const struct link_init_data *init_params)
++{
++ struct core_link *link =
++ dc_service_alloc(init_params->ctx, sizeof(*link));
++ link->ctx = init_params->ctx;
++
++ if (NULL == link)
++ goto alloc_fail;
++
++ if (false == construct(link, init_params))
++ goto construct_fail;
++
++ return link;
++
++construct_fail:
++ dc_service_free(init_params->ctx, link);
++
++alloc_fail:
++ return NULL;
++}
++
++void link_destroy(struct core_link **link)
++{
++ destruct(*link);
++ dc_service_free((*link)->ctx, *link);
++ *link = NULL;
++}
++
++static void dpcd_configure_panel_mode(
++ struct core_link *link,
++ enum dp_panel_mode panel_mode)
++{
++ union dpcd_edp_config edp_config_set;
++ bool panel_mode_edp = false;
++
++ dc_service_memset(&edp_config_set, '\0', sizeof(union dpcd_edp_config));
++
++ if (DP_PANEL_MODE_DEFAULT != panel_mode) {
++
++ switch (panel_mode) {
++ case DP_PANEL_MODE_EDP:
++ case DP_PANEL_MODE_SPECIAL:
++ panel_mode_edp = true;
++ break;
++
++ default:
++ break;
++ }
++
++ /*set edp panel mode in receiver*/
++ core_link_read_dpcd(
++ link,
++ DPCD_ADDRESS_EDP_CONFIG_SET,
++ &edp_config_set.raw,
++ sizeof(edp_config_set.raw));
++
++ if (edp_config_set.bits.PANEL_MODE_EDP
++ != panel_mode_edp) {
++ enum ddc_result result = DDC_RESULT_UNKNOWN;
++
++ edp_config_set.bits.PANEL_MODE_EDP =
++ panel_mode_edp;
++ result = core_link_write_dpcd(
++ link,
++ DPCD_ADDRESS_EDP_CONFIG_SET,
++ &edp_config_set.raw,
++ sizeof(edp_config_set.raw));
++
++ ASSERT(result == DDC_RESULT_SUCESSFULL);
++ }
++ }
++ dal_logger_write(link->ctx->logger, LOG_MAJOR_DETECTION,
++ LOG_MINOR_DETECTION_DP_CAPS,
++ "Connector: %d eDP panel mode supported: %d "
++ "eDP panel mode enabled: %d \n",
++ link->connector_index,
++ link->dpcd_caps.panel_mode_edp,
++ panel_mode_edp);
++}
++
++static enum dc_status enable_link_dp(struct core_stream *stream)
++{
++ enum dc_status status;
++ bool skip_video_pattern;
++ struct core_link *link = stream->sink->link;
++ struct link_settings link_settings = {0};
++ enum dp_panel_mode panel_mode;
++
++ /* get link settings for video mode timing */
++ decide_link_settings(stream, &link_settings);
++ status = dp_enable_link_phy(
++ stream->sink->link,
++ stream->signal,
++ stream->stream_enc->id,
++ &link_settings);
++
++ panel_mode = dp_get_panel_mode(link);
++ dpcd_configure_panel_mode(link, panel_mode);
++
++ skip_video_pattern = true;
++
++ if (link_settings.link_rate == LINK_RATE_LOW)
++ skip_video_pattern = false;
++
++ if (perform_link_training(link, &link_settings, skip_video_pattern)) {
++ link->cur_link_settings = link_settings;
++ status = DC_OK;
++ }
++ else
++ status = DC_ERROR_UNEXPECTED;
++
++ return status;
++}
++
++static enum dc_status enable_link_hdmi(struct core_stream *stream)
++{
++ struct core_link *link = stream->sink->link;
++
++ /* TODO:Need to add missing use cases, reference
++ * dal_hw_sequencer_enable_link_base*/
++ enum dc_status status = DC_OK;
++
++ /* enable video output */
++ /* here we need to specify that encoder output settings
++ * need to be calculated as for the set mode,
++ * it will lead to querying dynamic link capabilities
++ * which should be done before enable output */
++
++ uint32_t normalized_pix_clk = stream->public.timing.pix_clk_khz;
++ switch (stream->public.timing.display_color_depth) {
++ case COLOR_DEPTH_888:
++ break;
++ case COLOR_DEPTH_101010:
++ normalized_pix_clk = (normalized_pix_clk * 30) / 24;
++ break;
++ case COLOR_DEPTH_121212:
++ normalized_pix_clk = (normalized_pix_clk * 36) / 24;
++ break;
++ case COLOR_DEPTH_161616:
++ normalized_pix_clk = (normalized_pix_clk * 48) / 24;
++ break;
++ default:
++ break;
++ }
++
++ if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
++ dal_ddc_service_write_scdc_data(
++ stream->sink->link->ddc,
++ normalized_pix_clk,
++ stream->public.timing.flags.LTE_340MCSC_SCRAMBLE);
++
++ stream->sink->link->cur_link_settings.lane_count =
++ (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
++ ? LANE_COUNT_EIGHT : LANE_COUNT_FOUR;
++
++ if (link->ctx->dc->hwss.encoder_enable_output(
++ stream->sink->link->link_enc,
++ &stream->sink->link->cur_link_settings,
++ stream->stream_enc->id,
++ dal_clock_source_get_id(stream->clock_source),
++ stream->signal,
++ stream->public.timing.display_color_depth,
++ stream->public.timing.pix_clk_khz) != ENCODER_RESULT_OK)
++ status = DC_ERROR_UNEXPECTED;
++
++ if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
++ dal_ddc_service_read_scdc_data(link->ddc);
++
++ return status;
++}
++
++/****************************enable_link***********************************/
++enum dc_status core_link_enable(struct core_stream *stream)
++{
++ enum dc_status status;
++ switch (stream->signal) {
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_EDP:
++ status = enable_link_dp(stream);
++ break;
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ status = enable_link_hdmi(stream);
++ break;
++
++ default:
++ status = DC_ERROR_UNEXPECTED;
++ break;
++ }
++
++ if (stream->audio) {
++ stream->ctx->dc->hwss.set_afmt_memory_power_state(
++ stream->ctx, stream->stream_enc->id, true);
++ /* notify audio driver for audio modes of monitor */
++ dal_audio_enable_azalia_audio_jack_presence(stream->audio,
++ stream->stream_enc->id);
++
++ /* un-mute audio */
++ dal_audio_unmute(stream->audio, stream->stream_enc->id,
++ stream->signal);
++ }
++
++ return status;
++}
++
++enum dc_status core_link_disable(struct core_stream *stream)
++{
++ /* TODO dp_set_hw_test_pattern */
++ enum dc_status status = DC_OK;
++ struct dc *dc = stream->ctx->dc;
++
++ /* here we need to specify that encoder output settings
++ * need to be calculated as for the set mode,
++ * it will lead to querying dynamic link capabilities
++ * which should be done before enable output */
++
++ if (dc_is_dp_signal(stream->signal))
++ dp_disable_link_phy(stream->sink->link, stream->signal);
++ else if (ENCODER_RESULT_OK != dc->hwss.encoder_disable_output(
++ stream->sink->link->link_enc, stream->signal))
++ status = DC_ERROR_UNEXPECTED;
++
++ if (stream->audio) {
++ dc->hwss.set_afmt_memory_power_state(
++ stream->ctx, stream->stream_enc->id, false);
++ }
++
++ return status;
++}
++
++enum dc_status dc_link_validate_mode_timing(
++ const struct core_sink *sink,
++ struct core_link *link,
++ const struct dc_crtc_timing *timing)
++{
++ uint32_t max_pix_clk = sink->dongle_max_pix_clk;
++
++ if (0 != max_pix_clk && timing->pix_clk_khz > max_pix_clk)
++ return DC_EXCEED_DONGLE_MAX_CLK;
++
++ switch (sink->public.sink_signal) {
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ if(!dp_validate_mode_timing(
++ link,
++ timing))
++ return DC_NO_DP_LINK_BANDWIDTH;
++ break;
++
++ default:
++ break;
++ }
++
++ return DC_OK;
++}
++
++bool dc_link_set_backlight_level(const struct dc_link *public, uint32_t level)
++{
++ struct core_link *protected = DC_LINK_TO_CORE(public);
++ struct dc_context *ctx = protected->ctx;
++
++ dal_logger_write(ctx->logger, LOG_MAJOR_BACKLIGHT,
++ LOG_MINOR_BACKLIGHT_INTERFACE,
++ "New Backlight level: %d (0x%X)\n", level, level);
++
++ ctx->dc->hwss.encoder_set_lcd_backlight_level(protected->link_enc, level);
++
++ return true;
++}
++
++void core_link_resume(struct core_link *link)
++{
++ dal_connector_program_hpd_filter(
++ link->connector,
++ DELAY_ON_CONNECT_IN_MS,
++ DELAY_ON_DISCONNECT_IN_MS);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c
+new file mode 100644
+index 0000000..9214aec
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link_dp.c
+@@ -0,0 +1,1689 @@
++/* Copyright 2015 Advanced Micro Devices, Inc. */
++#include "dc_services.h"
++#include "dc.h"
++#include "dc_helpers.h"
++#include "inc/core_types.h"
++#include "link_hwss.h"
++#include "ddc_service_interface.h"
++#include "connector_interface.h"
++#include "core_status.h"
++#include "dpcd_defs.h"
++
++/* maximum pre emphasis level allowed for each voltage swing level*/
++static const enum pre_emphasis voltage_swing_to_pre_emphasis[] = {
++ PRE_EMPHASIS_LEVEL3,
++ PRE_EMPHASIS_LEVEL2,
++ PRE_EMPHASIS_LEVEL1,
++ PRE_EMPHASIS_DISABLED };
++
++enum {
++ POST_LT_ADJ_REQ_LIMIT = 6,
++ POST_LT_ADJ_REQ_TIMEOUT = 200
++};
++
++enum {
++ LINK_TRAINING_MAX_RETRY_COUNT = 5,
++ /* to avoid infinite loop where-in the receiver
++ * switches between different VS
++ */
++ LINK_TRAINING_MAX_CR_RETRY = 100
++};
++
++static const struct link_settings link_training_fallback_table[] = {
++/* 2160 Mbytes/sec*/
++{ LANE_COUNT_FOUR, LINK_RATE_HIGH2, LINK_SPREAD_DISABLED },
++/* 1080 Mbytes/sec*/
++{ LANE_COUNT_FOUR, LINK_RATE_HIGH, LINK_SPREAD_DISABLED },
++/* 648 Mbytes/sec*/
++{ LANE_COUNT_FOUR, LINK_RATE_LOW, LINK_SPREAD_DISABLED },
++/* 1080 Mbytes/sec*/
++{ LANE_COUNT_TWO, LINK_RATE_HIGH2, LINK_SPREAD_DISABLED },
++/* 540 Mbytes/sec*/
++{ LANE_COUNT_TWO, LINK_RATE_HIGH, LINK_SPREAD_DISABLED },
++/* 324 Mbytes/sec*/
++{ LANE_COUNT_TWO, LINK_RATE_LOW, LINK_SPREAD_DISABLED },
++/* 540 Mbytes/sec*/
++{ LANE_COUNT_ONE, LINK_RATE_HIGH2, LINK_SPREAD_DISABLED },
++/* 270 Mbytes/sec*/
++{ LANE_COUNT_ONE, LINK_RATE_HIGH, LINK_SPREAD_DISABLED },
++/* 162 Mbytes/sec*/
++{ LANE_COUNT_ONE, LINK_RATE_LOW, LINK_SPREAD_DISABLED } };
++
++static void wait_for_training_aux_rd_interval(
++ struct core_link* link,
++ uint32_t default_wait_in_micro_secs)
++{
++ uint8_t training_rd_interval;
++
++ /* overwrite the delay if rev > 1.1*/
++ if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
++ /* DP 1.2 or later - retrieve delay through
++ * "DPCD_ADDR_TRAINING_AUX_RD_INTERVAL" register */
++ core_link_read_dpcd(
++ link,
++ DPCD_ADDRESS_TRAINING_AUX_RD_INTERVAL,
++ &training_rd_interval,
++ sizeof(training_rd_interval));
++ default_wait_in_micro_secs = training_rd_interval ?
++ (training_rd_interval * 4000) :
++ default_wait_in_micro_secs;
++ }
++
++ dc_service_delay_in_microseconds(link->ctx, default_wait_in_micro_secs);
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s:\n wait = %d\n",
++ __func__,
++ default_wait_in_micro_secs);
++}
++
++static void dpcd_set_training_pattern(
++ struct core_link* link,
++ union dpcd_training_pattern dpcd_pattern)
++{
++ core_link_write_dpcd(
++ link,
++ DPCD_ADDRESS_TRAINING_PATTERN_SET,
++ &dpcd_pattern.raw,
++ 1);
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s\n %x pattern = %x\n",
++ __func__,
++ DPCD_ADDRESS_TRAINING_PATTERN_SET,
++ dpcd_pattern.bits.TRAINING_PATTERN_SET);
++}
++
++static void dpcd_set_link_settings(
++ struct core_link* link,
++ const struct link_training_settings *lt_settings)
++{
++ uint8_t rate = (uint8_t)
++ (lt_settings->link_settings.link_rate);
++
++ union down_spread_ctrl downspread = {{0}};
++ union lane_count_set lane_count_set = {{0}};
++ uint8_t link_set_buffer[2];
++
++
++ downspread.raw = (uint8_t)
++ (lt_settings->link_settings.link_spread);
++
++ lane_count_set.bits.LANE_COUNT_SET =
++ lt_settings->link_settings.lane_count;
++
++ lane_count_set.bits.ENHANCED_FRAMING = 1;
++
++ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED =
++ link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED;
++
++ link_set_buffer[0] = rate;
++ link_set_buffer[1] = lane_count_set.raw;
++
++ core_link_write_dpcd(link, DPCD_ADDRESS_LINK_BW_SET,
++ link_set_buffer, 2);
++ core_link_write_dpcd(link, DPCD_ADDRESS_DOWNSPREAD_CNTL,
++ &downspread.raw, sizeof(downspread));
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s\n %x rate = %x\n %x lane = %x\n %x spread = %x\n",
++ __func__,
++ DPCD_ADDRESS_LINK_BW_SET,
++ lt_settings->link_settings.link_rate,
++ DPCD_ADDRESS_LANE_COUNT_SET,
++ lt_settings->link_settings.lane_count,
++ DPCD_ADDRESS_DOWNSPREAD_CNTL,
++ lt_settings->link_settings.link_spread);
++
++}
++
++static enum dpcd_training_patterns
++ hw_training_pattern_to_dpcd_training_pattern(
++ struct core_link* link,
++ enum hw_dp_training_pattern pattern)
++{
++ enum dpcd_training_patterns dpcd_tr_pattern =
++ DPCD_TRAINING_PATTERN_VIDEOIDLE;
++
++ switch (pattern) {
++ case HW_DP_TRAINING_PATTERN_1:
++ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_1;
++ break;
++ case HW_DP_TRAINING_PATTERN_2:
++ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_2;
++ break;
++ case HW_DP_TRAINING_PATTERN_3:
++ dpcd_tr_pattern = DPCD_TRAINING_PATTERN_3;
++ break;
++ default:
++ ASSERT(0);
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s: Invalid HW Training pattern: %d\n",
++ __func__, pattern);
++ break;
++ }
++
++ return dpcd_tr_pattern;
++
++}
++
++static void dpcd_set_lt_pattern_and_lane_settings(
++ struct core_link* link,
++ const struct link_training_settings *lt_settings,
++ enum hw_dp_training_pattern pattern)
++{
++ union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}};
++ const uint32_t dpcd_base_lt_offset =
++ DPCD_ADDRESS_TRAINING_PATTERN_SET;
++ uint8_t dpcd_lt_buffer[5] = {0};
++ union dpcd_training_pattern dpcd_pattern = {{0}};
++ uint32_t lane;
++ uint32_t size_in_bytes;
++ bool edp_workaround = false; /* TODO link_prop.INTERNAL */
++
++ /*****************************************************************
++ * DpcdAddress_TrainingPatternSet
++ *****************************************************************/
++ dpcd_pattern.bits.TRAINING_PATTERN_SET =
++ hw_training_pattern_to_dpcd_training_pattern(link, pattern);
++
++ dpcd_lt_buffer[DPCD_ADDRESS_TRAINING_PATTERN_SET - dpcd_base_lt_offset]
++ = dpcd_pattern.raw;
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s\n %x pattern = %x\n",
++ __func__,
++ DPCD_ADDRESS_TRAINING_PATTERN_SET,
++ dpcd_pattern.bits.TRAINING_PATTERN_SET);
++
++
++ /*****************************************************************
++ * DpcdAddress_Lane0Set -> DpcdAddress_Lane3Set
++ *****************************************************************/
++ for (lane = 0; lane <
++ (uint32_t)(lt_settings->link_settings.lane_count); lane++) {
++
++ dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
++ (uint8_t)(lt_settings->lane_settings[lane].VOLTAGE_SWING);
++ dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
++ (uint8_t)(lt_settings->lane_settings[lane].PRE_EMPHASIS);
++
++ dpcd_lane[lane].bits.MAX_SWING_REACHED =
++ (lt_settings->lane_settings[lane].VOLTAGE_SWING ==
++ VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
++ dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
++ (lt_settings->lane_settings[lane].PRE_EMPHASIS ==
++ PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
++ }
++
++ /* concatinate everything into one buffer*/
++
++ size_in_bytes = lt_settings->link_settings.lane_count * sizeof(dpcd_lane[0]);
++
++ // 0x00103 - 0x00102
++ dc_service_memmove(
++ &dpcd_lt_buffer[DPCD_ADDRESS_LANE0_SET - dpcd_base_lt_offset],
++ dpcd_lane,
++ size_in_bytes);
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s:\n %x VS set = %x PE set = %x \
++ max VS Reached = %x max PE Reached = %x\n",
++ __func__,
++ DPCD_ADDRESS_LANE0_SET,
++ dpcd_lane[0].bits.VOLTAGE_SWING_SET,
++ dpcd_lane[0].bits.PRE_EMPHASIS_SET,
++ dpcd_lane[0].bits.MAX_SWING_REACHED,
++ dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
++
++
++ if (edp_workaround) {
++ /* for eDP write in 2 parts because the 5-byte burst is
++ * causing issues on some eDP panels (EPR#366724)
++ */
++ core_link_write_dpcd(
++ link,
++ DPCD_ADDRESS_TRAINING_PATTERN_SET,
++ &dpcd_pattern.raw,
++ sizeof(dpcd_pattern.raw) );
++
++ core_link_write_dpcd(
++ link,
++ DPCD_ADDRESS_LANE0_SET,
++ (uint8_t *)(dpcd_lane),
++ size_in_bytes);
++
++ } else
++ /* write it all in (1 + number-of-lanes)-byte burst*/
++ core_link_write_dpcd(
++ link,
++ dpcd_base_lt_offset,
++ dpcd_lt_buffer,
++ size_in_bytes + sizeof(dpcd_pattern.raw) );
++
++ link->ln_setting = lt_settings->lane_settings[0];
++}
++
++static bool is_cr_done(enum lane_count ln_count,
++ union lane_status *dpcd_lane_status)
++{
++ bool done = true;
++ uint32_t lane;
++ /*LANEx_CR_DONE bits All 1's?*/
++ for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
++ if (!dpcd_lane_status[lane].bits.CR_DONE_0)
++ done = false;
++ }
++ return done;
++
++}
++
++static bool is_ch_eq_done(enum lane_count ln_count,
++ union lane_status *dpcd_lane_status,
++ union lane_align_status_updated *lane_status_updated)
++{
++ bool done = true;
++ uint32_t lane;
++ if (!lane_status_updated->bits.INTERLANE_ALIGN_DONE)
++ done = false;
++ else {
++ for (lane = 0; lane < (uint32_t)(ln_count); lane++) {
++ if (!dpcd_lane_status[lane].bits.SYMBOL_LOCKED_0 ||
++ !dpcd_lane_status[lane].bits.CHANNEL_EQ_DONE_0)
++ done = false;
++ }
++ }
++ return done;
++
++}
++
++static void update_drive_settings(
++ struct link_training_settings *dest,
++ struct link_training_settings src)
++{
++ uint32_t lane;
++ for (lane = 0; lane < src.link_settings.lane_count; lane++) {
++ dest->lane_settings[lane].VOLTAGE_SWING =
++ src.lane_settings[lane].VOLTAGE_SWING;
++ dest->lane_settings[lane].PRE_EMPHASIS =
++ src.lane_settings[lane].PRE_EMPHASIS;
++ dest->lane_settings[lane].POST_CURSOR2 =
++ src.lane_settings[lane].POST_CURSOR2;
++ }
++}
++
++static uint8_t get_nibble_at_index(const uint8_t *buf,
++ uint32_t index)
++{
++ uint8_t nibble;
++ nibble = buf[index / 2];
++
++ if (index % 2)
++ nibble >>= 4;
++ else
++ nibble &= 0x0F;
++
++ return nibble;
++}
++
++static enum pre_emphasis get_max_pre_emphasis_for_voltage_swing(
++ enum voltage_swing voltage)
++{
++ enum pre_emphasis pre_emphasis;
++ pre_emphasis = PRE_EMPHASIS_MAX_LEVEL;
++
++ if (voltage <= VOLTAGE_SWING_MAX_LEVEL)
++ pre_emphasis = voltage_swing_to_pre_emphasis[voltage];
++
++ return pre_emphasis;
++
++}
++
++static void find_max_drive_settings(
++ const struct link_training_settings *link_training_setting,
++ struct link_training_settings *max_lt_setting)
++{
++ uint32_t lane;
++ struct lane_settings max_requested;
++
++ max_requested.VOLTAGE_SWING =
++ link_training_setting->
++ lane_settings[0].VOLTAGE_SWING;
++ max_requested.PRE_EMPHASIS =
++ link_training_setting->
++ lane_settings[0].PRE_EMPHASIS;
++ /*max_requested.postCursor2 =
++ * link_training_setting->laneSettings[0].postCursor2;*/
++
++ /* Determine what the maximum of the requested settings are*/
++ for (lane = 1; lane < link_training_setting->link_settings.lane_count;
++ lane++) {
++ if (link_training_setting->lane_settings[lane].VOLTAGE_SWING >
++ max_requested.VOLTAGE_SWING)
++
++ max_requested.VOLTAGE_SWING =
++ link_training_setting->
++ lane_settings[lane].VOLTAGE_SWING;
++
++
++ if (link_training_setting->lane_settings[lane].PRE_EMPHASIS >
++ max_requested.PRE_EMPHASIS)
++ max_requested.PRE_EMPHASIS =
++ link_training_setting->
++ lane_settings[lane].PRE_EMPHASIS;
++
++ /*
++ if (link_training_setting->laneSettings[lane].postCursor2 >
++ max_requested.postCursor2)
++ {
++ max_requested.postCursor2 =
++ link_training_setting->laneSettings[lane].postCursor2;
++ }
++ */
++ }
++
++ /* make sure the requested settings are
++ * not higher than maximum settings*/
++ if (max_requested.VOLTAGE_SWING > VOLTAGE_SWING_MAX_LEVEL)
++ max_requested.VOLTAGE_SWING = VOLTAGE_SWING_MAX_LEVEL;
++
++ if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL)
++ max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL;
++ /*
++ if (max_requested.postCursor2 > PostCursor2_MaxLevel)
++ max_requested.postCursor2 = PostCursor2_MaxLevel;
++ */
++
++ /* make sure the pre-emphasis matches the voltage swing*/
++ if (max_requested.PRE_EMPHASIS >
++ get_max_pre_emphasis_for_voltage_swing(
++ max_requested.VOLTAGE_SWING))
++ max_requested.PRE_EMPHASIS =
++ get_max_pre_emphasis_for_voltage_swing(
++ max_requested.VOLTAGE_SWING);
++
++ /*
++ * Post Cursor2 levels are completely independent from
++ * pre-emphasis (Post Cursor1) levels. But Post Cursor2 levels
++ * can only be applied to each allowable combination of voltage
++ * swing and pre-emphasis levels */
++ /* if ( max_requested.postCursor2 >
++ * getMaxPostCursor2ForVoltageSwing(max_requested.voltageSwing))
++ * max_requested.postCursor2 =
++ * getMaxPostCursor2ForVoltageSwing(max_requested.voltageSwing);
++ */
++
++ max_lt_setting->link_settings.link_rate =
++ link_training_setting->link_settings.link_rate;
++ max_lt_setting->link_settings.lane_count =
++ link_training_setting->link_settings.lane_count;
++ max_lt_setting->link_settings.link_spread =
++ link_training_setting->link_settings.link_spread;
++
++ for (lane = 0; lane <
++ link_training_setting->link_settings.lane_count;
++ lane++) {
++ max_lt_setting->lane_settings[lane].VOLTAGE_SWING =
++ max_requested.VOLTAGE_SWING;
++ max_lt_setting->lane_settings[lane].PRE_EMPHASIS =
++ max_requested.PRE_EMPHASIS;
++ /*max_lt_setting->laneSettings[lane].postCursor2 =
++ * max_requested.postCursor2;
++ */
++ }
++
++}
++
++static void get_lane_status_and_drive_settings(
++ struct core_link* link,
++ const struct link_training_settings *link_training_setting,
++ union lane_status *ln_status,
++ union lane_align_status_updated *ln_status_updated,
++ struct link_training_settings *req_settings)
++{
++ uint8_t dpcd_buf[6] = {0};
++ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {{{0}}};
++ struct link_training_settings request_settings = {{0}};
++ uint32_t lane;
++
++ dc_service_memset(req_settings, '\0', sizeof(struct link_training_settings));
++
++ core_link_read_dpcd(
++ link,
++ DPCD_ADDRESS_LANE_01_STATUS,
++ (uint8_t *)(dpcd_buf),
++ sizeof(dpcd_buf));
++
++
++ for (lane = 0; lane <
++ (uint32_t)(link_training_setting->link_settings.lane_count);
++ lane++) {
++
++ ln_status[lane].raw =
++ get_nibble_at_index(&dpcd_buf[0], lane);
++ dpcd_lane_adjust[lane].raw =
++ get_nibble_at_index(&dpcd_buf[4], lane);
++ }
++
++ ln_status_updated->raw = dpcd_buf[2];
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s:\n%x Lane01Status = %x\n %x Lane23Status = %x\n ",
++ __func__,
++ DPCD_ADDRESS_LANE_01_STATUS, dpcd_buf[0],
++ DPCD_ADDRESS_LANE_23_STATUS, dpcd_buf[1]);
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s:\n %x Lane01AdjustRequest = %x\n %x Lane23AdjustRequest = %x\n",
++ __func__,
++ DPCD_ADDRESS_ADJUST_REQUEST_LANE0_1,
++ dpcd_buf[4],
++ DPCD_ADDRESS_ADJUST_REQUEST_LANE2_3,
++ dpcd_buf[5]);
++
++ /*copy to req_settings*/
++ request_settings.link_settings.lane_count =
++ link_training_setting->link_settings.lane_count;
++ request_settings.link_settings.link_rate =
++ link_training_setting->link_settings.link_rate;
++ request_settings.link_settings.link_spread =
++ link_training_setting->link_settings.link_spread;
++
++ for (lane = 0; lane <
++ (uint32_t)(link_training_setting->link_settings.lane_count);
++ lane++) {
++
++ request_settings.lane_settings[lane].VOLTAGE_SWING =
++ (enum voltage_swing)(dpcd_lane_adjust[lane].bits.
++ VOLTAGE_SWING_LANE);
++ request_settings.lane_settings[lane].PRE_EMPHASIS =
++ (enum pre_emphasis)(dpcd_lane_adjust[lane].bits.
++ PRE_EMPHASIS_LANE);
++ }
++
++ /*Note: for postcursor2, read adjusted
++ * postcursor2 settings from*/
++ /*DpcdAddress_AdjustRequestPostCursor2 =
++ *0x020C (not implemented yet)*/
++
++ /* we find the maximum of the requested settings across all lanes*/
++ /* and set this maximum for all lanes*/
++ find_max_drive_settings(&request_settings, req_settings);
++
++ /* if post cursor 2 is needed in the future,
++ * read DpcdAddress_AdjustRequestPostCursor2 = 0x020C
++ */
++
++}
++
++static void dpcd_set_lane_settings(
++ struct core_link* link,
++ const struct link_training_settings *link_training_setting)
++{
++ union dpcd_training_lane dpcd_lane[LANE_COUNT_DP_MAX] = {{{0}}};
++ uint32_t lane;
++
++ for (lane = 0; lane <
++ (uint32_t)(link_training_setting->
++ link_settings.lane_count);
++ lane++) {
++ dpcd_lane[lane].bits.VOLTAGE_SWING_SET =
++ (uint8_t)(link_training_setting->
++ lane_settings[lane].VOLTAGE_SWING);
++ dpcd_lane[lane].bits.PRE_EMPHASIS_SET =
++ (uint8_t)(link_training_setting->
++ lane_settings[lane].PRE_EMPHASIS);
++ dpcd_lane[lane].bits.MAX_SWING_REACHED =
++ (link_training_setting->
++ lane_settings[lane].VOLTAGE_SWING ==
++ VOLTAGE_SWING_MAX_LEVEL ? 1 : 0);
++ dpcd_lane[lane].bits.MAX_PRE_EMPHASIS_REACHED =
++ (link_training_setting->
++ lane_settings[lane].PRE_EMPHASIS ==
++ PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
++ }
++
++ core_link_write_dpcd(link,
++ DPCD_ADDRESS_LANE0_SET,
++ (uint8_t *)(dpcd_lane),
++ link_training_setting->link_settings.lane_count);
++
++ /*
++ if (LTSettings.link.rate == LinkRate_High2)
++ {
++ DpcdTrainingLaneSet2 dpcd_lane2[lane_count_DPMax] = {0};
++ for ( uint32_t lane = 0;
++ lane < lane_count_DPMax; lane++)
++ {
++ dpcd_lane2[lane].bits.post_cursor2_set =
++ static_cast<unsigned char>(
++ LTSettings.laneSettings[lane].postCursor2);
++ dpcd_lane2[lane].bits.max_post_cursor2_reached = 0;
++ }
++ m_pDpcdAccessSrv->WriteDpcdData(
++ DpcdAddress_Lane0Set2,
++ reinterpret_cast<unsigned char*>(dpcd_lane2),
++ LTSettings.link.lanes);
++ }
++ */
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ "%s\n %x VS set = %x PE set = %x \
++ max VS Reached = %x max PE Reached = %x\n",
++ __func__,
++ DPCD_ADDRESS_LANE0_SET,
++ dpcd_lane[0].bits.VOLTAGE_SWING_SET,
++ dpcd_lane[0].bits.PRE_EMPHASIS_SET,
++ dpcd_lane[0].bits.MAX_SWING_REACHED,
++ dpcd_lane[0].bits.MAX_PRE_EMPHASIS_REACHED);
++
++ link->ln_setting = link_training_setting->lane_settings[0];
++
++}
++
++static bool is_max_vs_reached(
++ const struct link_training_settings *lt_settings)
++{
++ uint32_t lane;
++ for (lane = 0; lane <
++ (uint32_t)(lt_settings->link_settings.lane_count);
++ lane++) {
++ if (lt_settings->lane_settings[lane].VOLTAGE_SWING
++ == VOLTAGE_SWING_MAX_LEVEL)
++ return true;
++ }
++ return false;
++
++}
++
++void set_drive_settings(
++ struct core_link *link,
++ struct link_training_settings *lt_settings)
++{
++ /* program ASIC PHY settings*/
++ dp_set_hw_lane_settings(link, lt_settings);
++
++ /* Notify DP sink the PHY settings from source */
++ dpcd_set_lane_settings(link, lt_settings);
++}
++
++static bool perform_post_lt_adj_req_sequence(
++ struct core_link *link,
++ struct link_training_settings *lt_settings)
++{
++ enum lane_count lane_count =
++ lt_settings->link_settings.lane_count;
++
++ uint32_t adj_req_count;
++ uint32_t adj_req_timer;
++ bool req_drv_setting_changed;
++ uint32_t lane;
++
++ req_drv_setting_changed = false;
++ for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
++ adj_req_count++) {
++
++ req_drv_setting_changed = false;
++
++ for (adj_req_timer = 0;
++ adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
++ adj_req_timer++) {
++
++ struct link_training_settings req_settings;
++ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
++ union lane_align_status_updated
++ dpcd_lane_status_updated;
++
++ get_lane_status_and_drive_settings(
++ link,
++ lt_settings,
++ dpcd_lane_status,
++ &dpcd_lane_status_updated,
++ &req_settings);
++
++ if (dpcd_lane_status_updated.bits.
++ POST_LT_ADJ_REQ_IN_PROGRESS == 0)
++ return true;
++
++ if (!is_cr_done(lane_count, dpcd_lane_status))
++ return false;
++
++ if (!is_ch_eq_done(
++ lane_count,
++ dpcd_lane_status,
++ &dpcd_lane_status_updated))
++ return false;
++
++ for (lane = 0; lane < (uint32_t)(lane_count); lane++) {
++
++ if (lt_settings->
++ lane_settings[lane].VOLTAGE_SWING !=
++ req_settings.lane_settings[lane].
++ VOLTAGE_SWING ||
++ lt_settings->lane_settings[lane].PRE_EMPHASIS !=
++ req_settings.lane_settings[lane].PRE_EMPHASIS) {
++
++ req_drv_setting_changed = true;
++ break;
++ }
++ }
++
++ if (req_drv_setting_changed) {
++ update_drive_settings(
++ lt_settings,req_settings);
++
++ set_drive_settings(link, lt_settings);
++ break;
++ }
++
++ dc_service_sleep_in_milliseconds(link->ctx, 1);
++ }
++
++ if (!req_drv_setting_changed) {
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_LINK_SERVICE,
++ "%s: Post Link Training Adjust Request Timed out\n",
++ __func__);
++
++ ASSERT(0);
++ return true;
++ }
++ }
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_LINK_SERVICE,
++ "%s: Post Link Training Adjust Request limit reached\n",
++ __func__);
++
++ ASSERT(0);
++ return true;
++
++}
++
++static bool perform_channel_equalization_sequence(
++ struct core_link *link,
++ struct link_training_settings *lt_settings)
++{
++ struct link_training_settings req_settings;
++ enum hw_dp_training_pattern hw_tr_pattern;
++ uint32_t retries_ch_eq;
++ enum lane_count lane_count = lt_settings->link_settings.lane_count;
++ union lane_align_status_updated dpcd_lane_status_updated = {{0}};
++ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {{{0}}};;
++
++ /*TODO hw_tr_pattern = HW_DP_TRAINING_PATTERN_3;*/
++ hw_tr_pattern = HW_DP_TRAINING_PATTERN_2;
++
++ dp_set_hw_training_pattern(link, hw_tr_pattern);
++
++ for (retries_ch_eq = 0; retries_ch_eq <= LINK_TRAINING_MAX_RETRY_COUNT;
++ retries_ch_eq++) {
++
++ dp_set_hw_lane_settings(link, lt_settings);
++
++ /* 2. update DPCD*/
++ if (!retries_ch_eq)
++ /* EPR #361076 - write as a 5-byte burst,
++ * but only for the 1-st iteration*/
++ dpcd_set_lt_pattern_and_lane_settings(
++ link,
++ lt_settings,
++ hw_tr_pattern);
++ else
++ dpcd_set_lane_settings(link, lt_settings);
++
++ /* 3. wait for receiver to lock-on*/
++ wait_for_training_aux_rd_interval(link, 400);
++
++ /* 4. Read lane status and requested
++ * drive settings as set by the sink*/
++
++ get_lane_status_and_drive_settings(
++ link,
++ lt_settings,
++ dpcd_lane_status,
++ &dpcd_lane_status_updated,
++ &req_settings);
++
++ /* 5. check CR done*/
++ if (!is_cr_done(lane_count, dpcd_lane_status))
++ return false;
++
++ /* 6. check CHEQ done*/
++ if (is_ch_eq_done(lane_count,
++ dpcd_lane_status,
++ &dpcd_lane_status_updated))
++ return true;
++
++ /* 7. update VS/PE/PC2 in lt_settings*/
++ update_drive_settings(lt_settings, req_settings);
++ }
++
++ return false;
++
++}
++
++static bool perform_clock_recovery_sequence(
++ struct core_link *link,
++ struct link_training_settings *lt_settings)
++{
++ uint32_t retries_cr;
++ uint32_t retry_count;
++ uint32_t lane;
++ struct link_training_settings req_settings;
++ enum lane_count lane_count =
++ lt_settings->link_settings.lane_count;
++ enum hw_dp_training_pattern hw_tr_pattern = HW_DP_TRAINING_PATTERN_1;
++ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
++ union lane_align_status_updated dpcd_lane_status_updated;
++
++ retries_cr = 0;
++ retry_count = 0;
++ /* initial drive setting (VS/PE/PC2)*/
++ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
++ lt_settings->lane_settings[lane].VOLTAGE_SWING =
++ VOLTAGE_SWING_LEVEL0;
++ lt_settings->lane_settings[lane].PRE_EMPHASIS =
++ PRE_EMPHASIS_DISABLED;
++ lt_settings->lane_settings[lane].POST_CURSOR2 =
++ POST_CURSOR2_DISABLED;
++ }
++
++ dp_set_hw_training_pattern(link, hw_tr_pattern);
++
++ /* najeeb - The synaptics MST hub can put the LT in
++ * infinite loop by switching the VS
++ */
++ /* between level 0 and level 1 continuously, here
++ * we try for CR lock for LinkTrainingMaxCRRetry count*/
++ while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
++ (retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
++
++ dc_service_memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
++ dc_service_memset(&dpcd_lane_status_updated, '\0',
++ sizeof(dpcd_lane_status_updated));
++
++ /* 1. call HWSS to set lane settings*/
++ dp_set_hw_lane_settings(
++ link,
++ lt_settings);
++
++ /* 2. update DPCD of the receiver*/
++ if (!retries_cr)
++ /* EPR #361076 - write as a 5-byte burst,
++ * but only for the 1-st iteration.*/
++ dpcd_set_lt_pattern_and_lane_settings(
++ link,
++ lt_settings,
++ hw_tr_pattern);
++ else
++ dpcd_set_lane_settings(
++ link,
++ lt_settings);
++
++
++ /* 3. wait receiver to lock-on*/
++ wait_for_training_aux_rd_interval(
++ link,
++ 100);
++
++ /* 4. Read lane status and requested drive
++ * settings as set by the sink
++ */
++ get_lane_status_and_drive_settings(
++ link,
++ lt_settings,
++ dpcd_lane_status,
++ &dpcd_lane_status_updated,
++ &req_settings);
++
++
++ /* 5. check CR done*/
++ if (is_cr_done(lane_count, dpcd_lane_status))
++ return true;
++
++ /* 6. max VS reached*/
++ if (is_max_vs_reached(lt_settings))
++ return false;
++
++ /* 7. same voltage*/
++ /* Note: VS same for all lanes,
++ * so comparing first lane is sufficient*/
++ if (lt_settings->lane_settings[0].VOLTAGE_SWING ==
++ req_settings.lane_settings[0].VOLTAGE_SWING)
++ retries_cr++;
++ else
++ retries_cr = 0;
++
++
++ /* 8. update VS/PE/PC2 in lt_settings*/
++ update_drive_settings(lt_settings, req_settings);
++
++ retry_count++;
++ }
++
++ if (retry_count >= LINK_TRAINING_MAX_CR_RETRY) {
++ ASSERT(0);
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_LINK_SERVICE,
++ "%s: Link Training Error, could not \
++ get CR after %d tries. \
++ Possibly voltage swing issue", __func__,
++ LINK_TRAINING_MAX_CR_RETRY);
++
++ }
++
++ return false;
++}
++
++ bool perform_link_training(
++ struct core_link *link,
++ const struct link_settings *link_setting,
++ bool skip_video_pattern)
++{
++ bool status;
++ union dpcd_training_pattern dpcd_pattern = {{0}};
++ union lane_count_set lane_count_set = {{0}};
++ const int8_t *link_rate = "Unknown";
++ struct link_training_settings lt_settings;
++
++ status = false;
++ dc_service_memset(&lt_settings, '\0', sizeof(lt_settings));
++
++ lt_settings.link_settings.link_rate = link_setting->link_rate;
++ lt_settings.link_settings.lane_count = link_setting->lane_count;
++
++ /*@todo[vdevulap] move SS to LS, should not be handled by displaypath*/
++
++ /* TODO hard coded to SS for now
++ * lt_settings.link_settings.link_spread =
++ * dal_display_path_is_ss_supported(
++ * path_mode->display_path) ?
++ * LINK_SPREAD_05_DOWNSPREAD_30KHZ :
++ * LINK_SPREAD_DISABLED;
++ */
++ lt_settings.link_settings.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
++
++ /* 1. set link rate, lane count and spread*/
++ dpcd_set_link_settings(link, &lt_settings);
++
++ /* 2. perform link training (set link training done
++ * to false is done as well)*/
++ if (perform_clock_recovery_sequence(link, &lt_settings)) {
++
++ if (perform_channel_equalization_sequence(link, &lt_settings))
++ status = true;
++ }
++
++ if (status || !skip_video_pattern) {
++
++ /* 3. set training not in progress*/
++ dpcd_pattern.bits.TRAINING_PATTERN_SET =
++ DPCD_TRAINING_PATTERN_VIDEOIDLE;
++ dpcd_set_training_pattern(link, dpcd_pattern);
++
++ /* 4. mainlink output idle pattern*/
++ dp_set_hw_test_pattern(link, DP_TEST_PATTERN_VIDEO_MODE);
++
++ /* 5. post training adjust if required*/
++ if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED
++ == 1) {
++ if (status == true) {
++ if (perform_post_lt_adj_req_sequence(
++ link, &lt_settings) == false)
++ status = false;
++ }
++
++ lane_count_set.bits.LANE_COUNT_SET =
++ lt_settings.link_settings.lane_count;
++ lane_count_set.bits.ENHANCED_FRAMING = 1;
++ lane_count_set.bits.POST_LT_ADJ_REQ_GRANTED = 0;
++
++ core_link_write_dpcd(
++ link,
++ DPCD_ADDRESS_LANE_COUNT_SET,
++ &lane_count_set.raw,
++ sizeof(lane_count_set));
++ }
++ }
++
++ /* 6. print status message*/
++ switch (lt_settings.link_settings.link_rate) {
++
++ case LINK_RATE_LOW:
++ link_rate = "Low";
++ break;
++ case LINK_RATE_HIGH:
++ link_rate = "High";
++ break;
++ case LINK_RATE_HIGH2:
++ link_rate = "High2";
++ break;
++ case LINK_RATE_RBR2:
++ link_rate = "RBR2";
++ break;
++ default:
++ break;
++ }
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_MST,
++ LOG_MINOR_MST_PROGRAMMING,
++ "Link training for %d lanes at %s rate %s\n",
++ lt_settings.link_settings.lane_count,
++ link_rate,
++ status ? "succeeded" : "failed");
++
++ return status;
++}
++
++/*TODO add more check to see if link support request link configuration */
++static bool is_link_setting_supported(
++ const struct link_settings *link_setting,
++ const struct link_settings *max_link_setting)
++{
++ if (link_setting->lane_count > max_link_setting->lane_count ||
++ link_setting->link_rate > max_link_setting->link_rate)
++ return false;
++ return true;
++}
++
++static const uint32_t get_link_training_fallback_table_len(
++ struct core_link *link)
++{
++ return ARRAY_SIZE(link_training_fallback_table);
++}
++
++static const struct link_settings *get_link_training_fallback_table(
++ struct core_link *link, uint32_t i)
++{
++ return &link_training_fallback_table[i];
++}
++
++static bool exceeded_limit_link_setting(const struct link_settings *link_setting,
++ const struct link_settings *limit_link_setting)
++{
++ return (link_setting->lane_count * link_setting->link_rate
++ > limit_link_setting->lane_count * limit_link_setting->link_rate ?
++ true : false);
++}
++
++
++bool dp_hbr_verify_link_cap(
++ struct core_link *link,
++ struct link_settings *known_limit_link_setting)
++{
++ struct link_settings max_link_cap = {0};
++ bool success;
++ bool skip_link_training;
++ const struct link_settings *cur;
++ bool skip_video_pattern;
++ uint32_t i;
++
++ success = false;
++ skip_link_training = false;
++
++ /* TODO confirm this is correct for cz */
++ max_link_cap.lane_count = LANE_COUNT_FOUR;
++ max_link_cap.link_rate = LINK_RATE_HIGH2;
++ max_link_cap.link_spread = LINK_SPREAD_05_DOWNSPREAD_30KHZ;
++
++ /* TODO implement override and monitor patch later */
++
++ /* try to train the link from high to low to
++ * find the physical link capability
++ */
++ /* disable PHY done possible by BIOS, will be done by driver itself */
++ dp_disable_link_phy(link, link->public.connector_signal);
++
++ for (i = 0; i < get_link_training_fallback_table_len(link) &&
++ !success; i++) {
++ cur = get_link_training_fallback_table(link, i);
++
++ if (known_limit_link_setting->lane_count != LANE_COUNT_UNKNOWN &&
++ exceeded_limit_link_setting(cur,
++ known_limit_link_setting))
++ continue;
++
++ if (!is_link_setting_supported(cur, &max_link_cap))
++ continue;
++
++ skip_video_pattern = true;
++ if (cur->link_rate == LINK_RATE_LOW)
++ skip_video_pattern = false;
++ if (dp_enable_link_phy(
++ link,
++ link->public.connector_signal,
++ ENGINE_ID_UNKNOWN,
++ cur)) {
++ if (skip_link_training)
++ success = true;
++ else {
++ uint8_t num_retries = 3;
++ uint8_t j;
++ uint8_t delay_between_retries = 10;
++ for (j = 0; j < num_retries; ++j) {
++ success = perform_link_training(
++ link,
++ cur,
++ skip_video_pattern);
++
++ if (success)
++ break;
++
++ dc_service_sleep_in_milliseconds(
++ link->ctx,
++ delay_between_retries);
++
++ delay_between_retries += 10;
++ }
++ }
++ }
++
++ if (success)
++ link->verified_link_cap = *cur;
++
++ /* always disable the link before trying another
++ * setting or before returning we'll enable it later
++ * based on the actual mode we're driving
++ */
++ dp_disable_link_phy(link, link->public.connector_signal);
++ }
++
++ /* Link Training failed for all Link Settings
++ * (Lane Count is still unknown)
++ */
++ if (!success) {
++ /* If all LT fails for all settings,
++ * set verified = failed safe (1 lane low)
++ */
++ link->verified_link_cap.lane_count = LANE_COUNT_ONE;
++ link->verified_link_cap.link_rate = LINK_RATE_LOW;
++
++ link->verified_link_cap.link_spread =
++ LINK_SPREAD_DISABLED;
++ }
++
++ link->max_link_setting = link->verified_link_cap;
++
++ return success;
++}
++
++static uint32_t bandwidth_in_kbps_from_timing(
++ const struct dc_crtc_timing *timing)
++{
++ uint32_t bits_per_channel = 0;
++ uint32_t kbps;
++ switch (timing->display_color_depth) {
++
++ case COLOR_DEPTH_666:
++ bits_per_channel = 6;
++ break;
++ case COLOR_DEPTH_888:
++ bits_per_channel = 8;
++ break;
++ case COLOR_DEPTH_101010:
++ bits_per_channel = 10;
++ break;
++ case COLOR_DEPTH_121212:
++ bits_per_channel = 12;
++ break;
++ case COLOR_DEPTH_141414:
++ bits_per_channel = 14;
++ break;
++ case COLOR_DEPTH_161616:
++ bits_per_channel = 16;
++ break;
++ default:
++ break;
++ }
++ ASSERT(bits_per_channel != 0);
++
++ kbps = timing->pix_clk_khz;
++ kbps *= bits_per_channel;
++
++ if (timing->flags.Y_ONLY != 1)
++ /*Only YOnly make reduce bandwidth by 1/3 compares to RGB*/
++ kbps *= 3;
++
++ return kbps;
++
++}
++
++static uint32_t bandwidth_in_kbps_from_link_settings(
++ const struct link_settings *link_setting)
++{
++ uint32_t link_rate_in_kbps = link_setting->link_rate *
++ LINK_RATE_REF_FREQ_IN_KHZ;
++
++ uint32_t lane_count = link_setting->lane_count;
++ uint32_t kbps = link_rate_in_kbps;
++ kbps *= lane_count;
++ kbps *= 8; /* 8 bits per byte*/
++
++ return kbps;
++
++}
++
++bool dp_validate_mode_timing(
++ struct core_link *link,
++ const struct dc_crtc_timing *timing)
++{
++ uint32_t req_bw;
++ uint32_t max_bw;
++
++ const struct link_settings *link_setting;
++
++ /*always DP fail safe mode*/
++ if (timing->pix_clk_khz == (uint32_t)25175 &&
++ timing->h_addressable == (uint32_t)640 &&
++ timing->v_addressable == (uint32_t)480)
++ return true;
++
++ /* For static validation we always use reported
++ * link settings for other cases, when no modelist
++ * changed we can use verified link setting*/
++ link_setting = &link->reported_link_cap;
++
++ /* TODO: DYNAMIC_VALIDATION needs to be implemented */
++ /*if (flags.DYNAMIC_VALIDATION == 1 &&
++ link->verified_link_cap.lane_count != LANE_COUNT_UNKNOWN)
++ link_setting = &link->verified_link_cap;
++ */
++
++ req_bw = bandwidth_in_kbps_from_timing(timing);
++ max_bw = bandwidth_in_kbps_from_link_settings(link_setting);
++
++ if (req_bw < max_bw) {
++ /* remember the biggest mode here, during
++ * initial link training (to get
++ * verified_link_cap), LS sends event about
++ * cannot train at reported cap to upper
++ * layer and upper layer will re-enumerate modes.
++ * this is not necessary if the lower
++ * verified_link_cap is enough to drive
++ * all the modes */
++
++ /* TODO: DYNAMIC_VALIDATION needs to be implemented */
++ /* if (flags.DYNAMIC_VALIDATION == 1)
++ dpsst->max_req_bw_for_verified_linkcap = dal_max(
++ dpsst->max_req_bw_for_verified_linkcap, req_bw); */
++ return true;
++ } else
++ return false;
++}
++
++void decide_link_settings(struct core_stream *stream,
++ struct link_settings *link_setting)
++{
++
++ const struct link_settings *cur_ls;
++ struct core_link* link;
++ uint32_t req_bw;
++ uint32_t link_bw;
++ uint32_t i;
++
++ req_bw = bandwidth_in_kbps_from_timing(
++ &stream->public.timing);
++
++ /* if preferred is specified through AMDDP, use it, if it's enough
++ * to drive the mode
++ */
++ link = stream->sink->link;
++
++ if ((link->reported_link_cap.lane_count != LANE_COUNT_UNKNOWN) &&
++ (link->reported_link_cap.link_rate <=
++ link->verified_link_cap.link_rate)) {
++
++ link_bw = bandwidth_in_kbps_from_link_settings(
++ &link->reported_link_cap);
++
++ if (req_bw < link_bw) {
++ *link_setting = link->reported_link_cap;
++ return;
++ }
++ }
++
++ /* search for first suitable setting for the requested
++ * bandwidth
++ */
++ for (i = 0; i < get_link_training_fallback_table_len(link); i++) {
++
++ cur_ls = get_link_training_fallback_table(link, i);
++
++ link_bw =
++ bandwidth_in_kbps_from_link_settings(
++ cur_ls);
++
++ if (req_bw < link_bw) {
++ if (is_link_setting_supported(
++ cur_ls,
++ &link->max_link_setting)) {
++ *link_setting = *cur_ls;
++ return;
++ }
++ }
++ }
++
++ BREAK_TO_DEBUGGER();
++ ASSERT(link->verified_link_cap.lane_count !=
++ LANE_COUNT_UNKNOWN);
++
++ *link_setting = link->verified_link_cap;
++}
++
++/*************************Short Pulse IRQ***************************/
++
++static bool hpd_rx_irq_check_link_loss_status(
++ struct core_link *link,
++ union hpd_irq_data *hpd_irq_dpcd_data)
++{
++ uint8_t irq_reg_rx_power_state;
++ enum dc_status dpcd_result = DC_ERROR_UNEXPECTED;
++ union lane_status lane_status;
++ uint32_t lane;
++ bool sink_status_changed;
++ bool return_code;
++
++ sink_status_changed = false;
++ return_code = false;
++
++ if (link->cur_link_settings.lane_count == 0)
++ return return_code;
++ /*1. Check that we can handle interrupt: Not in FS DOS,
++ * Not in "Display Timeout" state, Link is trained.
++ */
++
++ dpcd_result = core_link_read_dpcd(link,
++ DPCD_ADDRESS_POWER_STATE,
++ &irq_reg_rx_power_state,
++ sizeof(irq_reg_rx_power_state));
++
++ if (dpcd_result != DC_OK) {
++ irq_reg_rx_power_state = DP_PWR_STATE_D0;
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_HPD_IRQ,
++ "%s: DPCD read failed to obtain power state.\n",
++ __func__);
++ }
++
++ if (irq_reg_rx_power_state == DP_PWR_STATE_D0) {
++
++ /*2. Check that Link Status changed, before re-training.*/
++
++ /*parse lane status*/
++ for (lane = 0; lane <
++ (uint32_t)(link->cur_link_settings.lane_count) &&
++ !sink_status_changed; lane++) {
++
++ /* check status of lanes 0,1
++ * changed DpcdAddress_Lane01Status (0x202)*/
++ lane_status.raw = get_nibble_at_index(
++ &hpd_irq_dpcd_data->bytes.lane01_status.raw,
++ lane);
++
++ if (!lane_status.bits.CHANNEL_EQ_DONE_0 ||
++ !lane_status.bits.CR_DONE_0 ||
++ !lane_status.bits.SYMBOL_LOCKED_0) {
++ /* if one of the channel equalization, clock
++ * recovery or symbol lock is dropped
++ * consider it as (link has been
++ * dropped) dp sink status has changed*/
++ sink_status_changed = true;
++ break;
++ }
++
++ }
++
++ /* Check interlane align.*/
++ if (sink_status_changed ||
++ !hpd_irq_dpcd_data->bytes.lane_status_updated.bits.
++ INTERLANE_ALIGN_DONE) {
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_HPD_IRQ,
++ "%s: Link Status changed.\n",
++ __func__);
++
++ return_code = true;
++ }
++ }
++
++ return return_code;
++}
++
++static enum dc_status read_hpd_rx_irq_data(
++ struct core_link *link,
++ union hpd_irq_data *irq_data)
++{
++ /* The HW reads 16 bytes from 200h on HPD,
++ * but if we get an AUX_DEFER, the HW cannot retry
++ * and this causes the CTS tests 4.3.2.1 - 3.2.4 to
++ * fail, so we now explicitly read 6 bytes which is
++ * the req from the above mentioned test cases.
++ */
++ return core_link_read_dpcd(
++ link,
++ DPCD_ADDRESS_SINK_COUNT,
++ irq_data->raw,
++ sizeof(union hpd_irq_data));
++}
++
++bool dc_link_handle_hpd_rx_irq(const struct dc_link *dc_link)
++{
++ struct core_link *link = DC_LINK_TO_LINK(dc_link);
++ union hpd_irq_data hpd_irq_dpcd_data = {{{{0}}}};
++ enum dc_status result = DDC_RESULT_UNKNOWN;
++ bool status = false;
++ /* For use cases related to down stream connection status change,
++ * PSR and device auto test, refer to function handle_sst_hpd_irq
++ * in DAL2.1*/
++
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_HPD_IRQ,
++ "%s: Got short pulse HPD on connector %d\n",
++ __func__, link->connector_index);
++
++ /* All the "handle_hpd_irq_xxx()" methods
++ * should be called only after
++ * dal_dpsst_ls_read_hpd_irq_data
++ * Order of calls is important too
++ */
++ result = read_hpd_rx_irq_data(link, &hpd_irq_dpcd_data);
++
++ if (result != DC_OK) {
++ dal_logger_write(link->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_HPD_IRQ,
++ "%s: DPCD read failed to obtain irq data\n",
++ __func__);
++ return false;
++ }
++
++ /* check if we have MST msg and return since we poll for it */
++ if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY ||
++ hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY)
++ return false;
++
++
++ /* For now we only handle 'Downstream port status' case. */
++ /* If we got sink count changed it means Downstream port status changed,
++ * then DM should call DC to do the detection. */
++ if (hpd_rx_irq_check_link_loss_status(
++ link,
++ &hpd_irq_dpcd_data)) {
++ perform_link_training(link, &link->cur_link_settings, true);
++ status = false;
++ }
++
++ if (hpd_irq_dpcd_data.bytes.sink_cnt.bits.SINK_COUNT
++ != link->dpcd_sink_count)
++ status = true;
++
++ /* reasons for HPD RX:
++ * 1. Link Loss - ie Re-train the Link
++ * 2. MST sideband message
++ * 3. Automated Test - ie. Internal Commit
++ * 4. CP (copy protection) - (not interesting for DM???)
++ * 5. DRR
++ * 6. Downstream Port status changed -ie. Detect - this the only one
++ * which is interesting for DM because it must call dc_link_detect.
++ */
++ return status;
++}
++
++/*query dpcd for version and mst cap addresses*/
++bool is_mst_supported(struct core_link *link)
++{
++ bool mst = false;
++ enum dc_status st = DC_OK;
++ union dpcd_rev rev;
++ union mstm_cap cap;
++
++ rev.raw = 0;
++ cap.raw = 0;
++
++ st = core_link_read_dpcd(link, DPCD_ADDRESS_DPCD_REV, &rev.raw,
++ sizeof(rev));
++
++ if (st == DC_OK && rev.raw >= DPCD_REV_12) {
++
++ st = core_link_read_dpcd(link, DPCD_ADDRESS_MSTM_CAP,
++ &cap.raw, sizeof(cap));
++ if (st == DC_OK && cap.bits.MST_CAP == 1)
++ mst = true;
++ }
++ return mst;
++
++}
++
++static void get_active_converter_info(
++ uint8_t data, struct core_link *link)
++{
++ union dp_downstream_port_present ds_port = { .byte = data };
++
++ /* decode converter info*/
++ if (!ds_port.fields.PORT_PRESENT) {
++ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
++ ddc_service_set_dongle_type(link->ddc,
++ link->dpcd_caps.dongle_type);
++ return;
++ }
++
++ switch (ds_port.fields.PORT_TYPE) {
++ case DOWNSTREAM_VGA:
++ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_VGA_CONVERTER;
++ break;
++ case DOWNSTREAM_DVI_HDMI:
++ /* At this point we don't know is it DVI or HDMI,
++ * assume DVI.*/
++ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_DP_DVI_CONVERTER;
++ break;
++ default:
++ link->dpcd_caps.dongle_type = DISPLAY_DONGLE_NONE;
++ break;
++ }
++
++ if (link->dpcd_caps.dpcd_rev.raw >= DCS_DPCD_REV_11) {
++ uint8_t det_caps[4];
++ union dwnstream_port_caps_byte0 *port_caps =
++ (union dwnstream_port_caps_byte0 *)det_caps;
++ core_link_read_dpcd(link, DPCD_ADDRESS_DWN_STRM_PORT0_CAPS,
++ det_caps, sizeof(det_caps));
++
++ switch (port_caps->bits.DWN_STRM_PORTX_TYPE) {
++ case DOWN_STREAM_DETAILED_VGA:
++ link->dpcd_caps.dongle_type =
++ DISPLAY_DONGLE_DP_VGA_CONVERTER;
++ break;
++ case DOWN_STREAM_DETAILED_DVI:
++ link->dpcd_caps.dongle_type =
++ DISPLAY_DONGLE_DP_DVI_CONVERTER;
++ break;
++ case DOWN_STREAM_DETAILED_HDMI:
++ link->dpcd_caps.dongle_type =
++ DISPLAY_DONGLE_DP_HDMI_CONVERTER;
++
++ if (ds_port.fields.DETAILED_CAPS) {
++
++ union dwnstream_port_caps_byte3_hdmi
++ hdmi_caps = {.raw = det_caps[3] };
++
++ link->dpcd_caps.is_dp_hdmi_s3d_converter =
++ hdmi_caps.bits.FRAME_SEQ_TO_FRAME_PACK;
++ }
++ break;
++ }
++ }
++ ddc_service_set_dongle_type(link->ddc,
++ link->dpcd_caps.dongle_type);
++}
++
++static void dp_wa_power_up_0010FA(struct core_link *link, uint8_t *dpcd_data,
++ int length)
++{
++ int retry = 0;
++ struct dp_device_vendor_id dp_id;
++ union dp_downstream_port_present ds_port = { 0 };
++
++ if (!link->dpcd_caps.dpcd_rev.raw) {
++ do {
++ dp_receiver_power_ctrl(link, true);
++ core_link_read_dpcd(link, DPCD_ADDRESS_DPCD_REV,
++ dpcd_data, length);
++ link->dpcd_caps.dpcd_rev.raw = dpcd_data[
++ DPCD_ADDRESS_DPCD_REV -
++ DPCD_ADDRESS_DPCD_REV];
++ } while (retry++ < 4 && !link->dpcd_caps.dpcd_rev.raw);
++ }
++
++ ds_port.byte = dpcd_data[DPCD_ADDRESS_DOWNSTREAM_PORT_PRESENT -
++ DPCD_ADDRESS_DPCD_REV];
++
++ get_active_converter_info(ds_port.byte, link);
++
++ /* read IEEE branch device id */
++ core_link_read_dpcd(link, DPCD_ADDRESS_BRANCH_DEVICE_ID_START,
++ (uint8_t *)&dp_id, sizeof(dp_id));
++ link->dpcd_caps.branch_dev_id =
++ (dp_id.ieee_oui[0] << 16) +
++ (dp_id.ieee_oui[1] << 8) +
++ dp_id.ieee_oui[2];
++
++ if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER) {
++ switch (link->dpcd_caps.branch_dev_id) {
++ /* Some active dongles (DP-VGA, DP-DLDVI converters) power down
++ * all internal circuits including AUX communication preventing
++ * reading DPCD table and EDID (spec violation).
++ * Encoder will skip DP RX power down on disable_output to
++ * keep receiver powered all the time.*/
++ case DP_BRANCH_DEVICE_ID_1:
++ case DP_BRANCH_DEVICE_ID_4:
++ link->dp_wa.bits.KEEP_RECEIVER_POWERED = 1;
++ break;
++
++ /* TODO: May need work around for other dongles. */
++ default:
++ link->dp_wa.bits.KEEP_RECEIVER_POWERED = 0;
++ break;
++ }
++ } else
++ link->dp_wa.bits.KEEP_RECEIVER_POWERED = 0;
++}
++
++static void retrieve_link_cap(struct core_link *link)
++{
++ uint8_t dpcd_data[
++ DPCD_ADDRESS_EDP_CONFIG_CAP -
++ DPCD_ADDRESS_DPCD_REV + 1];
++
++ union down_stream_port_count down_strm_port_count;
++ union edp_configuration_cap edp_config_cap;
++ union max_down_spread max_down_spread;
++ union dp_downstream_port_present ds_port = { 0 };
++
++ dc_service_memset(dpcd_data, '\0', sizeof(dpcd_data));
++ dc_service_memset(&down_strm_port_count,
++ '\0', sizeof(union down_stream_port_count));
++ dc_service_memset(&edp_config_cap, '\0',
++ sizeof(union edp_configuration_cap));
++ dc_service_memset(&max_down_spread, '\0',
++ sizeof(union max_down_spread));
++
++ core_link_read_dpcd(link, DPCD_ADDRESS_DPCD_REV,
++ dpcd_data, sizeof(dpcd_data));
++ link->dpcd_caps.dpcd_rev.raw = dpcd_data[
++ DPCD_ADDRESS_DPCD_REV -
++ DPCD_ADDRESS_DPCD_REV];
++
++ ds_port.byte = dpcd_data[DPCD_ADDRESS_DOWNSTREAM_PORT_PRESENT -
++ DPCD_ADDRESS_DPCD_REV];
++
++ get_active_converter_info(ds_port.byte, link);
++
++ dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data));
++
++ link->dpcd_caps.allow_invalid_MSA_timing_param =
++ down_strm_port_count.bits.IGNORE_MSA_TIMING_PARAM;
++
++ link->dpcd_caps.max_ln_count.raw = dpcd_data[
++ DPCD_ADDRESS_MAX_LANE_COUNT - DPCD_ADDRESS_DPCD_REV];
++
++ max_down_spread.raw = dpcd_data[
++ DPCD_ADDRESS_MAX_DOWNSPREAD - DPCD_ADDRESS_DPCD_REV];
++
++ link->reported_link_cap.lane_count =
++ link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
++ link->reported_link_cap.link_rate = dpcd_data[
++ DPCD_ADDRESS_MAX_LINK_RATE - DPCD_ADDRESS_DPCD_REV];
++ link->reported_link_cap.link_spread =
++ max_down_spread.bits.MAX_DOWN_SPREAD ?
++ LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
++
++ edp_config_cap.raw = dpcd_data[
++ DPCD_ADDRESS_EDP_CONFIG_CAP - DPCD_ADDRESS_DPCD_REV];
++ link->dpcd_caps.panel_mode_edp =
++ edp_config_cap.bits.ALT_SCRAMBLER_RESET;
++
++ link->edp_revision = DPCD_EDP_REVISION_EDP_UNKNOWN;
++
++ /* read sink count */
++ core_link_read_dpcd(link,
++ DPCD_ADDRESS_SINK_COUNT,
++ &link->dpcd_caps.sink_count.raw,
++ sizeof(link->dpcd_caps.sink_count.raw));
++
++ /* Display control registers starting at DPCD 700h are only valid and
++ * enabled if this eDP config cap bit is set. */
++ if (edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE) {
++ /* Read the Panel's eDP revision at DPCD 700h. */
++ core_link_read_dpcd(link,
++ DPCD_ADDRESS_EDP_REV,
++ (uint8_t *)(&link->edp_revision),
++ sizeof(link->edp_revision));
++ }
++ /* TODO: Confirm if need retrieve_psr_link_cap */
++}
++
++void detect_dp_sink_caps(struct core_link *link)
++{
++ retrieve_link_cap(link);
++
++ /* dc init_hw has power encoder using default
++ * signal for connector. For native DP, no
++ * need to power up encoder again. If not native
++ * DP, hw_init may need check signal or power up
++ * encoder here.
++ */
++
++ if (is_mst_supported(link)) {
++ link->verified_link_cap = link->reported_link_cap;
++ } else {
++ dp_hbr_verify_link_cap(link,
++ &link->reported_link_cap);
++ }
++ /* TODO save sink caps in link->sink */
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c
+new file mode 100644
+index 0000000..164cdeb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_link_hwss.c
+@@ -0,0 +1,188 @@
++/* Copyright 2015 Advanced Micro Devices, Inc. */
++
++#include "dc_services.h"
++#include "dc.h"
++#include "inc/core_dc.h"
++#include "include/ddc_service_types.h"
++#include "include/i2caux_interface.h"
++#include "link_hwss.h"
++#include "include/connector_interface.h"
++#include "hw_sequencer.h"
++#include "include/ddc_service_interface.h"
++
++enum dc_status core_link_read_dpcd(
++ struct core_link* link,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size)
++{
++ if (dal_ddc_service_read_dpcd_data(link->ddc, address, data, size)
++ != DDC_RESULT_SUCESSFULL)
++ return DC_ERROR_UNEXPECTED;
++
++ return DC_OK;
++}
++
++enum dc_status core_link_write_dpcd(
++ struct core_link* link,
++ uint32_t address,
++ const uint8_t *data,
++ uint32_t size)
++{
++ if (dal_ddc_service_write_dpcd_data(link->ddc, address, data, size)
++ != DDC_RESULT_SUCESSFULL)
++ return DC_ERROR_UNEXPECTED;
++
++ return DC_OK;
++}
++
++void dp_receiver_power_ctrl(struct core_link *link, bool on)
++{
++ uint8_t state;
++
++ state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
++
++ core_link_write_dpcd(link, DPCD_ADDRESS_POWER_STATE, &state,
++ sizeof(state));
++}
++
++
++/* TODO: HBR2 need raise clock for DP link training */
++enum dc_status dp_enable_link_phy(
++ struct core_link *link,
++ enum signal_type signal,
++ enum engine_id engine,
++ const struct link_settings *link_settings)
++{
++ enum dc_status status = DC_OK;
++
++ if (link->dc->hwss.encoder_enable_output(
++ link->link_enc,
++ link_settings,
++ engine,
++ CLOCK_SOURCE_ID_EXTERNAL,
++ signal,
++ COLOR_DEPTH_UNDEFINED,
++ 0) != ENCODER_RESULT_OK)
++ status = DC_ERROR_UNEXPECTED;
++
++ dp_receiver_power_ctrl(link, true);
++
++ return status;
++}
++
++void dp_disable_link_phy(struct core_link *link, enum signal_type signal)
++{
++ if(!link)
++ return;
++
++ if (!link->dp_wa.bits.KEEP_RECEIVER_POWERED)
++ dp_receiver_power_ctrl(link, false);
++
++ link->dc->hwss.encoder_disable_output(link->link_enc, signal);
++
++ /* Clear current link setting.*/
++ dc_service_memset(&link->cur_link_settings, 0,
++ sizeof(link->cur_link_settings));
++}
++
++bool dp_set_hw_training_pattern(
++ struct core_link *link,
++ enum hw_dp_training_pattern pattern)
++{
++ enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
++ struct encoder_set_dp_phy_pattern_param pattern_param = {0};
++ struct link_encoder *encoder = link->link_enc;
++
++ switch (pattern) {
++ case HW_DP_TRAINING_PATTERN_1:
++ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
++ break;
++ case HW_DP_TRAINING_PATTERN_2:
++ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
++ break;
++ case HW_DP_TRAINING_PATTERN_3:
++ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
++ break;
++ default:
++ break;
++ }
++
++ pattern_param.dp_phy_pattern = test_pattern;
++ pattern_param.custom_pattern = NULL;
++ pattern_param.custom_pattern_size = 0;
++ pattern_param.dp_panel_mode = dp_get_panel_mode(link);
++
++ link->ctx->dc->hwss.encoder_set_dp_phy_pattern(encoder, &pattern_param);
++
++ return true;
++}
++
++
++bool dp_set_hw_lane_settings(
++ struct core_link *link,
++ const struct link_training_settings *link_settings)
++{
++ struct link_encoder *encoder = link->link_enc;
++
++ /* call Encoder to set lane settings */
++ link->ctx->dc->hwss.encoder_dp_set_lane_settings(encoder, link_settings);
++
++ return true;
++}
++
++enum dp_panel_mode dp_get_panel_mode(struct core_link *link)
++{
++ /* We need to explicitly check that connector
++ * is not DP. Some Travis_VGA get reported
++ * by video bios as DP.
++ */
++ if (link->public.connector_signal != SIGNAL_TYPE_DISPLAY_PORT) {
++
++ switch (link->dpcd_caps.branch_dev_id) {
++ case DP_BRANCH_DEVICE_ID_2:
++ if (strncmp(
++ link->dpcd_caps.branch_dev_name,
++ DP_VGA_LVDS_CONVERTER_ID_2,
++ sizeof(
++ link->dpcd_caps.
++ branch_dev_name)) == 0) {
++ return DP_PANEL_MODE_SPECIAL;
++ }
++ break;
++ case DP_BRANCH_DEVICE_ID_3:
++ if (strncmp(link->dpcd_caps.branch_dev_name,
++ DP_VGA_LVDS_CONVERTER_ID_3,
++ sizeof(
++ link->dpcd_caps.
++ branch_dev_name)) == 0) {
++ return DP_PANEL_MODE_SPECIAL;
++ }
++ break;
++ default:
++ break;
++ }
++
++ if (link->dpcd_caps.panel_mode_edp) {
++ return DP_PANEL_MODE_EDP;
++ }
++ }
++
++ return DP_PANEL_MODE_DEFAULT;
++}
++
++void dp_set_hw_test_pattern(
++ struct core_link *link,
++ enum dp_test_pattern test_pattern)
++{
++ struct encoder_set_dp_phy_pattern_param pattern_param = {0};
++ struct link_encoder *encoder = link->link_enc;
++
++ pattern_param.dp_phy_pattern = test_pattern;
++ pattern_param.custom_pattern = NULL;
++ pattern_param.custom_pattern_size = 0;
++ pattern_param.dp_panel_mode = dp_get_panel_mode(link);
++
++ link->ctx->dc->hwss.encoder_set_dp_phy_pattern(encoder, &pattern_param);
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
+new file mode 100644
+index 0000000..5803e22
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_resource.c
+@@ -0,0 +1,378 @@
++/*
++* 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 "dc_services.h"
++
++#include "resource.h"
++#include "include/irq_service_interface.h"
++#include "link_encoder_types.h"
++#include "stream_encoder_types.h"
++
++
++void unreference_clock_source(
++ struct resource_context *res_ctx,
++ struct clock_source *clock_source)
++{
++ int i;
++ for (i = 0; i < res_ctx->pool.clk_src_count; i++) {
++ if (res_ctx->pool.clock_sources[i] == clock_source) {
++ res_ctx->clock_source_ref_count[i]--;
++ }
++ }
++}
++
++void reference_clock_source(
++ struct resource_context *res_ctx,
++ struct clock_source *clock_source)
++{
++ int i;
++ for (i = 0; i < res_ctx->pool.clk_src_count; i++) {
++ if (res_ctx->pool.clock_sources[i] == clock_source) {
++ res_ctx->clock_source_ref_count[i]++;
++ }
++ }
++}
++
++bool is_same_timing(
++ const struct dc_crtc_timing *timing1,
++ const struct dc_crtc_timing *timing2)
++{
++ return dal_memcmp(timing1, timing2, sizeof(struct dc_crtc_timing)) == 0;
++}
++
++static bool is_sharable_clk_src(
++ const struct core_stream *stream_with_clk_src,
++ const struct core_stream *stream)
++{
++ enum clock_source_id id = dal_clock_source_get_id(
++ stream_with_clk_src->clock_source);
++
++ if (stream_with_clk_src->clock_source == NULL)
++ return false;
++
++ if (!dc_is_dp_signal(stream->signal) && id == CLOCK_SOURCE_ID_EXTERNAL)
++ return false;
++
++ if(!is_same_timing(
++ &stream_with_clk_src->public.timing, &stream->public.timing))
++ return false;
++
++ return true;
++}
++
++struct clock_source *find_used_clk_src_for_sharing(
++ struct validate_context *context,
++ struct core_stream *stream)
++{
++ uint8_t i, j;
++ for (i = 0; i < context->target_count; i++) {
++ struct core_target *target = context->targets[i];
++ for (j = 0; j < target->stream_count; j++)
++ {
++ if (target->streams[j]->clock_source == NULL)
++ continue;
++ if (is_sharable_clk_src(target->streams[j], stream))
++ return target->streams[j]->clock_source;
++ }
++ }
++
++ return NULL;
++}
++
++static enum pixel_format convert_pixel_format_to_dalsurface(
++ enum surface_pixel_format surface_pixel_format)
++{
++ enum pixel_format dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
++
++ switch (surface_pixel_format) {
++ case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
++ dal_pixel_format = PIXEL_FORMAT_INDEX8;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
++ dal_pixel_format = PIXEL_FORMAT_RGB565;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
++ dal_pixel_format = PIXEL_FORMAT_RGB565;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
++ dal_pixel_format = PIXEL_FORMAT_ARGB8888;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_BGRA8888:
++ dal_pixel_format = PIXEL_FORMAT_ARGB8888;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
++ dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
++ dal_pixel_format = PIXEL_FORMAT_ARGB2101010;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
++ dal_pixel_format = PIXEL_FORMAT_ARGB2101010_XRBIAS;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
++ dal_pixel_format = PIXEL_FORMAT_FP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
++ dal_pixel_format = PIXEL_FORMAT_FP16;
++ break;
++
++
++ case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
++ dal_pixel_format = PIXEL_FORMAT_420BPP12;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
++ dal_pixel_format = PIXEL_FORMAT_420BPP12;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_422_YCb:
++ dal_pixel_format = PIXEL_FORMAT_422BPP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_422_YCr:
++ dal_pixel_format = PIXEL_FORMAT_422BPP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_422_CbY:
++ dal_pixel_format = PIXEL_FORMAT_422BPP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_422_CrY:
++ dal_pixel_format = PIXEL_FORMAT_422BPP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb1555:
++ dal_pixel_format = PIXEL_FORMAT_444BPP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_444_CrYCb565:
++ dal_pixel_format = PIXEL_FORMAT_444BPP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb4444:
++ dal_pixel_format = PIXEL_FORMAT_444BPP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_444_CbYCrA5551:
++ dal_pixel_format = PIXEL_FORMAT_444BPP16;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb8888:
++ dal_pixel_format = PIXEL_FORMAT_444BPP32;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb2101010:
++ dal_pixel_format = PIXEL_FORMAT_444BPP32;
++ break;
++ case SURFACE_PIXEL_FORMAT_VIDEO_444_CbYCrA1010102:
++ dal_pixel_format = PIXEL_FORMAT_444BPP32;
++ break;
++ default:
++ dal_pixel_format = PIXEL_FORMAT_UNKNOWN;
++ break;
++ }
++ return dal_pixel_format;
++}
++
++static void calculate_viewport(
++ const struct dc_surface *surface,
++ struct core_stream *stream)
++{
++ const struct rect src = surface->src_rect;
++ const struct rect clip = surface->clip_rect;
++ const struct rect dst = surface->dst_rect;
++
++ /* offset = src.ofs + (clip.ofs - dst.ofs) * scl_ratio
++ * num_pixels = clip.num_pix * scl_ratio
++ */
++ stream->viewport.x = src.x + (clip.x - dst.x) * src.width / dst.width;
++ stream->viewport.width = clip.width * src.width / dst.width;
++
++ stream->viewport.y = src.y + (clip.y - dst.y) * src.height / dst.height;
++ stream->viewport.height = clip.height * src.height / dst.height;
++
++ /* Minimum viewport such that 420/422 chroma vp is non 0 */
++ if (stream->viewport.width < 2)
++ {
++ stream->viewport.width = 2;
++ }
++ if (stream->viewport.height < 2)
++ {
++ stream->viewport.height = 2;
++ }
++}
++
++static void calculate_overscan(
++ const struct dc_surface *surface,
++ struct core_stream *stream)
++{
++ stream->overscan.left = stream->public.dst.x;
++ if (stream->public.src.x < surface->clip_rect.x)
++ stream->overscan.left += (surface->clip_rect.x
++ - stream->public.src.x) * stream->public.dst.width
++ / stream->public.src.width;
++
++ stream->overscan.right = stream->public.timing.h_addressable
++ - stream->public.dst.x - stream->public.dst.width;
++ if (stream->public.src.x + stream->public.src.width
++ > surface->clip_rect.x + surface->clip_rect.width)
++ stream->overscan.right = stream->public.timing.h_addressable -
++ dal_fixed31_32_floor(dal_fixed31_32_div(
++ dal_fixed31_32_from_int(
++ stream->viewport.width),
++ stream->ratios.horz)) -
++ stream->overscan.left;
++
++
++ stream->overscan.top = stream->public.dst.y;
++ if (stream->public.src.y < surface->clip_rect.y)
++ stream->overscan.top += (surface->clip_rect.y
++ - stream->public.src.y) * stream->public.dst.height
++ / stream->public.src.height;
++
++ stream->overscan.bottom = stream->public.timing.v_addressable
++ - stream->public.dst.y - stream->public.dst.height;
++ if (stream->public.src.y + stream->public.src.height
++ > surface->clip_rect.y + surface->clip_rect.height)
++ stream->overscan.bottom = stream->public.timing.v_addressable -
++ dal_fixed31_32_floor(dal_fixed31_32_div(
++ dal_fixed31_32_from_int(
++ stream->viewport.height),
++ stream->ratios.vert)) -
++ stream->overscan.top;
++
++
++ /* TODO: Add timing overscan to finalize overscan calculation*/
++}
++
++static void calculate_scaling_ratios(
++ const struct dc_surface *surface,
++ struct core_stream *stream)
++{
++ const uint32_t in_w = stream->public.src.width;
++ const uint32_t in_h = stream->public.src.height;
++ const uint32_t out_w = stream->public.dst.width;
++ const uint32_t out_h = stream->public.dst.height;
++
++ stream->ratios.horz = dal_fixed31_32_from_fraction(
++ surface->src_rect.width,
++ surface->dst_rect.width);
++ stream->ratios.vert = dal_fixed31_32_from_fraction(
++ surface->src_rect.height,
++ surface->dst_rect.height);
++
++ if (surface->stereo_format == PLANE_STEREO_FORMAT_SIDE_BY_SIDE)
++ stream->ratios.horz.value *= 2;
++ else if (surface->stereo_format
++ == PLANE_STEREO_FORMAT_TOP_AND_BOTTOM)
++ stream->ratios.vert.value *= 2;
++
++ stream->ratios.vert.value = stream->ratios.vert.value * in_h / out_h;
++ stream->ratios.horz.value = stream->ratios.horz.value * in_w / out_w;
++
++ stream->ratios.horz_c = stream->ratios.horz;
++ stream->ratios.vert_c = stream->ratios.vert;
++
++ if (stream->format == PIXEL_FORMAT_420BPP12) {
++ stream->ratios.horz_c.value /= 2;
++ stream->ratios.vert_c.value /= 2;
++ } else if (stream->format == PIXEL_FORMAT_422BPP16) {
++ stream->ratios.horz_c.value /= 2;
++ }
++}
++
++/*TODO: per pipe not per stream*/
++void build_scaling_params(
++ const struct dc_surface *surface,
++ struct core_stream *stream)
++{
++ /* Important: scaling ratio calculation requires pixel format,
++ * overscan calculation requires scaling ratios and viewport
++ * and lb depth/taps calculation requires overscan. Call sequence
++ * is therefore important */
++ stream->format = convert_pixel_format_to_dalsurface(surface->format);
++
++ calculate_viewport(surface, stream);
++
++ calculate_scaling_ratios(surface, stream);
++
++ calculate_overscan(surface, stream);
++
++ /* Check if scaling is required update taps if not */
++ if (dal_fixed31_32_u2d19(stream->ratios.horz) == 1 << 19)
++ stream->taps.h_taps = 1;
++ else
++ stream->taps.h_taps = surface->scaling_quality.h_taps;
++
++ if (dal_fixed31_32_u2d19(stream->ratios.horz_c) == 1 << 19)
++ stream->taps.h_taps_c = 1;
++ else
++ stream->taps.h_taps_c = surface->scaling_quality.h_taps_c;
++
++ if (dal_fixed31_32_u2d19(stream->ratios.vert) == 1 << 19)
++ stream->taps.v_taps = 1;
++ else
++ stream->taps.v_taps = surface->scaling_quality.v_taps;
++
++ if (dal_fixed31_32_u2d19(stream->ratios.vert_c) == 1 << 19)
++ stream->taps.v_taps_c = 1;
++ else
++ stream->taps.v_taps_c = surface->scaling_quality.v_taps_c;
++}
++
++void build_scaling_params_for_context(
++ const struct dc *dc,
++ struct validate_context *context)
++{
++ uint8_t i, j, k;
++ for (i = 0; i < context->target_count; i++) {
++ struct core_target *target = context->targets[i];
++ if (context->target_flags[i].unchanged)
++ continue;
++ for (j = 0; j < target->status.surface_count; j++) {
++ const struct dc_surface *surface = target->status.surfaces[j];
++ for (k = 0; k < target->stream_count; k++) {
++ struct core_stream *stream = target->streams[k];
++
++ build_scaling_params(surface, stream);
++ }
++ }
++ }
++}
++
++bool logical_attach_surfaces_to_target(
++ struct dc_surface *surfaces[],
++ uint8_t surface_count,
++ struct dc_target *dc_target)
++{
++ uint8_t i;
++ struct core_target *target = DC_TARGET_TO_CORE(dc_target);
++
++ if (target->status.surface_count >= MAX_SURFACE_NUM) {
++ dal_error("Surface: this target has too many surfaces!\n");
++ return false;
++ }
++
++ for (i = 0; i < target->status.surface_count; i++)
++ dc_surface_release(target->status.surfaces[i]);
++
++ for (i = 0; i < surface_count; i++) {
++ struct core_surface *surface = DC_SURFACE_TO_CORE(surfaces[i]);
++ surface->status.dc_target = &target->public;
++ target->status.surfaces[i] = surfaces[i];
++ dc_surface_retain(target->status.surfaces[i]);
++ }
++ target->status.surface_count = surface_count;
++
++ return true;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_sink.c b/drivers/gpu/drm/amd/dal/dc/core/dc_sink.c
+new file mode 100644
+index 0000000..3d537d5
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_sink.c
+@@ -0,0 +1,118 @@
++/*
++ * 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 "dc_services.h"
++#include "dc_helpers.h"
++#include "core_types.h"
++
++/*******************************************************************************
++ * Private definitions
++ ******************************************************************************/
++
++struct sink {
++ struct core_sink protected;
++ int ref_count;
++};
++
++#define DC_SINK_TO_SINK(dc_sink) \
++ container_of(dc_sink, struct sink, protected.public)
++
++/*******************************************************************************
++ * Private functions
++ ******************************************************************************/
++
++static void destruct(struct sink *sink)
++{
++
++}
++
++static bool construct(struct sink *sink, const struct sink_init_data *init_params)
++{
++
++ struct core_link *core_link = DC_LINK_TO_LINK(init_params->link);
++
++ sink->protected.public.sink_signal = init_params->sink_signal;
++ sink->protected.link = core_link;
++ sink->protected.ctx = core_link->ctx;
++ sink->protected.dongle_max_pix_clk = init_params->dongle_max_pix_clk;
++ sink->protected.converter_disable_audio =
++ init_params->converter_disable_audio;
++
++ return true;
++}
++
++/*******************************************************************************
++ * Public functions
++ ******************************************************************************/
++
++void dc_sink_retain(const struct dc_sink *dc_sink)
++{
++ struct sink *sink = DC_SINK_TO_SINK(dc_sink);
++
++ ++sink->ref_count;
++}
++
++void dc_sink_release(const struct dc_sink *dc_sink)
++{
++ struct core_sink *core_sink = DC_SINK_TO_CORE(dc_sink);
++ struct sink *sink = DC_SINK_TO_SINK(dc_sink);
++
++ --sink->ref_count;
++
++ if (sink->ref_count == 0) {
++ destruct(sink);
++ dc_service_free(core_sink->ctx, sink);
++ }
++}
++
++
++/*******************************************************************************
++ * Protected functions - visible only inside of DC (not visible in DM)
++ ******************************************************************************/
++
++struct dc_sink *sink_create(const struct sink_init_data *init_params)
++{
++ struct core_link *core_link = DC_LINK_TO_LINK(init_params->link);
++
++ struct sink *sink = dc_service_alloc(core_link->ctx, sizeof(*sink));
++
++ if (NULL == sink)
++ goto alloc_fail;
++
++ if (false == construct(sink, init_params))
++ goto construct_fail;
++
++ /* TODO should we move this outside to where the assignment actually happens? */
++ dc_sink_retain(&sink->protected.public);
++
++ return &sink->protected.public;
++
++construct_fail:
++ dc_service_free(core_link->ctx, sink);
++
++alloc_fail:
++ return NULL;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_stream.c b/drivers/gpu/drm/amd/dal/dc/core/dc_stream.c
+new file mode 100644
+index 0000000..1a7bf50
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_stream.c
+@@ -0,0 +1,172 @@
++/*
++ * 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 "dc_services.h"
++#include "dc.h"
++#include "core_types.h"
++#include "resource.h"
++
++/*******************************************************************************
++ * Private definitions
++ ******************************************************************************/
++
++struct stream {
++ struct core_stream protected;
++ int ref_count;
++};
++
++#define DC_STREAM_TO_STREAM(dc_stream) container_of(dc_stream, struct stream, protected.public)
++
++/*******************************************************************************
++ * Private functions
++ ******************************************************************************/
++
++static void build_bit_depth_reduction_params(
++ struct bit_depth_reduction_params *fmt_bit_depth)
++{
++ /*TODO: Need to un-hardcode, refer to function with same name
++ * in dal2 hw_sequencer*/
++
++ fmt_bit_depth->flags.TRUNCATE_ENABLED = 0;
++ fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 0;
++ fmt_bit_depth->flags.FRAME_MODULATION_ENABLED = 0;
++ fmt_bit_depth->flags.SPATIAL_DITHER_DEPTH = 1;
++
++ fmt_bit_depth->flags.SPATIAL_DITHER_ENABLED = 1;
++ /* frame random is on by default */
++ fmt_bit_depth->flags.FRAME_RANDOM = 1;
++ /* apply RGB dithering */
++ fmt_bit_depth->flags.RGB_RANDOM = true;
++
++ return;
++
++}
++
++static void setup_pixel_encoding(
++ struct clamping_and_pixel_encoding_params *clamping)
++{
++ /*TODO: Need to un-hardcode, refer to function with same name
++ * in dal2 hw_sequencer*/
++
++ clamping->pixel_encoding = PIXEL_ENCODING_RGB;
++
++ return;
++}
++
++static bool construct(struct core_stream *stream,
++ const struct dc_sink *dc_sink_data)
++{
++ uint32_t i = 0;
++
++ stream->sink = DC_SINK_TO_CORE(dc_sink_data);
++ stream->ctx = stream->sink->ctx;
++ stream->public.sink = dc_sink_data;
++
++ dc_sink_retain(dc_sink_data);
++
++ build_bit_depth_reduction_params(&stream->fmt_bit_depth);
++ setup_pixel_encoding(&stream->clamping);
++
++ /* Copy audio modes */
++ /* TODO - Remove this translation */
++ for (i = 0; i < (dc_sink_data->edid_caps.audio_mode_count); i++)
++ {
++ stream->public.audio_info.modes[i].channel_count = dc_sink_data->edid_caps.audio_modes[i].channel_count;
++ stream->public.audio_info.modes[i].format_code = dc_sink_data->edid_caps.audio_modes[i].format_code;
++ stream->public.audio_info.modes[i].sample_rates.all = dc_sink_data->edid_caps.audio_modes[i].sample_rate;
++ stream->public.audio_info.modes[i].sample_size = dc_sink_data->edid_caps.audio_modes[i].sample_size;
++ }
++ stream->public.audio_info.mode_count = dc_sink_data->edid_caps.audio_mode_count;
++ stream->public.audio_info.audio_latency = dc_sink_data->edid_caps.audio_latency;
++ stream->public.audio_info.video_latency = dc_sink_data->edid_caps.video_latency;
++ dc_service_memmove(
++ stream->public.audio_info.display_name,
++ dc_sink_data->edid_caps.display_name,
++ AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS);
++ stream->public.audio_info.manufacture_id = dc_sink_data->edid_caps.manufacturer_id;
++ stream->public.audio_info.product_id = dc_sink_data->edid_caps.product_id;
++ stream->public.audio_info.flags.all = dc_sink_data->edid_caps.speaker_flags;
++
++ /* TODO - Unhardcode port_id */
++ stream->public.audio_info.port_id[0] = 0x5558859e;
++ stream->public.audio_info.port_id[1] = 0xd989449;
++
++ /* EDID CAP translation for HDMI 2.0 */
++ stream->public.timing.flags.LTE_340MCSC_SCRAMBLE = dc_sink_data->edid_caps.lte_340mcsc_scramble;
++ return true;
++}
++
++static void destruct(struct core_stream *stream)
++{
++ dc_sink_release(&stream->sink->public);
++}
++
++void dc_stream_retain(struct dc_stream *dc_stream)
++{
++ struct stream *stream = DC_STREAM_TO_STREAM(dc_stream);
++ stream->ref_count++;
++}
++
++void dc_stream_release(struct dc_stream *public)
++{
++ struct stream *stream = DC_STREAM_TO_STREAM(public);
++ struct core_stream *protected = DC_STREAM_TO_CORE(public);
++ struct dc_context *ctx = protected->ctx;
++ stream->ref_count--;
++
++ if (stream->ref_count == 0) {
++ destruct(protected);
++ dc_service_free(ctx, stream);
++ }
++}
++
++struct dc_stream *dc_create_stream_for_sink(const struct dc_sink *dc_sink)
++{
++ struct core_sink *sink = DC_SINK_TO_CORE(dc_sink);
++ struct stream *stream;
++
++ if (sink == NULL)
++ goto alloc_fail;
++
++ stream = dc_service_alloc(sink->ctx, sizeof(struct stream));
++
++ if (NULL == stream)
++ goto alloc_fail;
++
++ if (false == construct(&stream->protected, dc_sink))
++ goto construct_fail;
++
++ dc_stream_retain(&stream->protected.public);
++
++ return &stream->protected.public;
++
++construct_fail:
++ dc_service_free(sink->ctx, stream);
++
++alloc_fail:
++ return NULL;
++}
++
++
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_surface.c b/drivers/gpu/drm/amd/dal/dc/core/dc_surface.c
+new file mode 100644
+index 0000000..41a5feb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_surface.c
+@@ -0,0 +1,124 @@
++/*
++ * Copyright 2015 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
++ *
++ */
++
++/* DC interface (public) */
++#include "dc_services.h"
++#include "dc.h"
++
++/* DC core (private) */
++#include "core_dc.h"
++#include "adjustment_types.h"
++
++
++/*******************************************************************************
++ * Private structures
++ ******************************************************************************/
++struct surface {
++ struct core_surface protected;
++ enum dc_irq_source irq_source;
++ int ref_count;
++};
++
++#define DC_SURFACE_TO_SURFACE(dc_surface) container_of(dc_surface, struct surface, protected.public)
++#define CORE_SURFACE_TO_SURFACE(core_surface) container_of(core_surface, struct surface, protected)
++
++/*******************************************************************************
++ * Private functions
++ ******************************************************************************/
++static bool construct(struct dc_context *ctx, struct surface *surface)
++{
++ uint32_t i;
++ struct gamma_ramp *gamma =
++ &surface->protected.public.gamma_correction;
++
++ /* construct gamma default value. */
++ for (i = 0; i < NUM_OF_RAW_GAMMA_RAMP_RGB_256; i++) {
++ gamma->gamma_ramp_rgb256x3x16.red[i] =
++ (unsigned short) (i << 8);
++ gamma->gamma_ramp_rgb256x3x16.green[i] =
++ (unsigned short) (i << 8);
++ gamma->gamma_ramp_rgb256x3x16.blue[i] =
++ (unsigned short) (i << 8);
++ }
++ gamma->type = GAMMA_RAMP_TYPE_RGB256;
++ gamma->size = sizeof(gamma->gamma_ramp_rgb256x3x16);
++
++ surface->protected.ctx = ctx;
++ return true;
++}
++
++static void destruct(struct surface *surface)
++{
++}
++
++/*******************************************************************************
++ * Public functions
++ ******************************************************************************/
++void enable_surface_flip_reporting(struct dc_surface *dc_surface,
++ uint32_t controller_id)
++{
++ struct surface *surface = DC_SURFACE_TO_SURFACE(dc_surface);
++ surface->irq_source = controller_id + DC_IRQ_SOURCE_PFLIP1 - 1;
++ /*register_flip_interrupt(surface);*/
++}
++
++struct dc_surface *dc_create_surface(const struct dc *dc)
++{
++ struct surface *surface = dc_service_alloc(dc->ctx, sizeof(*surface));
++
++ if (NULL == surface)
++ goto alloc_fail;
++
++ if (false == construct(dc->ctx, surface))
++ goto construct_fail;
++
++ dc_surface_retain(&surface->protected.public);
++
++ return &surface->protected.public;
++
++construct_fail:
++ dc_service_free(dc->ctx, surface);
++
++alloc_fail:
++ return NULL;
++}
++
++void dc_surface_retain(const struct dc_surface *dc_surface)
++{
++ struct surface *surface = DC_SURFACE_TO_SURFACE(dc_surface);
++
++ ++surface->ref_count;
++}
++
++void dc_surface_release(const struct dc_surface *dc_surface)
++{
++ struct surface *surface = DC_SURFACE_TO_SURFACE(dc_surface);
++ --surface->ref_count;
++
++ if (surface->ref_count == 0) {
++ destruct(surface);
++ dc_service_free(surface->protected.ctx, surface);
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/core/dc_target.c b/drivers/gpu/drm/amd/dal/dc/core/dc_target.c
+new file mode 100644
+index 0000000..9243c01
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/core/dc_target.c
+@@ -0,0 +1,473 @@
++/*
++ * 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 "dc_services.h"
++#include "core_types.h"
++#include "hw_sequencer.h"
++#include "resource.h"
++
++#define COEFF_RANGE 3
++#define REGAMMA_COEFF_A0 31308
++#define REGAMMA_COEFF_A1 12920
++#define REGAMMA_COEFF_A2 55
++#define REGAMMA_COEFF_A3 55
++#define REGAMMA_COEFF_GAMMA 2400
++
++struct target {
++ struct core_target protected;
++ int ref_count;
++};
++
++#define DC_TARGET_TO_TARGET(dc_target) \
++ container_of(dc_target, struct target, protected.public)
++#define CORE_TARGET_TO_TARGET(core_target) \
++ container_of(core_target, struct target, protected)
++
++static void construct(
++ struct core_target *target,
++ struct dc_context *ctx,
++ struct dc_stream *dc_streams[],
++ uint8_t stream_count)
++{
++ uint8_t i;
++ for (i = 0; i < stream_count; i++) {
++ target->streams[i] = DC_STREAM_TO_CORE(dc_streams[i]);
++ target->public.streams[i] = dc_streams[i];
++ dc_stream_retain(dc_streams[i]);
++ }
++
++ target->ctx = ctx;
++ target->stream_count = stream_count;
++}
++
++static void destruct(struct core_target *core_target)
++{
++ int i;
++
++ for (i = 0; i < core_target->status.surface_count; i++) {
++ dc_surface_release(core_target->status.surfaces[i]);
++ core_target->status.surfaces[i] = 0;
++ }
++ for (i = 0; i < core_target->stream_count; i++) {
++ dc_stream_release(&core_target->streams[i]->public);
++ core_target->streams[i] = 0;
++ }
++}
++
++void dc_target_retain(struct dc_target *dc_target)
++{
++ struct target *target = DC_TARGET_TO_TARGET(dc_target);
++
++ target->ref_count++;
++}
++
++void dc_target_release(struct dc_target *dc_target)
++{
++ struct target *target = DC_TARGET_TO_TARGET(dc_target);
++ struct core_target *protected = DC_TARGET_TO_CORE(dc_target);
++
++ ASSERT(target->ref_count > 0);
++ target->ref_count--;
++ if (target->ref_count == 0) {
++ destruct(protected);
++ dc_service_free(protected->ctx, target);
++ }
++}
++
++const struct dc_target_status *dc_target_get_status(
++ const struct dc_target* dc_target)
++{
++ struct core_target* target = DC_TARGET_TO_CORE(dc_target);
++ return &target->status;
++}
++
++struct dc_target *dc_create_target_for_streams(
++ struct dc_stream *dc_streams[],
++ uint8_t stream_count)
++{
++ struct core_stream *stream;
++ struct target *target;
++
++ if (0 == stream_count)
++ goto target_alloc_fail;
++
++ stream = DC_STREAM_TO_CORE(dc_streams[0]);
++
++ target = dc_service_alloc(stream->ctx, sizeof(struct target));
++
++ if (NULL == target)
++ goto target_alloc_fail;
++
++ construct(&target->protected, stream->ctx, dc_streams, stream_count);
++
++ dc_target_retain(&target->protected.public);
++
++ return &target->protected.public;
++
++
++target_alloc_fail:
++ return NULL;
++}
++
++static void build_gamma_params(
++ enum pixel_format pixel_format,
++ struct gamma_parameters *gamma_param)
++{
++ uint32_t i;
++
++ /* translate parameters */
++ gamma_param->surface_pixel_format = pixel_format;
++
++ gamma_param->regamma_adjust_type = GRAPHICS_REGAMMA_ADJUST_SW;
++ gamma_param->degamma_adjust_type = GRAPHICS_REGAMMA_ADJUST_SW;
++
++ gamma_param->selected_gamma_lut = GRAPHICS_GAMMA_LUT_LEGACY;
++
++ /* TODO support non-legacy gamma */
++ gamma_param->disable_adjustments = false;
++ gamma_param->flag.bits.config_is_changed = 0;
++ gamma_param->flag.bits.regamma_update = 1;
++ gamma_param->flag.bits.gamma_update = 1;
++
++ /* Set regamma */
++ gamma_param->regamma.features.bits.GRAPHICS_DEGAMMA_SRGB = 0;
++ gamma_param->regamma.features.bits.OVERLAY_DEGAMMA_SRGB = 0;
++ gamma_param->regamma.features.bits.GAMMA_RAMP_ARRAY = 0;
++ gamma_param->regamma.features.bits.APPLY_DEGAMMA = 0;
++
++ for (i = 0; i < COEFF_RANGE; i++) {
++ gamma_param->regamma.gamma_coeff.a0[i] = REGAMMA_COEFF_A0;
++ gamma_param->regamma.gamma_coeff.a1[i] = REGAMMA_COEFF_A1;
++ gamma_param->regamma.gamma_coeff.a2[i] = REGAMMA_COEFF_A2;
++ gamma_param->regamma.gamma_coeff.a3[i] = REGAMMA_COEFF_A3;
++ gamma_param->regamma.gamma_coeff.gamma[i] = REGAMMA_COEFF_GAMMA;
++ }
++}
++
++
++static bool program_gamma(
++ struct dc_context *ctx,
++ struct dc_surface *surface,
++ struct input_pixel_processor *ipp,
++ struct output_pixel_processor *opp)
++{
++ struct gamma_parameters *gamma_param;
++ bool result= false;
++
++ gamma_param = dc_service_alloc(ctx, sizeof(struct gamma_parameters));
++
++ if (!gamma_param)
++ goto gamma_param_fail;
++
++ build_gamma_params(surface->format, gamma_param);
++
++ result = ctx->dc->hwss.set_gamma_ramp(ipp, opp,
++ &surface->gamma_correction,
++ gamma_param);
++
++ dc_service_free(ctx, gamma_param);
++
++gamma_param_fail:
++ return result;
++}
++
++bool dc_commit_surfaces_to_target(
++ struct dc *dc,
++ struct dc_surface *surfaces[],
++ uint8_t surface_count,
++ struct dc_target *dc_target)
++
++{
++ uint8_t i, j;
++ struct core_target *target = DC_TARGET_TO_CORE(dc_target);
++ bool need_blanking = (target->status.surface_count == 0);
++
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_INTERFACE_TRACE,
++ LOG_MINOR_COMPONENT_DC,
++ "%s: commit %d surfaces to target 0x%x",
++ __func__,
++ surface_count,
++ dc_target);
++
++
++ if (!logical_attach_surfaces_to_target(
++ surfaces,
++ surface_count,
++ dc_target)) {
++ BREAK_TO_DEBUGGER();
++ goto unexpected_fail;
++ }
++
++ for (i = 0; i < surface_count; i++)
++ for (j = 0; j < target->stream_count; j++)
++ build_scaling_params(surfaces[i], target->streams[j]);
++
++ if (dc->hwss.validate_bandwidth(dc, &dc->current_context) != DC_OK) {
++ BREAK_TO_DEBUGGER();
++ goto unexpected_fail;
++ }
++
++ dc->hwss.program_bw(dc, &dc->current_context);
++
++ if (need_blanking)
++ dc_target_disable_memory_requests(dc_target);
++
++ for (i = 0; i < surface_count; i++) {
++ struct dc_surface *surface = surfaces[i];
++ struct core_surface *core_surface = DC_SURFACE_TO_CORE(surface);
++
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_INTERFACE_TRACE,
++ LOG_MINOR_COMPONENT_DC,
++ "0x%x:",
++ surface);
++ dc_surface_retain(surface);
++
++ program_gamma(dc->ctx, surface,
++ target->streams[0]->ipp,
++ target->streams[0]->opp);
++
++ dc->hwss.set_plane_config(
++ core_surface,
++ target);
++
++ dc->hwss.update_plane_address(core_surface, target);
++ }
++
++ if (surface_count > 0 && need_blanking)
++ dc_target_enable_memory_requests(dc_target);
++
++ return true;
++
++unexpected_fail:
++ for (i = 0; i < surface_count; i++) {
++ target->status.surfaces[i] = NULL;
++ }
++ target->status.surface_count = 0;
++
++ return false;
++}
++
++bool dc_target_is_connected_to_sink(
++ const struct dc_target * dc_target,
++ const struct dc_sink *dc_sink)
++{
++ struct core_target *target = DC_TARGET_TO_CORE(dc_target);
++ uint8_t i;
++ for (i = 0; i < target->stream_count; i++) {
++ if (&target->streams[i]->sink->public == dc_sink)
++ return true;
++ }
++ return false;
++}
++
++void dc_target_enable_memory_requests(struct dc_target *target)
++{
++ uint8_t i;
++ struct core_target *core_target = DC_TARGET_TO_CORE(target);
++ for (i = 0; i < core_target->stream_count; i++) {
++ struct timing_generator *tg = core_target->streams[i]->tg;
++ if (false == core_target->ctx->dc->hwss.enable_memory_requests(tg)) {
++ dal_error("DC: failed to unblank crtc!\n");
++ BREAK_TO_DEBUGGER();
++ }
++ }
++}
++
++void dc_target_disable_memory_requests(struct dc_target *target)
++{
++ uint8_t i;
++ struct core_target *core_target = DC_TARGET_TO_CORE(target);
++ for (i = 0; i < core_target->stream_count; i++) {
++ struct timing_generator *tg = core_target->streams[i]->tg;
++
++ if (NULL == tg) {
++ dal_error("DC: timing generator is NULL!\n");
++ BREAK_TO_DEBUGGER();
++ continue;
++ }
++
++ if (false == core_target->ctx->dc->hwss.disable_memory_requests(tg)) {
++ dal_error("DC: failed to blank crtc!\n");
++ BREAK_TO_DEBUGGER();
++ }
++ }
++}
++
++/**
++ * Update the cursor attributes and set cursor surface address
++ */
++bool dc_target_set_cursor_attributes(
++ struct dc_target *dc_target,
++ const struct dc_cursor_attributes *attributes)
++{
++ struct core_target *core_target;
++ struct input_pixel_processor *ipp;
++
++ if (NULL == dc_target) {
++ dal_error("DC: dc_target is NULL!\n");
++ return false;
++
++ }
++
++ core_target = DC_TARGET_TO_CORE(dc_target);
++ ipp = core_target->streams[0]->ipp;
++
++ if (NULL == ipp) {
++ dal_error("DC: input pixel processor is NULL!\n");
++ return false;
++ }
++
++ if (true == core_target->ctx->dc->hwss.cursor_set_attributes(ipp, attributes))
++ return true;
++
++ return false;
++}
++
++bool dc_target_set_cursor_position(
++ struct dc_target *dc_target,
++ const struct dc_cursor_position *position)
++{
++ struct core_target *core_target;
++ struct input_pixel_processor *ipp;
++
++ if (NULL == dc_target) {
++ dal_error("DC: dc_target is NULL!\n");
++ return false;
++ }
++
++ if (NULL == position) {
++ dal_error("DC: cursor position is NULL!\n");
++ return false;
++ }
++
++ core_target = DC_TARGET_TO_CORE(dc_target);
++ ipp = core_target->streams[0]->ipp;
++
++ if (NULL == ipp) {
++ dal_error("DC: input pixel processor is NULL!\n");
++ return false;
++ }
++
++
++ if (true == core_target->ctx->dc->hwss.cursor_set_position(ipp, position))
++ return true;
++
++ return false;
++}
++
++/* TODO: #flip temporary to make flip work */
++uint8_t dc_target_get_link_index(const struct dc_target *dc_target)
++{
++ const struct core_target *target = CONST_DC_TARGET_TO_CORE(dc_target);
++
++ return target->streams[0]->sink->link->link_index;
++}
++
++uint32_t dc_target_get_vblank_counter(const struct dc_target *dc_target)
++{
++ struct core_target *core_target = DC_TARGET_TO_CORE(dc_target);
++ struct timing_generator *tg = core_target->streams[0]->tg;
++
++ return core_target->ctx->dc->hwss.get_vblank_counter(tg);
++}
++
++enum dc_irq_source dc_target_get_irq_src(
++ const struct dc_target *dc_target, const enum irq_type irq_type)
++{
++ struct core_target *core_target = DC_TARGET_TO_CORE(dc_target);
++
++ /* #TODO - Remove the assumption that the controller is always in the
++ * first stream of a core target */
++ uint8_t controller_idx = core_target->streams[0]->controller_idx;
++
++ /* Get controller id */
++ enum controller_id crtc_id = controller_idx + 1;
++
++ /* Calculate controller offset */
++ unsigned int offset = crtc_id - CONTROLLER_ID_D0;
++ unsigned int base = irq_type;
++
++ /* Calculate irq source */
++ enum dc_irq_source src = base + offset;
++
++ return src;
++}
++
++void dc_target_log(
++ const struct dc_target *dc_target,
++ struct dal_logger *dal_logger,
++ enum log_major log_major,
++ enum log_minor log_minor)
++{
++ int i;
++
++ const struct core_target *core_target =
++ CONST_DC_TARGET_TO_CORE(dc_target);
++
++ dal_logger_write(dal_logger,
++ log_major,
++ log_minor,
++ "core_target 0x%x: surface_count=%d, stream_count=%d",
++ core_target,
++ core_target->status.surface_count,
++ core_target->stream_count);
++
++ for (i = 0; i < core_target->stream_count; i++) {
++ const struct core_stream *core_stream = core_target->streams[i];
++
++ dal_logger_write(dal_logger,
++ log_major,
++ log_minor,
++ "core_stream 0x%x: src: %d, %d, %d, %d; dst: %d, %d, %d, %d;",
++ core_stream,
++ core_stream->public.src.x,
++ core_stream->public.src.y,
++ core_stream->public.src.width,
++ core_stream->public.src.height,
++ core_stream->public.dst.x,
++ core_stream->public.dst.y,
++ core_stream->public.dst.width,
++ core_stream->public.dst.height);
++ dal_logger_write(dal_logger,
++ log_major,
++ log_minor,
++ "\tpix_clk_khz: %d, h_total: %d, v_total: %d",
++ core_stream->public.timing.pix_clk_khz,
++ core_stream->public.timing.h_total,
++ core_stream->public.timing.v_total);
++ dal_logger_write(dal_logger,
++ log_major,
++ log_minor,
++ "\tsink name: %s, serial: %d",
++ core_stream->sink->public.edid_caps.display_name,
++ core_stream->sink->public.edid_caps.serial_number);
++ dal_logger_write(dal_logger,
++ log_major,
++ log_minor,
++ "\tconnector: %d",
++ core_stream->sink->link->connector_index);
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dc.h b/drivers/gpu/drm/amd/dal/dc/dc.h
+new file mode 100644
+index 0000000..1db9395
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dc.h
+@@ -0,0 +1,440 @@
++/*
++ * Copyright 2012-14 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef DC_INTERFACE_H_
++#define DC_INTERFACE_H_
++
++#include "dc_types.h"
++/* TODO: We should not include audio_interface.h here. Maybe just define
++ * struct audio_info here */
++#include "audio_interface.h"
++#include "logger_types.h"
++
++#define MAX_SINKS_PER_LINK 4
++
++/*******************************************************************************
++ * Display Core Interfaces
++ ******************************************************************************/
++struct dc_init_data {
++ struct dc_context *ctx;
++ struct adapter_service *adapter_srv;
++};
++
++struct dc_caps {
++ uint32_t max_targets;
++ uint32_t max_links;
++ uint32_t max_audios;
++};
++
++void dc_get_caps(const struct dc *dc, struct dc_caps *caps);
++
++struct dc *dc_create(const struct dal_init_data *init_params);
++void dc_destroy(struct dc **dc);
++
++/*******************************************************************************
++ * Surface Interfaces
++ ******************************************************************************/
++
++struct dc_surface {
++ bool enabled;
++ bool flip_immediate;
++ struct dc_plane_address address;
++
++ struct scaling_taps scaling_quality;
++ struct rect src_rect;
++ struct rect dst_rect;
++ struct rect clip_rect;
++
++ union plane_size plane_size;
++ union plane_tiling_info tiling_info;
++ struct plane_colorimetry colorimetry;
++
++ enum surface_pixel_format format;
++ enum dc_rotation_angle rotation;
++ enum plane_stereo_format stereo_format;
++
++ struct gamma_ramp gamma_correction;
++};
++
++/*
++ * This structure is filled in by dc_surface_get_status and contains
++ * the last requested address and the currently active address so the called
++ * can determine if there are any outstanding flips
++ */
++struct dc_surface_status {
++ struct dc_plane_address requested_address;
++ struct dc_plane_address current_address;
++ const struct dc_target *dc_target;
++};
++
++/*
++ * Create a new surface with default parameters;
++ */
++struct dc_surface *dc_create_surface(const struct dc *dc);
++const struct dc_surface_status* dc_surface_get_status(
++ struct dc_surface *dc_surface);
++
++void dc_surface_retain(const struct dc_surface *dc_surface);
++void dc_surface_release(const struct dc_surface *dc_surface);
++
++/*
++ * This structure holds a surface address. There could be multiple addresses
++ * in cases such as Stereo 3D, Planar YUV, etc. Other per-flip attributes such
++ * as frame durations and DCC format can also be set.
++ */
++struct dc_flip_addrs {
++ struct dc_plane_address address;
++
++ /* TODO: DCC format info */
++ /* TODO: add flip duration for FreeSync */
++};
++
++/*
++ * Optimized flip address update function.
++ *
++ * After this call:
++ * Surface addresses and flip attributes are programmed.
++ * Surface flip occur at next configured time (h_sync or v_sync flip)
++ */
++void dc_flip_surface_addrs(struct dc* dc,
++ const struct dc_surface *const surfaces[],
++ struct dc_flip_addrs flip_addrs[],
++ uint32_t count);
++
++/*
++ * Set up surface attributes and associate to a target
++ * The surfaces parameter is an absolute set of all surface active for the target.
++ * If no surfaces are provided, the target will be blanked; no memory read.
++ * Any flip related attribute changes must be done through this interface.
++ *
++ * After this call:
++ * Surfaces attributes are programmed and configured to be composed into target.
++ * This does not trigger a flip. No surface address is programmed.
++ */
++bool dc_commit_surfaces_to_target(
++ struct dc *dc,
++ struct dc_surface *dc_surfaces[],
++ uint8_t surface_count,
++ struct dc_target *dc_target);
++
++/*******************************************************************************
++ * Target Interfaces
++ ******************************************************************************/
++#define MAX_STREAM_NUM 1
++
++struct dc_target {
++ uint32_t temp;
++ const struct dc_stream *streams[MAX_STREAM_NUM];
++};
++
++/*
++ * Target status is returned from dc_target_get_status in order to get the
++ * the IRQ source, current frame counter and currently attached surfaces.
++ */
++struct dc_target_status {
++ enum dc_irq_source page_flip_src;
++ enum dc_irq_source v_update_src;
++ uint32_t cur_frame_count;
++ const struct dc_surface *surfaces[MAX_SURFACE_NUM];
++ uint8_t surface_count;
++};
++
++struct dc_target *dc_create_target_for_streams(
++ struct dc_stream *dc_streams[],
++ uint8_t stream_count);
++
++/*
++ * Get the current target status.
++ */
++const struct dc_target_status *dc_target_get_status(
++ const struct dc_target* dc_target);
++
++void dc_target_retain(struct dc_target *dc_target);
++void dc_target_release(struct dc_target *dc_target);
++void dc_target_log(
++ const struct dc_target *dc_target,
++ struct dal_logger *dal_logger,
++ enum log_major log_major,
++ enum log_minor log_minor);
++
++uint8_t dc_get_current_target_count(const struct dc *dc);
++struct dc_target *dc_get_target_at_index(const struct dc *dc, uint8_t i);
++
++bool dc_target_is_connected_to_sink(
++ const struct dc_target *dc_target,
++ const struct dc_sink *dc_sink);
++
++uint8_t dc_target_get_link_index(const struct dc_target *dc_target);
++uint8_t dc_target_get_controller_id(const struct dc_target *dc_target);
++
++uint32_t dc_target_get_vblank_counter(const struct dc_target *dc_target);
++enum dc_irq_source dc_target_get_irq_src(
++ const struct dc_target *dc_target, const enum irq_type irq_type);
++
++void dc_target_enable_memory_requests(struct dc_target *target);
++void dc_target_disable_memory_requests(struct dc_target *target);
++
++/*
++ * Structure to store surface/target associations for validation
++ */
++struct dc_validation_set {
++ const struct dc_target *target;
++ const struct dc_surface *surfaces[4];
++ uint8_t surface_count;
++};
++
++/*
++ * This function takes a set of resources and checks that they are cofunctional.
++ *
++ * After this call:
++ * No hardware is programmed for call. Only validation is done.
++ */
++bool dc_validate_resources(
++ const struct dc *dc,
++ const struct dc_validation_set set[],
++ uint8_t set_count);
++
++/*
++ * Set up streams and links associated to targets to drive sinks
++ * The targets parameter is an absolute set of all active targets.
++ *
++ * After this call:
++ * Phy, Encoder, Timing Generator are programmed and enabled.
++ * New targets are enabled with blank stream; no memory read.
++ */
++bool dc_commit_targets(
++ struct dc *dc,
++ struct dc_target *targets[],
++ uint8_t target_count);
++
++/*******************************************************************************
++ * Stream Interfaces
++ ******************************************************************************/
++struct dc_stream {
++ const struct dc_sink *sink;
++ struct dc_crtc_timing timing;
++
++ struct rect src; /* viewport in target space*/
++ struct rect dst; /* stream addressable area */
++
++ struct audio_info audio_info;
++
++ /* TODO: dithering */
++ /* TODO: transfer function (CSC/regamma/gamut remap) */
++ /* TODO: custom INFO packets */
++ /* TODO: DRR/Freesync parameters */
++ /* TODO: ABM info (DMCU) */
++ /* TODO: PSR info */
++ /* TODO: CEA VIC */
++};
++
++/**
++ * Create a new default stream for the requested sink
++ */
++struct dc_stream *dc_create_stream_for_sink(const struct dc_sink *dc_sink);
++
++void dc_stream_retain(struct dc_stream *dc_stream);
++void dc_stream_release(struct dc_stream *dc_stream);
++
++/*******************************************************************************
++ * Link Interfaces
++ ******************************************************************************/
++
++/*
++ * A link contains one or more sinks and their connected status.
++ * The currently active signal type (HDMI, DP-SST, DP-MST) is also reported.
++ */
++struct dc_link {
++ const struct dc_sink *sink[MAX_SINKS_PER_LINK]; /* TODO: multiple sink support for MST */
++ unsigned int sink_count;
++ enum dc_connection_type type;
++ enum signal_type connector_signal;
++ enum dc_irq_source irq_source_hpd;
++ enum dc_irq_source irq_source_hpd_rx;/* aka DP Short Pulse */
++};
++
++/*
++ * Return an enumerated dc_link. dc_link order is constant and determined at
++ * boot time. They cannot be created or destroyed.
++ * Use dc_get_caps() to get number of links.
++ */
++const struct dc_link *dc_get_link_at_index(struct dc *dc, uint32_t link_index);
++
++/* Return id of physical connector represented by a dc_link at link_index.*/
++const struct graphics_object_id dc_get_link_id_at_index(
++ struct dc *dc, uint32_t link_index);
++
++/* Set backlight level of an embedded panel (eDP, LVDS). */
++bool dc_link_set_backlight_level(const struct dc_link *dc_link, uint32_t level);
++
++/* Request DC to detect if there is a Panel connected. */
++void dc_link_detect(const struct dc_link *dc_link);
++
++/* Notify DC about DP RX Interrupt (aka Short Pulse Interrupt).
++ * Return:
++ * true - Downstream port status changed. DM should call DC to do the
++ * detection.
++ * false - no change in Downstream port status. No further action required
++ * from DM. */
++bool dc_link_handle_hpd_rx_irq(const struct dc_link *dc_link);
++
++bool dc_link_add_sink(
++ struct dc_link *link,
++ struct dc_sink *sink
++ );
++
++void dc_link_remove_sink(struct dc_link *link, const struct dc_sink *sink);
++
++/*******************************************************************************
++ * Sink Interfaces - A sink corresponds to a display output device
++ ******************************************************************************/
++
++/*
++ * The sink structure contains EDID and other display device properties
++ */
++struct dc_sink {
++ enum signal_type sink_signal;
++ struct dc_edid dc_edid; /* raw edid */
++ struct dc_edid_caps edid_caps; /* parse display caps */
++};
++
++void dc_sink_retain(const struct dc_sink *sink);
++void dc_sink_release(const struct dc_sink *sink);
++
++const struct audio **dc_get_audios(struct dc *dc);
++
++struct sink_init_data {
++ enum signal_type sink_signal;
++ struct dc_link *link;
++ uint32_t dongle_max_pix_clk;
++ bool converter_disable_audio;
++};
++
++struct dc_sink *sink_create(const struct sink_init_data *init_params);
++
++
++/*******************************************************************************
++ * Cursor interfaces - To manages the cursor within a target
++ ******************************************************************************/
++struct dc_cursor {
++ struct dc_plane_address address;
++ struct dc_cursor_attributes attributes;
++};
++
++/*
++ * Create a new cursor with default values for a given target.
++ */
++struct dc_cursor *dc_create_cursor_for_target(
++ const struct dc *dc,
++ struct dc_target *dc_target);
++
++/**
++ * Commit cursor attribute changes such as pixel format and dimensions and
++ * surface address.
++ *
++ * After this call:
++ * Cursor address and format is programmed to the new values.
++ * Cursor position is unmodified.
++ */
++bool dc_commit_cursor(
++ const struct dc *dc,
++ struct dc_cursor *cursor);
++
++/*
++ * Optimized cursor position update
++ *
++ * After this call:
++ * Cursor position will be programmed as well as enable/disable bit.
++ */
++bool dc_set_cursor_position(
++ const struct dc *dc,
++ struct dc_cursor *cursor,
++ struct dc_cursor_position *pos);
++
++
++
++/*******************************************************************************
++ * Interrupt interfaces
++ ******************************************************************************/
++enum dc_irq_source dc_interrupt_to_irq_source(
++ struct dc *dc,
++ uint32_t src_id,
++ uint32_t ext_id);
++void dc_interrupt_set(const struct dc *dc, enum dc_irq_source src, bool enable);
++void dc_interrupt_ack(struct dc *dc, enum dc_irq_source src);
++const enum dc_irq_source dc_get_hpd_irq_source_at_index(
++ struct dc *dc, uint32_t link_index);
++const struct dc_target *dc_get_target_on_irq_source(
++ const struct dc *dc,
++ enum dc_irq_source src);
++
++
++/*******************************************************************************
++ * Power Interfaces
++ ******************************************************************************/
++
++void dc_set_power_state(
++ struct dc *dc,
++ enum dc_acpi_cm_power_state power_state,
++ enum dc_video_power_state video_power_state);
++void dc_resume(const struct dc *dc);
++
++/*******************************************************************************
++ * DDC Interfaces
++ ******************************************************************************/
++
++const struct ddc_service *dc_get_ddc_at_index(
++ struct dc *dc, uint32_t link_index);
++const struct dc_ddc* dc_get_ddc_from_sink(const struct dc_sink* sink);
++const struct dc_ddc* dc_get_ddc_from_link(const struct dc_link* link);
++bool dc_ddc_query_i2c(const struct dc_ddc* ddc,
++ uint32_t address,
++ uint8_t* write_buf,
++ uint32_t write_size,
++ uint8_t* read_buf,
++ uint32_t read_size);
++bool dc_ddc_dpcd_read(const struct dc_ddc* ddc, uint32_t address,
++ uint8_t* data, uint32_t len);
++bool dc_ddc_dpcd_write(const struct dc_ddc* ddc, uint32_t address,
++ const uint8_t* data, uint32_t len);
++
++
++
++bool dc_read_dpcd(
++ struct dc *dc,
++ uint32_t link_index,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size);
++
++bool dc_write_dpcd(
++ struct dc *dc,
++ uint32_t link_index,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size);
++
++
++#endif /* DC_INTERFACE_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dc_helpers.h b/drivers/gpu/drm/amd/dal/dc/dc_helpers.h
+new file mode 100644
+index 0000000..c06eb8c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dc_helpers.h
+@@ -0,0 +1,75 @@
++/*
++ * 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
++ *
++ */
++
++/**
++ * This file defines helper functions provided by the Display Manager to
++ * Display Core.
++ */
++#ifndef __DC_HELPERS__
++#define __DC_HELPERS__
++
++#include "dc_types.h"
++#include "dc.h"
++
++enum dc_edid_status dc_helpers_parse_edid_caps(
++ struct dc_context *ctx,
++ const struct dc_edid *edid,
++ struct dc_edid_caps *edid_caps);
++
++/*
++ * Writes payload allocation table in immediate downstream device.
++ */
++bool dc_helpers_dp_mst_write_payload_allocation_table(
++ struct dc_context *ctx,
++ const struct dc_sink *sink,
++ struct dp_mst_stream_allocation *alloc_entity,
++ bool enable);
++
++/*
++ * Polls for ACT (allocation change trigger) handled and
++ */
++bool dc_helpers_dp_mst_poll_for_allocation_change_trigger(
++ struct dc_context *ctx,
++ const struct dc_sink *sink);
++/*
++ * Sends ALLOCATE_PAYLOAD message.
++ */
++bool dc_helpers_dp_mst_send_payload_allocation(
++ struct dc_context *ctx,
++ const struct dc_sink *sink,
++ bool enable);
++
++void dc_helpers_dp_mst_handle_mst_hpd_rx_irq(
++ void *param);
++
++bool dc_helpers_dp_mst_start_top_mgr(
++ struct dc_context *ctx,
++ const struct dc_link *link);
++
++void dc_helpers_dp_mst_stop_top_mgr(
++ struct dc_context *ctx,
++ const struct dc_link *link);
++
++#endif /* __DC_HELPERS__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dc_services.h b/drivers/gpu/drm/amd/dal/dc/dc_services.h
+new file mode 100644
+index 0000000..f430864
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dc_services.h
+@@ -0,0 +1,174 @@
++/*
++ * Copyright 2015 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
++ *
++ */
++
++/**
++ * This file defines external dependencies of Display Core.
++ */
++
++#ifndef __DC_SERVICES_H__
++#define __DC_SERVICES_H__
++
++/* TODO: remove when DC is complete. */
++#include "dal_services_types.h"
++#include "include/dal_types.h"
++#include "logger_interface.h"
++#include "irq_types.h"
++#include "dal_power_interface_types.h"
++
++
++/* if the pointer is not NULL, the allocated memory is zeroed */
++void *dc_service_alloc(struct dc_context *ctx, uint32_t size);
++
++void dc_service_free(struct dc_context *ctx, void *p);
++
++void dc_service_memset(void *p, int32_t c, uint32_t count);
++
++void dc_service_memmove(void *dst, const void *src, uint32_t size);
++
++/* TODO: rename to dc_memcmp*/
++int32_t dal_memcmp(const void *p1, const void *p2, uint32_t count);
++
++/* TODO: remove when windows_dm will start registering for IRQs */
++irq_handler_idx dc_service_register_interrupt(
++ struct dc_context *ctx,
++ struct dc_interrupt_params *int_params,
++ interrupt_handler ih,
++ void *handler_args);
++
++/* TODO: remove when windows_dm will start registering for IRQs */
++void dc_service_unregister_interrupt(
++ struct dc_context *ctx,
++ enum dc_irq_source irq_source,
++ irq_handler_idx handler_idx);
++
++/**************************************
++ * Calls to Power Play (PP) component
++ **************************************/
++
++/* DAL calls this function to notify PP about clocks it needs for the Mode Set.
++ * This is done *before* it changes DCE clock.
++ *
++ * If required clock is higher than current, then PP will increase the voltage.
++ *
++ * If required clock is lower than current, then PP will defer reduction of
++ * voltage until the call to dc_service_pp_post_dce_clock_change().
++ *
++ * \input - Contains clocks needed for Mode Set.
++ *
++ * \output - Contains clocks adjusted by PP which DAL should use for Mode Set.
++ * Valid only if function returns zero.
++ *
++ * \returns true - call is successful
++ * false - call failed
++ */
++bool dc_service_pp_pre_dce_clock_change(
++ struct dc_context *ctx,
++ struct dal_to_power_info *input,
++ struct power_to_dal_info *output);
++
++struct dc_pp_display_configuration {
++ bool nb_pstate_switch_disable;/* controls NB PState switch */
++ bool cpu_cc6_disable; /* controls CPU CState switch ( on or off) */
++ bool cpu_pstate_disable;
++ uint32_t cpu_pstate_separation_time;
++};
++
++/* DAL calls this function to notify PP about completion of Mode Set.
++ * For PP it means that current DCE clocks are those which were returned
++ * by dc_service_pp_pre_dce_clock_change(), in the 'output' parameter.
++ *
++ * If the clocks are higher than before, then PP does nothing.
++ *
++ * If the clocks are lower than before, then PP reduces the voltage.
++ *
++ * \returns true - call is successful
++ * false - call failed
++ */
++bool dc_service_pp_post_dce_clock_change(
++ struct dc_context *ctx,
++ const struct dc_pp_display_configuration *pp_display_cfg);
++
++/* The returned clocks range are 'static' system clocks which will be used for
++ * mode validation purposes.
++ *
++ * \returns true - call is successful
++ * false - call failed
++ */
++bool dc_service_get_system_clocks_range(
++ struct dc_context *ctx,
++ struct dal_system_clock_range *sys_clks);
++
++/* for future use */
++bool dc_service_pp_set_display_clock(
++ struct dc_context *ctx,
++ struct dal_to_power_dclk *dclk);
++
++void dc_service_sleep_in_milliseconds(struct dc_context *ctx, uint32_t milliseconds);
++
++/* end of power component calls */
++
++void dc_service_delay_in_microseconds(struct dc_context *ctx, uint32_t microseconds);
++
++/*
++ *
++ * general debug capabilities
++ *
++ */
++#if defined(CONFIG_DEBUG_KERNEL) || defined(CONFIG_DEBUG_DRIVER)
++
++#if defined(CONFIG_HAVE_KGDB) || defined(CONFIG_KGDB)
++#define ASSERT_CRITICAL(expr) do { \
++ if (WARN_ON(!(expr))) { \
++ kgdb_breakpoint(); \
++ } \
++} while (0)
++#else
++#define ASSERT_CRITICAL(expr) do { \
++ if (WARN_ON(!(expr))) { \
++ ; \
++ } \
++} while (0)
++#endif
++
++#if defined(CONFIG_DEBUG_KERNEL_DAL)
++#define ASSERT(expr) ASSERT_CRITICAL(expr)
++
++#else
++#define ASSERT(expr) WARN_ON(!(expr))
++#endif
++
++#define BREAK_TO_DEBUGGER() ASSERT(0)
++
++#else
++
++#define ASSERT_CRITICAL(expr) do {if (expr)/* Do nothing */; } while (0)
++
++#define ASSERT(expr) do {if (expr)/* Do nothing */; } while (0)
++
++#define BREAK_TO_DEBUGGER() do {} while (0)
++
++#endif /* CONFIG_DEBUG_KERNEL || CONFIG_DEBUG_DRIVER */
++
++#endif /* __DC_SERVICES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dc_temp.h b/drivers/gpu/drm/amd/dal/dc/dc_temp.h
+new file mode 100644
+index 0000000..b609deb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dc_temp.h
+@@ -0,0 +1,508 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#ifndef DC_TEMP_H_
++#define DC_TEMP_H_
++
++#include "dc_types.h"
++
++#define MAX_SURFACE_NUM 2
++
++enum clamping_range {
++ CLAMPING_FULL_RANGE = 0, /* No Clamping */
++ CLAMPING_LIMITED_RANGE_8BPC, /* 8 bpc: Clamping 1 to FE */
++ CLAMPING_LIMITED_RANGE_10BPC, /* 10 bpc: Clamping 4 to 3FB */
++ CLAMPING_LIMITED_RANGE_12BPC, /* 12 bpc: Clamping 10 to FEF */
++ /* Use programmable clampping value on FMT_CLAMP_COMPONENT_R/G/B. */
++ CLAMPING_LIMITED_RANGE_PROGRAMMABLE
++};
++
++struct clamping_and_pixel_encoding_params {
++ enum dc_pixel_encoding pixel_encoding; /* Pixel Encoding */
++ enum clamping_range clamping_level; /* Clamping identifier */
++ enum dc_color_depth c_depth; /* Deep color use. */
++};
++
++struct bit_depth_reduction_params {
++ struct {
++ /* truncate/round */
++ /* trunc/round enabled*/
++ uint32_t TRUNCATE_ENABLED:1;
++ /* 2 bits: 0=6 bpc, 1=8 bpc, 2 = 10bpc*/
++ uint32_t TRUNCATE_DEPTH:2;
++ /* truncate or round*/
++ uint32_t TRUNCATE_MODE:1;
++
++ /* spatial dither */
++ /* Spatial Bit Depth Reduction enabled*/
++ uint32_t SPATIAL_DITHER_ENABLED:1;
++ /* 2 bits: 0=6 bpc, 1 = 8 bpc, 2 = 10bpc*/
++ uint32_t SPATIAL_DITHER_DEPTH:2;
++ /* 0-3 to select patterns*/
++ uint32_t SPATIAL_DITHER_MODE:2;
++ /* Enable RGB random dithering*/
++ uint32_t RGB_RANDOM:1;
++ /* Enable Frame random dithering*/
++ uint32_t FRAME_RANDOM:1;
++ /* Enable HighPass random dithering*/
++ uint32_t HIGHPASS_RANDOM:1;
++
++ /* temporal dither*/
++ /* frame modulation enabled*/
++ uint32_t FRAME_MODULATION_ENABLED:1;
++ /* same as for trunc/spatial*/
++ uint32_t FRAME_MODULATION_DEPTH:2;
++ /* 2/4 gray levels*/
++ uint32_t TEMPORAL_LEVEL:1;
++ uint32_t FRC25:2;
++ uint32_t FRC50:2;
++ uint32_t FRC75:2;
++ } flags;
++
++ uint32_t r_seed_value;
++ uint32_t b_seed_value;
++ uint32_t g_seed_value;
++};
++
++enum pipe_gating_control {
++ PIPE_GATING_CONTROL_DISABLE = 0,
++ PIPE_GATING_CONTROL_ENABLE,
++ PIPE_GATING_CONTROL_INIT
++};
++
++enum surface_color_space {
++ SURFACE_COLOR_SPACE_SRGB = 0x0000,
++ SURFACE_COLOR_SPACE_BT601 = 0x0001,
++ SURFACE_COLOR_SPACE_BT709 = 0x0002,
++ SURFACE_COLOR_SPACE_XVYCC_BT601 = 0x0004,
++ SURFACE_COLOR_SPACE_XVYCC_BT709 = 0x0008,
++ SURFACE_COLOR_SPACE_XRRGB = 0x0010
++};
++
++enum {
++ MAX_LANES = 2,
++ MAX_COFUNC_PATH = 6,
++ LAYER_INDEX_PRIMARY = -1,
++};
++
++/* Scaling format */
++enum scaling_transformation {
++ SCALING_TRANSFORMATION_UNINITIALIZED,
++ SCALING_TRANSFORMATION_IDENTITY = 0x0001,
++ SCALING_TRANSFORMATION_CENTER_TIMING = 0x0002,
++ SCALING_TRANSFORMATION_FULL_SCREEN_SCALE = 0x0004,
++ SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE = 0x0008,
++ SCALING_TRANSFORMATION_DAL_DECIDE = 0x0010,
++ SCALING_TRANSFORMATION_INVALID = 0x80000000,
++
++ /* Flag the first and last */
++ SCALING_TRANSFORMATION_BEGING = SCALING_TRANSFORMATION_IDENTITY,
++ SCALING_TRANSFORMATION_END =
++ SCALING_TRANSFORMATION_PRESERVE_ASPECT_RATIO_SCALE
++};
++
++struct view_stereo_3d_support {
++ enum view_3d_format format;
++ struct {
++ uint32_t CLONE_MODE:1;
++ uint32_t SCALING:1;
++ uint32_t SINGLE_FRAME_SW_PACKED:1;
++ } features;
++};
++
++struct plane_colorimetry {
++ enum surface_color_space color_space;
++ bool limited_range;
++};
++
++enum tiling_mode {
++ TILING_MODE_INVALID,
++ TILING_MODE_LINEAR,
++ TILING_MODE_TILED,
++ TILING_MODE_COUNT
++};
++
++struct view_position {
++ uint32_t x;
++ uint32_t y;
++};
++
++union plane_tiling_info {
++
++ struct {
++ /* Specifies the number of memory banks for tiling
++ * purposes.
++ * Only applies to 2D and 3D tiling modes.
++ * POSSIBLE VALUES: 2,4,8,16
++ */
++ uint32_t NUM_BANKS:5;
++ /* Specifies the number of tiles in the x direction
++ * to be incorporated into the same bank.
++ * Only applies to 2D and 3D tiling modes.
++ * POSSIBLE VALUES: 1,2,4,8
++ */
++ uint32_t BANK_WIDTH:4;
++ /* Specifies the number of tiles in the y direction to
++ * be incorporated into the same bank.
++ * Only applies to 2D and 3D tiling modes.
++ * POSSIBLE VALUES: 1,2,4,8
++ */
++ uint32_t BANK_HEIGHT:4;
++ /* Specifies the macro tile aspect ratio. Only applies
++ * to 2D and 3D tiling modes.
++ */
++ uint32_t TILE_ASPECT:3;
++ /* Specifies the number of bytes that will be stored
++ * contiguously for each tile.
++ * If the tile data requires more storage than this
++ * amount, it is split into multiple slices.
++ * This field must not be larger than
++ * GB_ADDR_CONFIG.DRAM_ROW_SIZE.
++ * Only applies to 2D and 3D tiling modes.
++ * For color render targets, TILE_SPLIT >= 256B.
++ */
++ uint32_t TILE_SPLIT:3;
++ /* Specifies the addressing within a tile.
++ * 0x0 - DISPLAY_MICRO_TILING
++ * 0x1 - THIN_MICRO_TILING
++ * 0x2 - DEPTH_MICRO_TILING
++ * 0x3 - ROTATED_MICRO_TILING
++ */
++ uint32_t TILE_MODE:2;
++ /* Specifies the number of pipes and how they are
++ * interleaved in the surface.
++ * Refer to memory addressing document for complete
++ * details and constraints.
++ */
++ uint32_t PIPE_CONFIG:5;
++ /* Specifies the tiling mode of the surface.
++ * THIN tiles use an 8x8x1 tile size.
++ * THICK tiles use an 8x8x4 tile size.
++ * 2D tiling modes rotate banks for successive Z slices
++ * 3D tiling modes rotate pipes and banks for Z slices
++ * Refer to memory addressing document for complete
++ * details and constraints.
++ */
++ uint32_t ARRAY_MODE:4;
++ } grph;
++
++
++ struct {
++ /*possible values: 2,4,8,16*/
++ uint32_t NUM_BANKS:5;
++ /*must use enum video_array_mode*/
++ uint32_t ARRAY_MODE:4;
++ /*must use enum addr_pipe_config*/
++ uint32_t PIPE_CONFIG:5;
++ /*possible values 1,2,4,8 */
++ uint32_t BANK_WIDTH_LUMA:4;
++ /*possible values 1,2,4,8 */
++ uint32_t BANK_HEIGHT_LUMA:4;
++ /*must use enum macro_tile_aspect*/
++ uint32_t TILE_ASPECT_LUMA:3;
++ /*must use enum tile_split*/
++ uint32_t TILE_SPLIT_LUMA:3;
++ /*must use micro_tile_mode */
++ uint32_t TILE_MODE_LUMA:2;
++ /*possible values: 1,2,4,8*/
++ uint32_t BANK_WIDTH_CHROMA:4;
++ /*possible values: 1,2,4,8*/
++ uint32_t BANK_HEIGHT_CHROMA:4;
++ /*must use enum macro_tile_aspect*/
++ uint32_t TILE_ASPECT_CHROMA:3;
++ /*must use enum tile_split*/
++ uint32_t TILE_SPLIT_CHROMA:3;
++ /*must use enum micro_tile_mode*/
++ uint32_t TILE_MODE_CHROMA:2;
++
++ } video;
++
++ uint64_t value;
++};
++
++union plane_size {
++ /* Grph or Video will be selected
++ * based on format above:
++ * Use Video structure if
++ * format >= DalPixelFormat_VideoBegin
++ * else use Grph structure
++ */
++ struct {
++ struct rect surface_size;
++ /* Graphic surface pitch in pixels.
++ * In LINEAR_GENERAL mode, pitch
++ * is 32 pixel aligned.
++ */
++ uint32_t surface_pitch;
++ } grph;
++
++ struct {
++ struct rect luma_size;
++ /* Graphic surface pitch in pixels.
++ * In LINEAR_GENERAL mode, pitch is
++ * 32 pixel aligned.
++ */
++ uint32_t luma_pitch;
++
++ struct rect chroma_size;
++ /* Graphic surface pitch in pixels.
++ * In LINEAR_GENERAL mode, pitch is
++ * 32 pixel aligned.
++ */
++ uint32_t chroma_pitch;
++ } video;
++};
++
++/* Windows only */
++enum dc_scaling_transform {
++ SCL_TRANS_CENTERED = 0,
++ SCL_TRANS_ASPECT_RATIO,
++ SCL_TRANS_FULL
++};
++
++struct dev_c_lut {
++ uint8_t red;
++ uint8_t green;
++ uint8_t blue;
++};
++
++struct dev_c_lut16 {
++ uint16_t red;
++ uint16_t green;
++ uint16_t blue;
++};
++
++enum gamma_ramp_type {
++ GAMMA_RAMP_UNINITIALIZED = 0,
++ GAMMA_RAMP_DEFAULT,
++ GAMMA_RAMP_RBG256X3X16,
++ GAMMA_RAMP_DXGI_1,
++};
++
++enum surface_type {
++ OVERLAY_SURFACE = 1, GRAPHIC_SURFACE
++};
++
++#define CONST_RGB_GAMMA_VALUE 2400
++
++enum {
++ RGB_256X3X16 = 256, DX_GAMMA_RAMP_MAX = 1025
++};
++
++struct gamma_ramp_rgb256x3x16 {
++ uint16_t red[RGB_256X3X16];
++ uint16_t green[RGB_256X3X16];
++ uint16_t blue[RGB_256X3X16];
++};
++
++struct dxgi_rgb {
++ struct fixed32_32 red;
++ struct fixed32_32 green;
++ struct fixed32_32 blue;
++};
++
++struct gamma_ramp_dxgi_1 {
++ struct dxgi_rgb scale;
++ struct dxgi_rgb offset;
++ struct dxgi_rgb gamma_curve[DX_GAMMA_RAMP_MAX];
++};
++
++struct gamma_ramp {
++ enum gamma_ramp_type type;
++ union {
++ struct gamma_ramp_rgb256x3x16 gamma_ramp_rgb256x3x16;
++ struct gamma_ramp_dxgi_1 gamma_ramp_dxgi1;
++ };
++ uint32_t size;
++};
++
++struct regamma_ramp {
++ uint16_t gamma[RGB_256X3X16 * 3];
++};
++
++/* used by Graphics and Overlay gamma */
++struct gamma_coeff {
++ int32_t gamma[3];
++ int32_t a0[3]; /* index 0 for red, 1 for green, 2 for blue */
++ int32_t a1[3];
++ int32_t a2[3];
++ int32_t a3[3];
++};
++
++struct regamma_lut {
++ union {
++ struct {
++ uint32_t GRAPHICS_DEGAMMA_SRGB :1;
++ uint32_t OVERLAY_DEGAMMA_SRGB :1;
++ uint32_t GAMMA_RAMP_ARRAY :1;
++ uint32_t APPLY_DEGAMMA :1;
++ uint32_t RESERVED :28;
++ } bits;
++ uint32_t value;
++ } features;
++
++ union {
++ struct regamma_ramp regamma_ramp;
++ struct gamma_coeff gamma_coeff;
++ };
++};
++
++union gamma_flag {
++ struct {
++ uint32_t config_is_changed :1;
++ uint32_t both_pipe_req :1;
++ uint32_t regamma_update :1;
++ uint32_t gamma_update :1;
++ uint32_t reserved :28;
++ } bits;
++ uint32_t u_all;
++};
++
++enum graphics_regamma_adjust {
++ GRAPHICS_REGAMMA_ADJUST_BYPASS = 0, GRAPHICS_REGAMMA_ADJUST_HW, /* without adjustments */
++ GRAPHICS_REGAMMA_ADJUST_SW /* use adjustments */
++};
++
++enum graphics_gamma_lut {
++ GRAPHICS_GAMMA_LUT_LEGACY = 0, /* use only legacy LUT */
++ GRAPHICS_GAMMA_LUT_REGAMMA, /* use only regamma LUT */
++ GRAPHICS_GAMMA_LUT_LEGACY_AND_REGAMMA /* use legacy & regamma LUT's */
++};
++
++enum graphics_degamma_adjust {
++ GRAPHICS_DEGAMMA_ADJUST_BYPASS = 0, GRAPHICS_DEGAMMA_ADJUST_HW, /*without adjustments */
++ GRAPHICS_DEGAMMA_ADJUST_SW /* use adjustments */
++};
++
++struct gamma_parameters {
++ union gamma_flag flag;
++ enum pixel_format surface_pixel_format; /*OS surface pixel format*/
++ struct regamma_lut regamma;
++
++ enum graphics_regamma_adjust regamma_adjust_type;
++ enum graphics_degamma_adjust degamma_adjust_type;
++
++ enum graphics_gamma_lut selected_gamma_lut;
++
++ bool disable_adjustments;
++
++ /* here we grow with parameters if necessary */
++};
++
++struct pixel_format_support {
++ bool INDEX8 :1;
++ bool RGB565 :1;
++ bool ARGB8888 :1;
++ bool ARGB2101010 :1;
++ bool ARGB2101010_XRBIAS :1;
++ bool FP16 :1;
++};
++
++struct render_mode {
++ struct view view;
++ enum pixel_format pixel_format;
++};
++
++struct refresh_rate {
++ uint32_t field_rate;
++ bool INTERLACED :1;
++ bool VIDEO_OPTIMIZED_RATE :1;
++};
++
++struct stereo_3d_view {
++ enum view_3d_format view_3d_format;
++ union {
++ uint32_t raw;
++ struct /*stereo_3d_view_flags*/
++ {
++ bool SINGLE_FRAME_SW_PACKED :1;
++ bool EXCLUSIVE_3D :1;
++ } bits;
++ } flags;
++};
++
++enum solution_importance {
++ SOLUTION_IMPORTANCE_PREFERRED = 1,
++ /* Means we want to use this solution
++ * even in wide topology configurations*/
++ SOLUTION_IMPORTANCE_SAFE,
++ SOLUTION_IMPORTANCE_UNSAFE,
++ SOLUTION_IMPORTANCE_DEFAULT
++/* Temporary state , means Solution object
++ * should define importance by itself
++ */
++};
++
++struct solution {
++ const struct dc_mode_timing *dc_mode_timing;
++ enum solution_importance importance;
++ bool is_custom_mode;
++ uint32_t scl_support[NUM_PIXEL_FORMATS];
++ /* bit vector of the scaling that can be supported on the timing */
++ uint32_t scl_support_guaranteed[NUM_PIXEL_FORMATS];
++ /* subset of m_sclSupport that can be guaranteed supported */
++};
++
++enum timing_select {
++ TIMING_SELECT_DEFAULT,
++ TIMING_SELECT_NATIVE_ONLY,
++ TIMING_SELECT_PRESERVE_ASPECT
++};
++
++enum downscale_state {
++ DOWNSCALESTATE_DEFAULT, // Disabled, but not user selected
++ DOWNSCALESTATE_DISABLED, // User disabled through CCC
++ DOWNSCALESTATE_ENABLED // User enabled through CCC
++};
++struct scaling_support {
++ bool IDENTITY :1;
++ bool FULL_SCREEN_SCALE :1;
++ bool PRESERVE_ASPECT_RATIO_SCALE :1;
++ bool CENTER_TIMING :1;
++};
++
++
++/* TODO: combine the two cursor functions into one to make cursor
++ * programming resistant to changes in OS call sequence. */
++bool dc_target_set_cursor_attributes(
++ struct dc_target *dc_target,
++ const struct dc_cursor_attributes *attributes);
++
++bool dc_target_set_cursor_position(
++ struct dc_target *dc_target,
++ const struct dc_cursor_position *position);
++
++/******************************************************************************
++ * TODO: these definitions only for Timing Sync feature bring-up. Remove
++ * when the feature is complete.
++ *****************************************************************************/
++
++#define MAX_TARGET_NUM 6
++
++void dc_print_sync_report(
++ const struct dc *dc);
++
++/******************************************************************************/
++
++#endif /* DC_TEMP_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dc_types.h b/drivers/gpu/drm/amd/dal/dc/dc_types.h
+new file mode 100644
+index 0000000..b6526e9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dc_types.h
+@@ -0,0 +1,677 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#ifndef DC_TYPES_H_
++#define DC_TYPES_H_
++
++#include "fixed32_32.h"
++#include "fixed31_32.h"
++#include "irq_types.h"
++
++/* forward declarations */
++struct dc;
++struct dc_surface;
++struct dc_target;
++struct dc_stream;
++struct dc_link;
++struct dc_sink;
++struct dal;
++
++#define MAX_EDID_BUFFER_SIZE 512
++
++/*Displayable pixel format in fb*/
++enum surface_pixel_format {
++ SURFACE_PIXEL_FORMAT_GRPH_BEGIN = 0,
++ /*TOBE REMOVED paletta 256 colors*/
++ SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS =
++ SURFACE_PIXEL_FORMAT_GRPH_BEGIN,
++ /*16 bpp*/
++ SURFACE_PIXEL_FORMAT_GRPH_ARGB1555,
++ /*16 bpp*/
++ SURFACE_PIXEL_FORMAT_GRPH_RGB565,
++ /*32 bpp*/
++ SURFACE_PIXEL_FORMAT_GRPH_ARGB8888,
++ /*32 bpp swaped*/
++ SURFACE_PIXEL_FORMAT_GRPH_BGRA8888,
++
++ SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010,
++ /*swaped*/
++ SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010,
++ /*TOBE REMOVED swaped, XR_BIAS has no differance
++ * for pixel layout than previous and we can
++ * delete this after discusion*/
++ SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS,
++ /*64 bpp */
++ SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616,
++ /*swaped & float*/
++ SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F,
++ /*grow graphics here if necessary */
++
++ SURFACE_PIXEL_FORMAT_VIDEO_BEGIN,
++ SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr =
++ SURFACE_PIXEL_FORMAT_VIDEO_BEGIN,
++ SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb,
++ SURFACE_PIXEL_FORMAT_VIDEO_422_YCb,
++ SURFACE_PIXEL_FORMAT_VIDEO_422_YCr,
++ SURFACE_PIXEL_FORMAT_VIDEO_422_CbY,
++ SURFACE_PIXEL_FORMAT_VIDEO_422_CrY,
++ /*grow 422/420 video here if necessary */
++ SURFACE_PIXEL_FORMAT_VIDEO_444_BEGIN,
++ SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb1555 =
++ SURFACE_PIXEL_FORMAT_VIDEO_444_BEGIN,
++ SURFACE_PIXEL_FORMAT_VIDEO_444_CrYCb565,
++ SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb4444,
++ SURFACE_PIXEL_FORMAT_VIDEO_444_CbYCrA5551,
++ SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb8888,
++ SURFACE_PIXEL_FORMAT_VIDEO_444_ACrYCb2101010,
++ SURFACE_PIXEL_FORMAT_VIDEO_444_CbYCrA1010102
++ /*grow 444 video here if necessary */
++};
++
++
++/* Pixel format */
++enum pixel_format {
++ /*graph*/
++ PIXEL_FORMAT_UNINITIALIZED,
++ PIXEL_FORMAT_INDEX8,
++ PIXEL_FORMAT_RGB565,
++ PIXEL_FORMAT_ARGB8888,
++ PIXEL_FORMAT_ARGB2101010,
++ PIXEL_FORMAT_ARGB2101010_XRBIAS,
++ PIXEL_FORMAT_FP16,
++ /*video*/
++ PIXEL_FORMAT_420BPP12,
++ PIXEL_FORMAT_422BPP16,
++ PIXEL_FORMAT_444BPP16,
++ PIXEL_FORMAT_444BPP32,
++ /*end of pixel format definition*/
++ PIXEL_FORMAT_INVALID,
++
++ PIXEL_FORMAT_GRPH_BEGIN = PIXEL_FORMAT_INDEX8,
++ PIXEL_FORMAT_GRPH_END = PIXEL_FORMAT_FP16,
++ PIXEL_FORMAT_VIDEO_BEGIN = PIXEL_FORMAT_420BPP12,
++ PIXEL_FORMAT_VIDEO_END = PIXEL_FORMAT_444BPP32,
++ PIXEL_FORMAT_UNKNOWN
++};
++
++enum plane_stereo_format {
++ PLANE_STEREO_FORMAT_NONE = 0,
++ PLANE_STEREO_FORMAT_SIDE_BY_SIDE = 1,
++ PLANE_STEREO_FORMAT_TOP_AND_BOTTOM = 2,
++ PLANE_STEREO_FORMAT_FRAME_ALTERNATE = 3,
++ PLANE_STEREO_FORMAT_ROW_INTERLEAVED = 5,
++ PLANE_STEREO_FORMAT_COLUMN_INTERLEAVED = 6,
++ PLANE_STEREO_FORMAT_CHECKER_BOARD = 7
++};
++
++/* 3D format for view, typically define how L/R eye surface is arranged within
++ * frames
++ */
++enum view_3d_format {
++ VIEW_3D_FORMAT_NONE = 0,
++ VIEW_3D_FORMAT_FRAME_SEQUENTIAL,
++ VIEW_3D_FORMAT_SIDE_BY_SIDE,
++ VIEW_3D_FORMAT_TOP_AND_BOTTOM,
++ VIEW_3D_FORMAT_COUNT,
++ VIEW_3D_FORMAT_FIRST = VIEW_3D_FORMAT_FRAME_SEQUENTIAL
++};
++
++enum dc_pixel_encoding {
++ PIXEL_ENCODING_UNDEFINED,
++ PIXEL_ENCODING_RGB,
++ PIXEL_ENCODING_YCBCR422,
++ PIXEL_ENCODING_YCBCR444,
++ PIXEL_ENCODING_YCBCR420,
++ PIXEL_ENCODING_COUNT
++};
++
++/* TODO: Find way to calculate number of bits
++ * Please increase if pixel_format enum increases
++ * num from PIXEL_FORMAT_INDEX8 to PIXEL_FORMAT_444BPP32
++ */
++#define NUM_PIXEL_FORMATS 10
++
++
++
++union large_integer {
++ struct {
++ uint32_t low_part;
++ int32_t high_part;
++ };
++
++ struct {
++ uint32_t low_part;
++ int32_t high_part;
++ } u;
++
++ int64_t quad_part;
++};
++
++#define PHYSICAL_ADDRESS_LOC union large_integer
++
++enum dc_edid_connector_type {
++ EDID_CONNECTOR_UNKNOWN = 0,
++ EDID_CONNECTOR_ANALOG = 1,
++ EDID_CONNECTOR_DIGITAL = 10,
++ EDID_CONNECTOR_DVI = 11,
++ EDID_CONNECTOR_HDMIA = 12,
++ EDID_CONNECTOR_MDDI = 14,
++ EDID_CONNECTOR_DISPLAYPORT = 15
++};
++
++enum dc_edid_status {
++ EDID_OK,
++ EDID_BAD_INPUT,
++ EDID_NO_RESPONSE,
++ EDID_BAD_CHECKSUM,
++};
++
++/* audio capability from EDID*/
++struct dc_cea_audio_mode {
++ uint8_t format_code; /* ucData[0] [6:3]*/
++ uint8_t channel_count; /* ucData[0] [2:0]*/
++ uint8_t sample_rate; /* ucData[1]*/
++ union {
++ uint8_t sample_size; /* for LPCM*/
++ /* for Audio Formats 2-8 (Max bit rate divided by 8 kHz)*/
++ uint8_t max_bit_rate;
++ uint8_t audio_codec_vendor_specific; /* for Audio Formats 9-15*/
++ };
++};
++
++struct dc_edid {
++ uint32_t length;
++ uint8_t raw_edid[MAX_EDID_BUFFER_SIZE];
++};
++
++/* When speaker location data block is not available, DEFAULT_SPEAKER_LOCATION
++ * is used. In this case we assume speaker location are: front left, front
++ * right and front center. */
++#define DEFAULT_SPEAKER_LOCATION 5
++
++#define DC_MAX_AUDIO_DESC_COUNT 16
++
++#define AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS 20
++
++struct dc_edid_caps {
++ /* sink identification */
++ uint16_t manufacturer_id;
++ uint16_t product_id;
++ uint32_t serial_number;
++ uint8_t manufacture_week;
++ uint8_t manufacture_year;
++ uint8_t display_name[AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS];
++
++ /* audio caps */
++ uint8_t speaker_flags;
++ uint32_t audio_mode_count;
++ struct dc_cea_audio_mode audio_modes[DC_MAX_AUDIO_DESC_COUNT];
++ uint32_t audio_latency;
++ uint32_t video_latency;
++
++ /*HDMI 2.0 caps*/
++ uint8_t lte_340mcsc_scramble;
++};
++
++struct scaling_taps {
++ uint32_t v_taps;
++ uint32_t h_taps;
++ uint32_t v_taps_c;
++ uint32_t h_taps_c;
++};
++
++struct scaling_ratios {
++ struct fixed31_32 horz;
++ struct fixed31_32 vert;
++ struct fixed31_32 horz_c;
++ struct fixed31_32 vert_c;
++};
++
++struct rect {
++ uint32_t x;
++ uint32_t y;
++ uint32_t width;
++ uint32_t height;
++};
++
++struct view {
++ uint32_t width;
++ uint32_t height;
++};
++
++struct dc_resolution {
++ uint32_t width;
++ uint32_t height;
++};
++
++
++struct dc_mode_flags {
++ /* note: part of refresh rate flag*/
++ uint32_t INTERLACE :1;
++ /* native display timing*/
++ uint32_t NATIVE :1;
++ /* preferred is the recommended mode, one per display */
++ uint32_t PREFERRED :1;
++ /* true if this mode should use reduced blanking timings
++ *_not_ related to the Reduced Blanking adjustment*/
++ uint32_t REDUCED_BLANKING :1;
++ /* note: part of refreshrate flag*/
++ uint32_t VIDEO_OPTIMIZED_RATE :1;
++ /* should be reported to upper layers as mode_flags*/
++ uint32_t PACKED_PIXEL_FORMAT :1;
++ /*< preferred view*/
++ uint32_t PREFERRED_VIEW :1;
++ /* this timing should be used only in tiled mode*/
++ uint32_t TILED_MODE :1;
++ uint32_t DSE_MODE :1;
++ /* Refresh rate divider when Miracast sink is using a
++ different rate than the output display device
++ Must be zero for wired displays and non-zero for
++ Miracast displays*/
++ uint32_t MIRACAST_REFRESH_DIVIDER;
++};
++
++struct dc_crtc_timing_flags {
++ uint32_t INTERLACE :1;
++ uint32_t HSYNC_POSITIVE_POLARITY :1; /* when set to 1,
++ it is positive polarity --reversed with dal1 or video bios define*/
++ uint32_t VSYNC_POSITIVE_POLARITY :1; /* when set to 1,
++ it is positive polarity --reversed with dal1 or video bios define*/
++
++ uint32_t HORZ_COUNT_BY_TWO:1;
++
++ uint32_t EXCLUSIVE_3D :1; /* if this bit set,
++ timing can be driven in 3D format only
++ and there is no corresponding 2D timing*/
++ uint32_t RIGHT_EYE_3D_POLARITY :1; /* 1 - means right eye polarity
++ (right eye = '1', left eye = '0') */
++ uint32_t SUB_SAMPLE_3D :1; /* 1 - means left/right images subsampled
++ when mixed into 3D image. 0 - means summation (3D timing is doubled)*/
++ uint32_t USE_IN_3D_VIEW_ONLY :1; /* Do not use this timing in 2D View,
++ because corresponding 2D timing also present in the list*/
++ uint32_t STEREO_3D_PREFERENCE :1; /* Means this is 2D timing
++ and we want to match priority of corresponding 3D timing*/
++ uint32_t Y_ONLY :1;
++
++ uint32_t YCBCR420 :1; /* TODO: shouldn't need this flag, should be a separate pixel format */
++ uint32_t DTD_COUNTER :5; /* values 1 to 16 */
++
++ /* HDMI 2.0 - Support scrambling for TMDS character
++ * rates less than or equal to 340Mcsc */
++ uint32_t LTE_340MCSC_SCRAMBLE:1;
++
++};
++
++enum dc_timing_standard {
++ TIMING_STANDARD_UNDEFINED,
++ TIMING_STANDARD_DMT,
++ TIMING_STANDARD_GTF,
++ TIMING_STANDARD_CVT,
++ TIMING_STANDARD_CVT_RB,
++ TIMING_STANDARD_CEA770,
++ TIMING_STANDARD_CEA861,
++ TIMING_STANDARD_HDMI,
++ TIMING_STANDARD_TV_NTSC,
++ TIMING_STANDARD_TV_NTSC_J,
++ TIMING_STANDARD_TV_PAL,
++ TIMING_STANDARD_TV_PAL_M,
++ TIMING_STANDARD_TV_PAL_CN,
++ TIMING_STANDARD_TV_SECAM,
++ TIMING_STANDARD_EXPLICIT,
++ /*!< For explicit timings from EDID, VBIOS, etc.*/
++ TIMING_STANDARD_USER_OVERRIDE,
++ /*!< For mode timing override by user*/
++ TIMING_STANDARD_MAX
++};
++
++enum dc_aspect_ratio {
++ ASPECT_RATIO_NO_DATA,
++ ASPECT_RATIO_4_3,
++ ASPECT_RATIO_16_9,
++ ASPECT_RATIO_64_27,
++ ASPECT_RATIO_256_135,
++ ASPECT_RATIO_FUTURE
++};
++
++enum dc_color_depth {
++ COLOR_DEPTH_UNDEFINED,
++ COLOR_DEPTH_666,
++ COLOR_DEPTH_888,
++ COLOR_DEPTH_101010,
++ COLOR_DEPTH_121212,
++ COLOR_DEPTH_141414,
++ COLOR_DEPTH_161616,
++ COLOR_DEPTH_COUNT
++};
++
++enum dc_timing_3d_format {
++ TIMING_3D_FORMAT_NONE,
++ TIMING_3D_FORMAT_FRAME_ALTERNATE, /* No stereosync at all*/
++ TIMING_3D_FORMAT_INBAND_FA, /* Inband Frame Alternate (DVI/DP)*/
++ TIMING_3D_FORMAT_DP_HDMI_INBAND_FA, /* Inband FA to HDMI Frame Pack*/
++ /* for active DP-HDMI dongle*/
++ TIMING_3D_FORMAT_SIDEBAND_FA, /* Sideband Frame Alternate (eDP)*/
++ TIMING_3D_FORMAT_HW_FRAME_PACKING,
++ TIMING_3D_FORMAT_SW_FRAME_PACKING,
++ TIMING_3D_FORMAT_ROW_INTERLEAVE,
++ TIMING_3D_FORMAT_COLUMN_INTERLEAVE,
++ TIMING_3D_FORMAT_PIXEL_INTERLEAVE,
++ TIMING_3D_FORMAT_SIDE_BY_SIDE,
++ TIMING_3D_FORMAT_TOP_AND_BOTTOM,
++ TIMING_3D_FORMAT_SBS_SW_PACKED,
++ /* Side-by-side, packed by application/driver into 2D frame*/
++ TIMING_3D_FORMAT_TB_SW_PACKED,
++ /* Top-and-bottom, packed by application/driver into 2D frame*/
++
++ TIMING_3D_FORMAT_MAX,
++};
++
++enum dc_timing_source {
++ TIMING_SOURCE_UNDEFINED,
++
++ /* explicitly specifed by user, most important*/
++ TIMING_SOURCE_USER_FORCED,
++ TIMING_SOURCE_USER_OVERRIDE,
++ TIMING_SOURCE_CUSTOM,
++ TIMING_SOURCE_EXPLICIT,
++
++ /* explicitly specified by the display device, more important*/
++ TIMING_SOURCE_EDID_CEA_SVD_3D,
++ TIMING_SOURCE_EDID_CEA_SVD_PREFERRED,
++ TIMING_SOURCE_EDID_CEA_SVD_420,
++ TIMING_SOURCE_EDID_DETAILED,
++ TIMING_SOURCE_EDID_ESTABLISHED,
++ TIMING_SOURCE_EDID_STANDARD,
++ TIMING_SOURCE_EDID_CEA_SVD,
++ TIMING_SOURCE_EDID_CVT_3BYTE,
++ TIMING_SOURCE_EDID_4BYTE,
++ TIMING_SOURCE_VBIOS,
++ TIMING_SOURCE_CV,
++ TIMING_SOURCE_TV,
++ TIMING_SOURCE_HDMI_VIC,
++
++ /* implicitly specified by display device, still safe but less important*/
++ TIMING_SOURCE_DEFAULT,
++
++ /* only used for custom base modes */
++ TIMING_SOURCE_CUSTOM_BASE,
++
++ /* these timing might not work, least important*/
++ TIMING_SOURCE_RANGELIMIT,
++ TIMING_SOURCE_OS_FORCED,
++ TIMING_SOURCE_IMPLICIT,
++
++ /* only used by default mode list*/
++ TIMING_SOURCE_BASICMODE,
++
++ TIMING_SOURCE_COUNT
++};
++
++enum dc_timing_support_method {
++ TIMING_SUPPORT_METHOD_UNDEFINED,
++ TIMING_SUPPORT_METHOD_EXPLICIT,
++ TIMING_SUPPORT_METHOD_IMPLICIT,
++ TIMING_SUPPORT_METHOD_NATIVE
++};
++
++struct dc_mode_info {
++ uint32_t pixel_width;
++ uint32_t pixel_height;
++ uint32_t field_rate;
++ /* Vertical refresh rate for progressive modes.
++ * Field rate for interlaced modes.*/
++
++ enum dc_timing_standard timing_standard;
++ enum dc_timing_source timing_source;
++ struct dc_mode_flags flags;
++};
++
++/* TODO: assess necessity*/
++/*scanning type*/
++enum scanning_type {
++ SCANNING_TYPE_NODATA = 0,
++ SCANNING_TYPE_OVERSCAN,
++ SCANNING_TYPE_UNDERSCAN,
++ SCANNING_TYPE_FUTURE,
++ SCANNING_TYPE_UNDEFINED
++};
++
++struct dc_crtc_timing {
++ uint32_t h_total;
++ uint32_t h_border_left;
++ uint32_t h_addressable;
++ uint32_t h_border_right;
++ uint32_t h_front_porch;
++ uint32_t h_sync_width;
++
++ uint32_t v_total;
++ uint32_t v_border_top;
++ uint32_t v_addressable;
++ uint32_t v_border_bottom;
++ uint32_t v_front_porch;
++ uint32_t v_sync_width;
++
++ uint32_t pix_clk_khz;
++
++ uint32_t vic;
++ uint32_t hdmi_vic;
++ enum dc_timing_standard timing_standard;
++ enum dc_timing_3d_format timing_3d_format;
++ enum dc_color_depth display_color_depth;
++ enum dc_pixel_encoding pixel_encoding;
++ enum dc_aspect_ratio aspect_ratio;
++ enum scanning_type scan_type;
++
++ struct dc_crtc_timing_flags flags;
++};
++
++struct dc_mode_timing {
++ struct dc_mode_info mode_info;
++ struct dc_crtc_timing crtc_timing;
++};
++
++/* Rotation angle */
++enum dc_rotation_angle {
++ ROTATION_ANGLE_0 = 0,
++ ROTATION_ANGLE_90,
++ ROTATION_ANGLE_180,
++ ROTATION_ANGLE_270,
++ ROTATION_ANGLE_COUNT
++};
++
++struct dc_cursor_position {
++ uint32_t x;
++ uint32_t y;
++
++ uint32_t x_origin;
++ uint32_t y_origin;
++
++ /*
++ * This parameter indicates whether HW cursor should be enabled
++ */
++ bool enable;
++
++ /*
++ * This parameter indicates whether cursor hot spot should be
++ * programmed
++ */
++ bool hot_spot_enable;
++};
++
++/* This enum is for programming CURSOR_MODE register field. */
++/* What this register should be programmed to depends on */
++/* OS requested cursor shape flags */
++/* and what we stored in the cursor surface. */
++enum dc_cursor_color_format {
++ CURSOR_MODE_MONO,
++ CURSOR_MODE_COLOR_1BIT_AND,
++ CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA,
++ CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA
++};
++
++union dc_cursor_attribute_flags {
++ struct {
++ uint32_t ENABLE_MAGNIFICATION:1;
++ uint32_t INVERSE_TRANSPARENT_CLAMPING:1;
++ uint32_t HORIZONTAL_MIRROR:1;
++ uint32_t VERTICAL_MIRROR:1;
++ uint32_t RESERVED:28;
++ } bits;
++ uint32_t value;
++};
++
++/* This is all the parameters required by DAL in order to */
++/* update the cursor attributes, */
++/* including the new cursor image surface address, size, */
++/* hotspot location, color format, etc. */
++struct dc_cursor_attributes {
++ PHYSICAL_ADDRESS_LOC address;
++
++ /* Width and height should correspond to cursor surface width x heigh */
++ uint32_t width;
++ uint32_t height;
++ uint32_t x_hot;
++ uint32_t y_hot;
++
++ enum dc_cursor_color_format color_format;
++
++ /* In case we support HW Cursor rotation in the future */
++ enum dc_rotation_angle rotation_angle;
++
++ union dc_cursor_attribute_flags attribute_flags;
++
++};
++
++
++enum dc_plane_addr_type {
++ PLN_ADDR_TYPE_GRAPHICS = 0,
++ PLN_ADDR_TYPE_GRPH_STEREO,
++ PLN_ADDR_TYPE_VIDEO_PROGRESSIVE,
++ PLN_ADDR_TYPE_VIDEO_INTERLACED,
++ PLN_ADDR_TYPE_VIDEO_PROGRESSIVE_STEREO,
++ PLN_ADDR_TYPE_VIDEO_INTERLACED_STEREO
++};
++
++struct dc_plane_address {
++ enum dc_plane_addr_type type;
++ union {
++ struct{
++ PHYSICAL_ADDRESS_LOC addr;
++ } grph;
++
++ /*stereo*/
++ struct {
++ PHYSICAL_ADDRESS_LOC left_addr;
++ PHYSICAL_ADDRESS_LOC right_addr;
++ } grph_stereo;
++
++ /*video progressive*/
++ struct {
++ PHYSICAL_ADDRESS_LOC chroma_addr;
++ PHYSICAL_ADDRESS_LOC luma_addr;
++ } video_progressive;
++
++ /*video interlaced*/
++ struct {
++ PHYSICAL_ADDRESS_LOC chroma_addr;
++ PHYSICAL_ADDRESS_LOC luma_addr;
++ PHYSICAL_ADDRESS_LOC chroma_bottom_addr;
++ PHYSICAL_ADDRESS_LOC luma_bottom_addr;
++ } video_interlaced;
++
++ /*video Progressive Stereo*/
++ struct {
++ PHYSICAL_ADDRESS_LOC left_chroma_addr;
++ PHYSICAL_ADDRESS_LOC left_luma_addr;
++ PHYSICAL_ADDRESS_LOC right_chroma_addr;
++ PHYSICAL_ADDRESS_LOC right_luma_addr;
++ } video_progressive_stereo;
++
++ /*video interlaced stereo*/
++ struct {
++ PHYSICAL_ADDRESS_LOC left_chroma_addr;
++ PHYSICAL_ADDRESS_LOC left_luma_addr;
++ PHYSICAL_ADDRESS_LOC left_chroma_bottom_addr;
++ PHYSICAL_ADDRESS_LOC left_luma_bottom_addr;
++
++ PHYSICAL_ADDRESS_LOC right_chroma_addr;
++ PHYSICAL_ADDRESS_LOC right_luma_addr;
++ PHYSICAL_ADDRESS_LOC right_chroma_bottom_addr;
++ PHYSICAL_ADDRESS_LOC right_luma_bottom_addr;
++ } video_interlaced_stereo;
++ };
++};
++
++enum dc_power_state {
++ DC_POWER_STATE_ON = 1,
++ DC_POWER_STATE_STANDBY,
++ DC_POWER_STATE_SUSPEND,
++ DC_POWER_STATE_OFF
++};
++
++/* DC PowerStates */
++enum dc_video_power_state {
++ DC_VIDEO_POWER_UNSPECIFIED = 0,
++ DC_VIDEO_POWER_ON = 1,
++ DC_VIDEO_POWER_STANDBY,
++ DC_VIDEO_POWER_SUSPEND,
++ DC_VIDEO_POWER_OFF,
++ DC_VIDEO_POWER_HIBERNATE,
++ DC_VIDEO_POWER_SHUTDOWN,
++ DC_VIDEO_POWER_ULPS, /* BACO or Ultra-Light-Power-State */
++ DC_VIDEO_POWER_AFTER_RESET,
++ DC_VIDEO_POWER_MAXIMUM
++};
++
++enum dc_acpi_cm_power_state {
++ DC_ACPI_CM_POWER_STATE_D0 = 1,
++ DC_ACPI_CM_POWER_STATE_D1 = 2,
++ DC_ACPI_CM_POWER_STATE_D2 = 4,
++ DC_ACPI_CM_POWER_STATE_D3 = 8
++};
++
++struct view_port_alignment {
++ uint8_t x_width_size_alignment;
++ uint8_t y_height_size_alignment;
++ uint8_t x_start_alignment;
++ uint8_t y_start_alignment;
++};
++
++enum dc_connection_type {
++ dc_connection_none,
++ dc_connection_single,
++ dc_connection_mst_branch,
++ dc_connection_active_dongle
++};
++
++struct dc_csc_adjustments {
++ struct fixed31_32 contrast;
++ struct fixed31_32 saturation;
++ struct fixed31_32 brightness;
++ struct fixed31_32 hue;
++};
++
++#include "dc_temp.h"
++
++#endif /* DC_TYPES_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/Makefile b/drivers/gpu/drm/amd/dal/dc/dce110/Makefile
+new file mode 100644
+index 0000000..5bf9b56
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/Makefile
+@@ -0,0 +1,33 @@
++#
++# Makefile for the 'controller' sub-component of DAL.
++# It provides the control and status of HW CRTC block.
++
++DCE110 = dce110_ipp.o dce110_ipp_cursor.o \
++dce110_ipp_gamma.o dce110_link_encoder.o dce110_opp.o \
++dce110_opp_formatter.o dce110_opp_regamma.o dce110_stream_encoder.o \
++dce110_timing_generator.o dce110_transform.o dce110_transform_gamut.o \
++dce110_transform_scl.o dce110_transform_sclv.o dce110_opp_csc.o\
++dce110_compressor.o dce110_mem_input.o dce110_hw_sequencer.o \
++dce110_resource.o dce110_transform_bit_depth.o
++
++AMD_DAL_DCE110 = $(addprefix $(AMDDALPATH)/dc/dce110/,$(DCE110))
++
++AMD_DAL_FILES += $(AMD_DAL_DCE110)
++
++
++###############################################################################
++# DCE 11x
++###############################################################################
++ifdef 0#CONFIG_DRM_AMD_DAL_DCE11_0
++TG_DCE110 = dce110_ipp.o dce110_ipp_cursor.o \
++dce110_ipp_gamma.o dce110_timing_generator.o dce110_link_encoder.o \
++dce110_opp.o dce110_opp_regamma.o dce110_opp_formatter.o dce110_opp_csc.o \
++dce110_transform.o dce110_transform_gamut.o dce110_transform_bit_depth.o \
++dce110_compressor.o dce110_mem_input.o dce110_hw_sequencer.o dce110_resource.o
++
++AMD_DAL_TG_DCE110 = $(addprefix \
++ $(AMDDALPATH)/dc/dce110/,$(TG_DCE110))
++
++AMD_DAL_FILES += $(AMD_DAL_TG_DCE110)
++endif
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_compressor.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_compressor.c
+new file mode 100644
+index 0000000..7abb790
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_compressor.c
+@@ -0,0 +1,886 @@
++/*
++ * 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 "dal_services.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++#include "gmc/gmc_8_2_sh_mask.h"
++#include "gmc/gmc_8_2_d.h"
++
++#include "include/logger_interface.h"
++#include "include/adapter_service_interface.h"
++
++#include "dce110_compressor.h"
++
++#define DCP_REG(reg)\
++ (reg + cp110->offsets.dcp_offset)
++#define DMIF_REG(reg)\
++ (reg + cp110->offsets.dmif_offset)
++
++static const struct dce110_compressor_reg_offsets reg_offsets[] = {
++{
++ .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .dmif_offset =
++ (mmDMIF_PG0_DPG_PIPE_DPM_CONTROL
++ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
++},
++{
++ .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .dmif_offset =
++ (mmDMIF_PG1_DPG_PIPE_DPM_CONTROL
++ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
++},
++{
++ .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .dmif_offset =
++ (mmDMIF_PG2_DPG_PIPE_DPM_CONTROL
++ - mmDMIF_PG0_DPG_PIPE_DPM_CONTROL),
++}
++};
++
++static const uint32_t dce11_one_lpt_channel_max_resolution = 2560 * 1600;
++
++enum fbc_idle_force {
++ /* Bit 0 - Display registers updated */
++ FBC_IDLE_FORCE_DISPLAY_REGISTER_UPDATE = 0x00000001,
++
++ /* Bit 2 - FBC_GRPH_COMP_EN register updated */
++ FBC_IDLE_FORCE_GRPH_COMP_EN = 0x00000002,
++ /* Bit 3 - FBC_SRC_SEL register updated */
++ FBC_IDLE_FORCE_SRC_SEL_CHANGE = 0x00000004,
++ /* Bit 4 - FBC_MIN_COMPRESSION register updated */
++ FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE = 0x00000008,
++ /* Bit 5 - FBC_ALPHA_COMP_EN register updated */
++ FBC_IDLE_FORCE_ALPHA_COMP_EN = 0x00000010,
++ /* Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated */
++ FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN = 0x00000020,
++ /* Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated */
++ FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF = 0x00000040,
++
++ /* Bit 24 - Memory write to region 0 defined by MC registers. */
++ FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION0 = 0x01000000,
++ /* Bit 25 - Memory write to region 1 defined by MC registers */
++ FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION1 = 0x02000000,
++ /* Bit 26 - Memory write to region 2 defined by MC registers */
++ FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION2 = 0x04000000,
++ /* Bit 27 - Memory write to region 3 defined by MC registers. */
++ FBC_IDLE_FORCE_MEMORY_WRITE_TO_REGION3 = 0x08000000,
++
++ /* Bit 28 - Memory write from any client other than MCIF */
++ FBC_IDLE_FORCE_MEMORY_WRITE_OTHER_THAN_MCIF = 0x10000000,
++ /* Bit 29 - CG statics screen signal is inactive */
++ FBC_IDLE_FORCE_CG_STATIC_SCREEN_IS_INACTIVE = 0x20000000,
++};
++
++static uint32_t lpt_size_alignment(struct dce110_compressor *cp110)
++{
++ /*LPT_ALIGNMENT (in bytes) = ROW_SIZE * #BANKS * # DRAM CHANNELS. */
++ return cp110->base.raw_size * cp110->base.banks_num *
++ cp110->base.dram_channels_num;
++}
++
++static uint32_t lpt_memory_control_config(struct dce110_compressor *cp110,
++ uint32_t lpt_control)
++{
++ /*LPT MC Config */
++ if (cp110->base.options.bits.LPT_MC_CONFIG == 1) {
++ /* POSSIBLE VALUES for LPT NUM_PIPES (DRAM CHANNELS):
++ * 00 - 1 CHANNEL
++ * 01 - 2 CHANNELS
++ * 02 - 4 OR 6 CHANNELS
++ * (Only for discrete GPU, N/A for CZ)
++ * 03 - 8 OR 12 CHANNELS
++ * (Only for discrete GPU, N/A for CZ) */
++ switch (cp110->base.dram_channels_num) {
++ case 2:
++ set_reg_field_value(
++ lpt_control,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_PIPES);
++ break;
++ case 1:
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_PIPES);
++ break;
++ default:
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid LPT NUM_PIPES!!!",
++ __func__);
++ break;
++ }
++
++ /* The mapping for LPT NUM_BANKS is in
++ * GRPH_CONTROL.GRPH_NUM_BANKS register field
++ * Specifies the number of memory banks for tiling
++ * purposes. Only applies to 2D and 3D tiling modes.
++ * POSSIBLE VALUES:
++ * 00 - DCP_GRPH_NUM_BANKS_2BANK: ADDR_SURF_2_BANK
++ * 01 - DCP_GRPH_NUM_BANKS_4BANK: ADDR_SURF_4_BANK
++ * 02 - DCP_GRPH_NUM_BANKS_8BANK: ADDR_SURF_8_BANK
++ * 03 - DCP_GRPH_NUM_BANKS_16BANK: ADDR_SURF_16_BANK */
++ switch (cp110->base.banks_num) {
++ case 16:
++ set_reg_field_value(
++ lpt_control,
++ 3,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_BANKS);
++ break;
++ case 8:
++ set_reg_field_value(
++ lpt_control,
++ 2,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_BANKS);
++ break;
++ case 4:
++ set_reg_field_value(
++ lpt_control,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_BANKS);
++ break;
++ case 2:
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_NUM_BANKS);
++ break;
++ default:
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid LPT NUM_BANKS!!!",
++ __func__);
++ break;
++ }
++
++ /* The mapping is in DMIF_ADDR_CALC.
++ * ADDR_CONFIG_PIPE_INTERLEAVE_SIZE register field for
++ * Carrizo specifies the memory interleave per pipe.
++ * It effectively specifies the location of pipe bits in
++ * the memory address.
++ * POSSIBLE VALUES:
++ * 00 - ADDR_CONFIG_PIPE_INTERLEAVE_256B: 256 byte
++ * interleave
++ * 01 - ADDR_CONFIG_PIPE_INTERLEAVE_512B: 512 byte
++ * interleave
++ */
++ switch (cp110->base.channel_interleave_size) {
++ case 256: /*256B */
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE);
++ break;
++ case 512: /*512B */
++ set_reg_field_value(
++ lpt_control,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_PIPE_INTERLEAVE_SIZE);
++ break;
++ default:
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid LPT INTERLEAVE_SIZE!!!",
++ __func__);
++ break;
++ }
++
++ /* The mapping for LOW_POWER_TILING_ROW_SIZE is in
++ * DMIF_ADDR_CALC.ADDR_CONFIG_ROW_SIZE register field
++ * for Carrizo. Specifies the size of dram row in bytes.
++ * This should match up with NOOFCOLS field in
++ * MC_ARB_RAMCFG (ROW_SIZE = 4 * 2 ^^ columns).
++ * This register DMIF_ADDR_CALC is not used by the
++ * hardware as it is only used for addrlib assertions.
++ * POSSIBLE VALUES:
++ * 00 - ADDR_CONFIG_1KB_ROW: Treat 1KB as DRAM row
++ * boundary
++ * 01 - ADDR_CONFIG_2KB_ROW: Treat 2KB as DRAM row
++ * boundary
++ * 02 - ADDR_CONFIG_4KB_ROW: Treat 4KB as DRAM row
++ * boundary */
++ switch (cp110->base.raw_size) {
++ case 4096: /*4 KB */
++ set_reg_field_value(
++ lpt_control,
++ 2,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ROW_SIZE);
++ break;
++ case 2048:
++ set_reg_field_value(
++ lpt_control,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ROW_SIZE);
++ break;
++ case 1024:
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ROW_SIZE);
++ break;
++ default:
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid LPT ROW_SIZE!!!",
++ __func__);
++ break;
++ }
++ } else {
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: LPT MC Configuration is not provided",
++ __func__);
++ }
++
++ return lpt_control;
++}
++
++
++
++static bool is_source_bigger_than_epanel_size(
++ struct dce110_compressor *cp110,
++ uint32_t source_view_width,
++ uint32_t source_view_height)
++{
++ if (cp110->base.embedded_panel_h_size != 0 &&
++ cp110->base.embedded_panel_v_size != 0 &&
++ ((source_view_width * source_view_height) >
++ (cp110->base.embedded_panel_h_size *
++ cp110->base.embedded_panel_v_size)))
++ return true;
++
++ return false;
++}
++
++static uint32_t align_to_chunks_number_per_line(
++ struct dce110_compressor *cp110,
++ uint32_t pixels)
++{
++ return 256 * ((pixels + 255) / 256);
++}
++
++static void wait_for_fbc_state_changed(
++ struct dce110_compressor *cp110,
++ bool enabled)
++{
++ uint8_t counter = 0;
++ uint32_t addr = mmFBC_STATUS;
++ uint32_t value;
++
++ while (counter < 10) {
++ value = dal_read_reg(cp110->base.ctx, addr);
++ if (get_reg_field_value(
++ value,
++ FBC_STATUS,
++ FBC_ENABLE_STATUS) == enabled)
++ break;
++ dc_service_delay_in_microseconds(cp110->base.ctx, 10);
++ counter++;
++ }
++
++ if (counter == 10) {
++ dal_logger_write(
++ cp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: wait counter exceeded, changes to HW not applied",
++ __func__);
++ }
++}
++
++void dce110_compressor_power_up_fbc(struct compressor *compressor)
++{
++ uint32_t value;
++ uint32_t addr;
++
++ addr = mmFBC_CNTL;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
++ set_reg_field_value(value, 1, FBC_CNTL, FBC_EN);
++ set_reg_field_value(value, 2, FBC_CNTL, FBC_COHERENCY_MODE);
++ if (compressor->options.bits.CLK_GATING_DISABLED == 1) {
++ /* HW needs to do power measurement comparison. */
++ set_reg_field_value(
++ value,
++ 0,
++ FBC_CNTL,
++ FBC_COMP_CLK_GATE_EN);
++ }
++ dal_write_reg(compressor->ctx, addr, value);
++
++ addr = mmFBC_COMP_MODE;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_RLE_EN);
++ set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_DPCM4_RGB_EN);
++ set_reg_field_value(value, 1, FBC_COMP_MODE, FBC_IND_EN);
++ dal_write_reg(compressor->ctx, addr, value);
++
++ addr = mmFBC_COMP_CNTL;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(value, 1, FBC_COMP_CNTL, FBC_DEPTH_RGB08_EN);
++ dal_write_reg(compressor->ctx, addr, value);
++ /*FBC_MIN_COMPRESSION 0 ==> 2:1 */
++ /* 1 ==> 4:1 */
++ /* 2 ==> 8:1 */
++ /* 0xF ==> 1:1 */
++ set_reg_field_value(value, 0xF, FBC_COMP_CNTL, FBC_MIN_COMPRESSION);
++ dal_write_reg(compressor->ctx, addr, value);
++ compressor->min_compress_ratio = FBC_COMPRESS_RATIO_1TO1;
++
++ value = 0;
++ dal_write_reg(compressor->ctx, mmFBC_IND_LUT0, value);
++
++ value = 0xFFFFFF;
++ dal_write_reg(compressor->ctx, mmFBC_IND_LUT1, value);
++}
++
++void dce110_compressor_enable_fbc(
++ struct compressor *compressor,
++ uint32_t paths_num,
++ struct compr_addr_and_pitch_params *params)
++{
++ struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
++
++ if (compressor->options.bits.FBC_SUPPORT &&
++ (compressor->options.bits.DUMMY_BACKEND == 0) &&
++ (!dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL)) &&
++ (!is_source_bigger_than_epanel_size(
++ cp110,
++ params->source_view_width,
++ params->source_view_height))) {
++
++ uint32_t addr;
++ uint32_t value;
++
++ /* Before enabling FBC first need to enable LPT if applicable
++ * LPT state should always be changed (enable/disable) while FBC
++ * is disabled */
++ if (compressor->options.bits.LPT_SUPPORT && (paths_num < 2) &&
++ (params->source_view_width *
++ params->source_view_height <=
++ dce11_one_lpt_channel_max_resolution)) {
++ dce110_compressor_enable_lpt(compressor);
++ }
++
++ addr = mmFBC_CNTL;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
++ set_reg_field_value(
++ value,
++ params->inst,
++ FBC_CNTL, FBC_SRC_SEL);
++ dal_write_reg(compressor->ctx, addr, value);
++
++ /* Keep track of enum controller_id FBC is attached to */
++ compressor->is_enabled = true;
++ compressor->attached_inst = params->inst;
++ cp110->offsets = reg_offsets[params->inst - 1];
++
++ /*Toggle it as there is bug in HW */
++ set_reg_field_value(value, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
++ dal_write_reg(compressor->ctx, addr, value);
++ set_reg_field_value(value, 1, FBC_CNTL, FBC_GRPH_COMP_EN);
++ dal_write_reg(compressor->ctx, addr, value);
++
++ wait_for_fbc_state_changed(cp110, true);
++ }
++}
++
++void dce110_compressor_disable_fbc(struct compressor *compressor)
++{
++ struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
++
++ if (compressor->options.bits.FBC_SUPPORT &&
++ dce110_compressor_is_fbc_enabled_in_hw(compressor, NULL)) {
++ uint32_t reg_data;
++ /* Turn off compression */
++ reg_data = dal_read_reg(compressor->ctx, mmFBC_CNTL);
++ set_reg_field_value(reg_data, 0, FBC_CNTL, FBC_GRPH_COMP_EN);
++ dal_write_reg(compressor->ctx, mmFBC_CNTL, reg_data);
++
++ /* Reset enum controller_id to undefined */
++ compressor->attached_inst = 0;
++ compressor->is_enabled = false;
++
++ /* Whenever disabling FBC make sure LPT is disabled if LPT
++ * supported */
++ if (compressor->options.bits.LPT_SUPPORT)
++ dce110_compressor_disable_lpt(compressor);
++
++ wait_for_fbc_state_changed(cp110, false);
++ }
++}
++
++bool dce110_compressor_is_fbc_enabled_in_hw(
++ struct compressor *compressor,
++ uint32_t *inst)
++{
++ /* Check the hardware register */
++ uint32_t value;
++
++ value = dal_read_reg(compressor->ctx, mmFBC_STATUS);
++ if (get_reg_field_value(value, FBC_STATUS, FBC_ENABLE_STATUS)) {
++ if (inst != NULL)
++ *inst = compressor->attached_inst;
++ return true;
++ }
++
++ value = dal_read_reg(compressor->ctx, mmFBC_MISC);
++ if (get_reg_field_value(value, FBC_MISC, FBC_STOP_ON_HFLIP_EVENT)) {
++ value = dal_read_reg(compressor->ctx, mmFBC_CNTL);
++
++ if (get_reg_field_value(value, FBC_CNTL, FBC_GRPH_COMP_EN)) {
++ if (inst != NULL)
++ *inst =
++ compressor->attached_inst;
++ return true;
++ }
++ }
++ return false;
++}
++
++bool dce110_compressor_is_lpt_enabled_in_hw(struct compressor *compressor)
++{
++ /* Check the hardware register */
++ uint32_t value = dal_read_reg(compressor->ctx,
++ mmLOW_POWER_TILING_CONTROL);
++
++ return get_reg_field_value(
++ value,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ENABLE);
++}
++
++void dce110_compressor_program_compressed_surface_address_and_pitch(
++ struct compressor *compressor,
++ struct compr_addr_and_pitch_params *params)
++{
++ struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
++ uint32_t value = 0;
++ uint32_t fbc_pitch = 0;
++ uint32_t compressed_surf_address_low_part =
++ compressor->compr_surface_address.addr.low_part;
++
++ /* Clear content first. */
++ dal_write_reg(
++ compressor->ctx,
++ DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
++ 0);
++ dal_write_reg(compressor->ctx,
++ DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS), 0);
++
++ if (compressor->options.bits.LPT_SUPPORT) {
++ uint32_t lpt_alignment = lpt_size_alignment(cp110);
++
++ if (lpt_alignment != 0) {
++ compressed_surf_address_low_part =
++ ((compressed_surf_address_low_part
++ + (lpt_alignment - 1)) / lpt_alignment)
++ * lpt_alignment;
++ }
++ }
++
++ /* Write address, HIGH has to be first. */
++ dal_write_reg(compressor->ctx,
++ DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS_HIGH),
++ compressor->compr_surface_address.addr.high_part);
++ dal_write_reg(compressor->ctx,
++ DCP_REG(mmGRPH_COMPRESS_SURFACE_ADDRESS),
++ compressed_surf_address_low_part);
++
++ fbc_pitch = align_to_chunks_number_per_line(
++ cp110,
++ params->source_view_width);
++
++ if (compressor->min_compress_ratio == FBC_COMPRESS_RATIO_1TO1)
++ fbc_pitch = fbc_pitch / 8;
++ else
++ dal_logger_write(
++ compressor->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Unexpected DCE11 compression ratio",
++ __func__);
++
++ /* Clear content first. */
++ dal_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), 0);
++
++ /* Write FBC Pitch. */
++ set_reg_field_value(
++ value,
++ fbc_pitch,
++ GRPH_COMPRESS_PITCH,
++ GRPH_COMPRESS_PITCH);
++ dal_write_reg(compressor->ctx, DCP_REG(mmGRPH_COMPRESS_PITCH), value);
++
++}
++
++void dce110_compressor_disable_lpt(struct compressor *compressor)
++{
++ struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
++ uint32_t value;
++ uint32_t addr;
++ uint32_t inx;
++
++ /* Disable all pipes LPT Stutter */
++ for (inx = 0; inx < 3; inx++) {
++ value =
++ dal_read_reg(
++ compressor->ctx,
++ DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH));
++ set_reg_field_value(
++ value,
++ 0,
++ DPG_PIPE_STUTTER_CONTROL_NONLPTCH,
++ STUTTER_ENABLE_NONLPTCH);
++ dal_write_reg(
++ compressor->ctx,
++ DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH),
++ value);
++ }
++ /* Disable Underlay pipe LPT Stutter */
++ addr = mmDPGV0_PIPE_STUTTER_CONTROL_NONLPTCH;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 0,
++ DPGV0_PIPE_STUTTER_CONTROL_NONLPTCH,
++ STUTTER_ENABLE_NONLPTCH);
++ dal_write_reg(compressor->ctx, addr, value);
++
++ /* Disable LPT */
++ addr = mmLOW_POWER_TILING_CONTROL;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ENABLE);
++ dal_write_reg(compressor->ctx, addr, value);
++
++ /* Clear selection of Channel(s) containing Compressed Surface */
++ addr = mmGMCON_LPT_TARGET;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 0xFFFFFFFF,
++ GMCON_LPT_TARGET,
++ STCTRL_LPT_TARGET);
++ dal_write_reg(compressor->ctx, mmGMCON_LPT_TARGET, value);
++}
++
++void dce110_compressor_enable_lpt(struct compressor *compressor)
++{
++ struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
++ uint32_t value;
++ uint32_t addr;
++ uint32_t value_control;
++ uint32_t channels;
++
++ /* Enable LPT Stutter from Display pipe */
++ value = dal_read_reg(compressor->ctx,
++ DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH));
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL_NONLPTCH,
++ STUTTER_ENABLE_NONLPTCH);
++ dal_write_reg(compressor->ctx,
++ DMIF_REG(mmDPG_PIPE_STUTTER_CONTROL_NONLPTCH), value);
++
++ /* Enable Underlay pipe LPT Stutter */
++ addr = mmDPGV0_PIPE_STUTTER_CONTROL_NONLPTCH;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPGV0_PIPE_STUTTER_CONTROL_NONLPTCH,
++ STUTTER_ENABLE_NONLPTCH);
++ dal_write_reg(compressor->ctx, addr, value);
++
++ /* Selection of Channel(s) containing Compressed Surface: 0xfffffff
++ * will disable LPT.
++ * STCTRL_LPT_TARGETn corresponds to channel n. */
++ addr = mmLOW_POWER_TILING_CONTROL;
++ value_control = dal_read_reg(compressor->ctx, addr);
++ channels = get_reg_field_value(value_control,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_MODE);
++
++ addr = mmGMCON_LPT_TARGET;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ channels + 1, /* not mentioned in programming guide,
++ but follow DCE8.1 */
++ GMCON_LPT_TARGET,
++ STCTRL_LPT_TARGET);
++ dal_write_reg(compressor->ctx, addr, value);
++
++ /* Enable LPT */
++ addr = mmLOW_POWER_TILING_CONTROL;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ENABLE);
++ dal_write_reg(compressor->ctx, addr, value);
++}
++
++void dce110_compressor_program_lpt_control(
++ struct compressor *compressor,
++ struct compr_addr_and_pitch_params *params)
++{
++ struct dce110_compressor *cp110 = TO_DCE110_COMPRESSOR(compressor);
++ uint32_t rows_per_channel;
++ uint32_t lpt_alignment;
++ uint32_t source_view_width;
++ uint32_t source_view_height;
++ uint32_t lpt_control = 0;
++
++ if (!compressor->options.bits.LPT_SUPPORT)
++ return;
++
++ lpt_control = dal_read_reg(compressor->ctx,
++ mmLOW_POWER_TILING_CONTROL);
++
++ /* POSSIBLE VALUES for Low Power Tiling Mode:
++ * 00 - Use channel 0
++ * 01 - Use Channel 0 and 1
++ * 02 - Use Channel 0,1,2,3
++ * 03 - reserved */
++ switch (compressor->lpt_channels_num) {
++ /* case 2:
++ * Use Channel 0 & 1 / Not used for DCE 11 */
++ case 1:
++ /*Use Channel 0 for LPT for DCE 11 */
++ set_reg_field_value(
++ lpt_control,
++ 0,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_MODE);
++ break;
++ default:
++ dal_logger_write(
++ compressor->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: Invalid selected DRAM channels for LPT!!!",
++ __func__);
++ break;
++ }
++
++ lpt_control = lpt_memory_control_config(cp110, lpt_control);
++
++ /* Program LOW_POWER_TILING_ROWS_PER_CHAN field which depends on
++ * FBC compressed surface pitch.
++ * LOW_POWER_TILING_ROWS_PER_CHAN = Roundup ((Surface Height *
++ * Surface Pitch) / (Row Size * Number of Channels *
++ * Number of Banks)). */
++ rows_per_channel = 0;
++ lpt_alignment = lpt_size_alignment(cp110);
++ source_view_width =
++ align_to_chunks_number_per_line(
++ cp110,
++ params->source_view_width);
++ source_view_height = (params->source_view_height + 1) & (~0x1);
++
++ if (lpt_alignment != 0) {
++ rows_per_channel = source_view_width * source_view_height * 4;
++ rows_per_channel =
++ (rows_per_channel % lpt_alignment) ?
++ (rows_per_channel / lpt_alignment + 1) :
++ rows_per_channel / lpt_alignment;
++ }
++
++ set_reg_field_value(
++ lpt_control,
++ rows_per_channel,
++ LOW_POWER_TILING_CONTROL,
++ LOW_POWER_TILING_ROWS_PER_CHAN);
++
++ dal_write_reg(compressor->ctx,
++ mmLOW_POWER_TILING_CONTROL, lpt_control);
++}
++
++/*
++ * DCE 11 Frame Buffer Compression Implementation
++ */
++
++
++void dce110_compressor_set_fbc_invalidation_triggers(
++ struct compressor *compressor,
++ uint32_t fbc_trigger)
++{
++ /* Disable region hit event, FBC_MEMORY_REGION_MASK = 0 (bits 16-19)
++ * for DCE 11 regions cannot be used - does not work with S/G
++ */
++ uint32_t addr = mmFBC_CLIENT_REGION_MASK;
++ uint32_t value = dal_read_reg(compressor->ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ FBC_CLIENT_REGION_MASK,
++ FBC_MEMORY_REGION_MASK);
++ dal_write_reg(compressor->ctx, addr, value);
++
++ /* Setup events when to clear all CSM entries (effectively marking
++ * current compressed data invalid)
++ * For DCE 11 CSM metadata 11111 means - "Not Compressed"
++ * Used as the initial value of the metadata sent to the compressor
++ * after invalidation, to indicate that the compressor should attempt
++ * to compress all chunks on the current pass. Also used when the chunk
++ * is not successfully written to memory.
++ * When this CSM value is detected, FBC reads from the uncompressed
++ * buffer. Set events according to passed in value, these events are
++ * valid for DCE11:
++ * - bit 0 - display register updated
++ * - bit 28 - memory write from any client except from MCIF
++ * - bit 29 - CG static screen signal is inactive
++ * In addition, DCE11.1 also needs to set new DCE11.1 specific events
++ * that are used to trigger invalidation on certain register changes,
++ * for example enabling of Alpha Compression may trigger invalidation of
++ * FBC once bit is set. These events are as follows:
++ * - Bit 2 - FBC_GRPH_COMP_EN register updated
++ * - Bit 3 - FBC_SRC_SEL register updated
++ * - Bit 4 - FBC_MIN_COMPRESSION register updated
++ * - Bit 5 - FBC_ALPHA_COMP_EN register updated
++ * - Bit 6 - FBC_ZERO_ALPHA_CHUNK_SKIP_EN register updated
++ * - Bit 7 - FBC_FORCE_COPY_TO_COMP_BUF register updated
++ */
++ addr = mmFBC_IDLE_FORCE_CLEAR_MASK;
++ value = dal_read_reg(compressor->ctx, addr);
++ set_reg_field_value(
++ value,
++ fbc_trigger |
++ FBC_IDLE_FORCE_GRPH_COMP_EN |
++ FBC_IDLE_FORCE_SRC_SEL_CHANGE |
++ FBC_IDLE_FORCE_MIN_COMPRESSION_CHANGE |
++ FBC_IDLE_FORCE_ALPHA_COMP_EN |
++ FBC_IDLE_FORCE_ZERO_ALPHA_CHUNK_SKIP_EN |
++ FBC_IDLE_FORCE_FORCE_COPY_TO_COMP_BUF,
++ FBC_IDLE_FORCE_CLEAR_MASK,
++ FBC_IDLE_FORCE_CLEAR_MASK);
++ dal_write_reg(compressor->ctx, addr, value);
++}
++
++bool dce110_compressor_construct(struct dce110_compressor *compressor,
++ struct dc_context *ctx, struct adapter_service *as)
++{
++ struct embedded_panel_info panel_info;
++
++ compressor->base.options.bits.FBC_SUPPORT = true;
++ if (!(dal_adapter_service_is_feature_supported(
++ FEATURE_DISABLE_LPT_SUPPORT)))
++ compressor->base.options.bits.LPT_SUPPORT = true;
++ /* For DCE 11 always use one DRAM channel for LPT */
++ compressor->base.lpt_channels_num = 1;
++
++ if (dal_adapter_service_is_feature_supported(FEATURE_DUMMY_FBC_BACKEND))
++ compressor->base.options.bits.DUMMY_BACKEND = true;
++
++ /* Check if this system has more than 1 DRAM channel; if only 1 then LPT
++ * should not be supported */
++ if (compressor->base.memory_bus_width == 64)
++ compressor->base.options.bits.LPT_SUPPORT = false;
++
++ if (dal_adapter_service_is_feature_supported(
++ FEATURE_DISABLE_FBC_COMP_CLK_GATE))
++ compressor->base.options.bits.CLK_GATING_DISABLED = true;
++
++ compressor->base.ctx = ctx;
++ compressor->base.embedded_panel_h_size = 0;
++ compressor->base.embedded_panel_v_size = 0;
++ compressor->base.memory_bus_width =
++ dal_adapter_service_get_asic_vram_bit_width(as);
++ compressor->base.allocated_size = 0;
++ compressor->base.preferred_requested_size = 0;
++ compressor->base.min_compress_ratio = FBC_COMPRESS_RATIO_INVALID;
++ compressor->base.options.raw = 0;
++ compressor->base.banks_num = 0;
++ compressor->base.raw_size = 0;
++ compressor->base.channel_interleave_size = 0;
++ compressor->base.dram_channels_num = 0;
++ compressor->base.lpt_channels_num = 0;
++ compressor->base.attached_inst = 0;
++ compressor->base.is_enabled = false;
++
++ if (dal_adapter_service_get_embedded_panel_info(as,
++ &panel_info)) {
++ compressor->base.embedded_panel_h_size =
++ panel_info.lcd_timing.horizontal_addressable;
++ compressor->base.embedded_panel_v_size =
++ panel_info.lcd_timing.vertical_addressable;
++ }
++ return true;
++}
++
++struct compressor *dce110_compressor_create(struct dc_context *ctx,
++ struct adapter_service *as)
++{
++ struct dce110_compressor *cp110 =
++ dc_service_alloc(ctx, sizeof(struct dce110_compressor));
++
++ if (!cp110)
++ return NULL;
++
++ if (dce110_compressor_construct(cp110, ctx, as))
++ return &cp110->base;
++
++ BREAK_TO_DEBUGGER();
++ dc_service_free(ctx, cp110);
++ return NULL;
++}
++
++void dce110_compressor_destroy(struct compressor **compressor)
++{
++ dc_service_free((*compressor)->ctx, TO_DCE110_COMPRESSOR(*compressor));
++ *compressor = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_compressor.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_compressor.h
+new file mode 100644
+index 0000000..0beef22
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_compressor.h
+@@ -0,0 +1,84 @@
++/* Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_COMPRESSOR_DCE110_H__
++#define __DC_COMPRESSOR_DCE110_H__
++
++#include "../inc/compressor.h"
++
++#define TO_DCE110_COMPRESSOR(compressor)\
++ container_of(compressor, struct dce110_compressor, base)
++
++struct dce110_compressor_reg_offsets {
++ uint32_t dcp_offset;
++ uint32_t dmif_offset;
++};
++
++struct dce110_compressor {
++ struct compressor base;
++ struct dce110_compressor_reg_offsets offsets;
++};
++
++struct compressor *dce110_compressor_create(struct dc_context *ctx,
++ struct adapter_service *as);
++
++bool dce110_compressor_construct(struct dce110_compressor *cp110,
++ struct dc_context *ctx, struct adapter_service *as);
++
++void dce110_compressor_destroy(struct compressor **cp);
++
++/* FBC RELATED */
++void dce110_compressor_power_up_fbc(struct compressor *cp);
++
++void dce110_compressor_enable_fbc(struct compressor *cp, uint32_t paths_num,
++ struct compr_addr_and_pitch_params *params);
++
++void dce110_compressor_disable_fbc(struct compressor *cp);
++
++void dce110_compressor_set_fbc_invalidation_triggers(struct compressor *cp,
++ uint32_t fbc_trigger);
++
++void dce110_compressor_program_compressed_surface_address_and_pitch(
++ struct compressor *cp,
++ struct compr_addr_and_pitch_params *params);
++
++bool dce110_compressor_get_required_compressed_surface_size(
++ struct compressor *cp,
++ struct fbc_input_info *input_info,
++ struct fbc_requested_compressed_size *size);
++
++bool dce110_compressor_is_fbc_enabled_in_hw(struct compressor *cp,
++ uint32_t *fbc_mapped_crtc_id);
++
++/* LPT RELATED */
++void dce110_compressor_enable_lpt(struct compressor *cp);
++
++void dce110_compressor_disable_lpt(struct compressor *cp);
++
++void dce110_compressor_program_lpt_control(struct compressor *cp,
++ struct compr_addr_and_pitch_params *params);
++
++bool dce110_compressor_is_lpt_enabled_in_hw(struct compressor *cp);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+new file mode 100644
+index 0000000..74294cb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.c
+@@ -0,0 +1,1825 @@
++/*
++ * Copyright 2015 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++#include "dc_services.h"
++#include "dc.h"
++#include "core_types.h"
++#include "core_status.h"
++#include "resource.h"
++#include "hw_sequencer.h"
++#include "dc_helpers.h"
++
++#include "dce110/dce110_resource.h"
++#include "dce110/dce110_timing_generator.h"
++#include "dce110/dce110_link_encoder.h"
++#include "dce110/dce110_stream_encoder.h"
++#include "stream_encoder_types.h"
++#include "link_encoder_types.h"
++#include "dce110/dce110_mem_input.h"
++#include "dce110/dce110_ipp.h"
++#include "dce110/dce110_transform.h"
++#include "dce110/dce110_opp.h"
++#include "gpu/dce110/dc_clock_gating_dce110.h"
++
++/* include DCE11 register header files */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++struct dce110_hw_seq_reg_offsets {
++ uint32_t dcfe_offset;
++ uint32_t blnd_offset;
++ uint32_t crtc_offset;
++ uint32_t dcp_offset;
++};
++
++enum crtc_stereo_mixer_mode {
++ HW_STEREO_MIXER_MODE_INACTIVE,
++ HW_STEREO_MIXER_MODE_ROW_INTERLEAVE,
++ HW_STEREO_MIXER_MODE_COLUMN_INTERLEAVE,
++ HW_STEREO_MIXER_MODE_PIXEL_INTERLEAVE,
++ HW_STEREO_MIXER_MODE_BLENDER
++};
++
++struct crtc_mixer_params {
++ bool sub_sampling;
++ enum crtc_stereo_mixer_mode mode;
++};
++
++enum pipe_lock_control {
++ PIPE_LOCK_CONTROL_GRAPHICS = 1 << 0,
++ PIPE_LOCK_CONTROL_BLENDER = 1 << 1,
++ PIPE_LOCK_CONTROL_SCL = 1 << 2,
++ PIPE_LOCK_CONTROL_SURFACE = 1 << 3,
++ PIPE_LOCK_CONTROL_MODE = 1 << 4
++};
++
++enum blender_mode {
++ BLENDER_MODE_CURRENT_PIPE = 0,/* Data from current pipe only */
++ BLENDER_MODE_OTHER_PIPE, /* Data from other pipe only */
++ BLENDER_MODE_BLENDING,/* Alpha blending - blend 'current' and 'other' */
++ BLENDER_MODE_STEREO
++};
++
++enum blender_type {
++ BLENDER_TYPE_NON_SINGLE_PIPE = 0,
++ BLENDER_TYPE_SB_SINGLE_PIPE,
++ BLENDER_TYPE_TB_SINGLE_PIPE
++};
++
++enum dc_memory_sleep_state {
++ DC_MEMORY_SLEEP_DISABLE = 0,
++ DC_MEMORY_LIGHT_SLEEP,
++ DC_MEMORY_DEEP_SLEEP,
++ DC_MEMORY_SHUTDOWN
++};
++enum {
++ DCE110_PIPE_UPDATE_PENDING_DELAY = 1000,
++ DCE110_PIPE_UPDATE_PENDING_CHECKCOUNT = 5000
++};
++
++static const struct dce110_hw_seq_reg_offsets reg_offsets[] = {
++{
++ .dcfe_offset = (mmDCFE0_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .blnd_offset = (mmBLND0_BLND_CONTROL - mmBLND0_BLND_CONTROL),
++ .crtc_offset = (mmCRTC0_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
++ .dcp_offset = (mmDCP0_DVMM_PTE_CONTROL - mmDCP0_DVMM_PTE_CONTROL),
++},
++{
++ .dcfe_offset = (mmDCFE1_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .blnd_offset = (mmBLND1_BLND_CONTROL - mmBLND0_BLND_CONTROL),
++ .crtc_offset = (mmCRTC1_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
++ .dcp_offset = (mmDCP1_DVMM_PTE_CONTROL - mmDCP0_DVMM_PTE_CONTROL),
++},
++{
++ .dcfe_offset = (mmDCFE2_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .blnd_offset = (mmBLND2_BLND_CONTROL - mmBLND0_BLND_CONTROL),
++ .crtc_offset = (mmCRTC2_CRTC_GSL_CONTROL - mmCRTC0_CRTC_GSL_CONTROL),
++ .dcp_offset = (mmDCP2_DVMM_PTE_CONTROL - mmDCP0_DVMM_PTE_CONTROL),
++}
++};
++
++#define HW_REG_DCFE(reg, id)\
++ (reg + reg_offsets[id].dcfe_offset)
++
++#define HW_REG_BLND(reg, id)\
++ (reg + reg_offsets[id].blnd_offset)
++
++#define HW_REG_CRTC(reg, id)\
++ (reg + reg_offsets[id].crtc_offset)
++
++#define HW_REG_DCP(reg, id)\
++ (reg + reg_offsets[id].dcp_offset)
++
++
++static void init_pte(struct dc_context *ctx);
++
++/*******************************************************************************
++ * Private definitions
++ ******************************************************************************/
++
++static void dce110_enable_display_pipe_clock_gating(
++ struct dc_context *ctx,
++ bool clock_gating)
++{
++ /*TODO*/
++}
++
++static bool dce110_enable_display_power_gating(
++ struct dc_context *ctx,
++ uint8_t controller_id,
++ struct bios_parser *bp,
++ enum pipe_gating_control power_gating)
++{
++ enum bp_result bp_result = BP_RESULT_OK;
++ enum bp_pipe_control_action cntl;
++
++ if (power_gating == PIPE_GATING_CONTROL_INIT)
++ cntl = ASIC_PIPE_INIT;
++ else if (power_gating == PIPE_GATING_CONTROL_ENABLE)
++ cntl = ASIC_PIPE_ENABLE;
++ else
++ cntl = ASIC_PIPE_DISABLE;
++
++ if (!(power_gating == PIPE_GATING_CONTROL_INIT &&
++ (controller_id + 1) != CONTROLLER_ID_D0))
++ bp_result = dal_bios_parser_enable_disp_power_gating(
++ bp, controller_id + 1, cntl);
++
++ if (power_gating != PIPE_GATING_CONTROL_ENABLE)
++ init_pte(ctx);
++
++ if (bp_result == BP_RESULT_OK)
++ return true;
++ else
++ return false;
++}
++
++
++static bool set_gamma_ramp(
++ struct input_pixel_processor *ipp,
++ struct output_pixel_processor *opp,
++ const struct gamma_ramp *ramp,
++ const struct gamma_parameters *params)
++{
++ /*Power on LUT memory*/
++ dce110_opp_power_on_regamma_lut(opp, true);
++
++ if (params->surface_pixel_format == PIXEL_FORMAT_INDEX8 ||
++ params->selected_gamma_lut == GRAPHICS_GAMMA_LUT_LEGACY) {
++ /* do legacy DCP for 256 colors if we are requested to do so */
++ dce110_ipp_set_legacy_input_gamma_ramp(
++ ipp, ramp, params);
++
++ dce110_ipp_set_legacy_input_gamma_mode(ipp, true);
++
++ /* set bypass */
++ dce110_ipp_program_prescale(ipp, PIXEL_FORMAT_UNINITIALIZED);
++
++ dce110_ipp_set_degamma(ipp, params, true);
++
++ dce110_opp_set_regamma(opp, ramp, params, true);
++ } else if (params->selected_gamma_lut ==
++ GRAPHICS_GAMMA_LUT_LEGACY_AND_REGAMMA) {
++ if (!dce110_opp_map_legacy_and_regamma_hw_to_x_user(
++ opp, ramp, params)) {
++ BREAK_TO_DEBUGGER();
++ /* invalid parameters or bug */
++ return false;
++ }
++
++ /* do legacy DCP for 256 colors if we are requested to do so */
++ dce110_ipp_set_legacy_input_gamma_ramp(
++ ipp, ramp, params);
++
++ dce110_ipp_set_legacy_input_gamma_mode(ipp, true);
++
++ /* set bypass */
++ dce110_ipp_program_prescale(ipp, PIXEL_FORMAT_UNINITIALIZED);
++ } else {
++ dce110_ipp_set_legacy_input_gamma_mode(ipp, false);
++
++ dce110_ipp_program_prescale(ipp, params->surface_pixel_format);
++
++ /* Do degamma step : remove the given gamma value from FB.
++ * For FP16 or no degamma do by pass */
++ dce110_ipp_set_degamma(ipp, params, false);
++
++ dce110_opp_set_regamma(opp, ramp, params, false);
++ }
++
++ /*re-enable low power mode for LUT memory*/
++ dce110_opp_power_on_regamma_lut(opp, false);
++
++ return true;
++}
++
++static enum dc_status bios_parser_crtc_source_select(
++ struct core_stream *stream)
++{
++ /* call VBIOS table to set CRTC source for the HW
++ * encoder block
++ * note: video bios clears all FMT setting here. */
++
++ struct bp_crtc_source_select crtc_source_select = {0};
++ const struct core_sink *sink = stream->sink;
++ crtc_source_select.engine_id = stream->stream_enc->id;
++ crtc_source_select.controller_id = stream->controller_idx + 1;
++ /*TODO: Need to un-hardcode color depth, dp_audio and account for
++ * the case where signal and sink signal is different (translator
++ * encoder)*/
++ crtc_source_select.signal = sink->public.sink_signal;
++ crtc_source_select.enable_dp_audio = false;
++ crtc_source_select.sink_signal = sink->public.sink_signal;
++ crtc_source_select.display_output_bit_depth
++ = PANEL_8BIT_COLOR;
++
++ if (BP_RESULT_OK != dal_bios_parser_crtc_source_select(
++ dal_adapter_service_get_bios_parser(sink->link->adapter_srv),
++ &crtc_source_select)) {
++ return DC_ERROR_UNEXPECTED;
++ }
++ return DC_OK;
++}
++
++static enum color_space surface_color_to_color_space(
++ struct plane_colorimetry *colorimetry)
++{
++ enum color_space color_space = COLOR_SPACE_UNKNOWN;
++
++ switch (colorimetry->color_space) {
++ case SURFACE_COLOR_SPACE_SRGB:
++ case SURFACE_COLOR_SPACE_XRRGB:
++ if (colorimetry->limited_range)
++ color_space = COLOR_SPACE_SRGB_LIMITED_RANGE;
++ else
++ color_space = COLOR_SPACE_SRGB_FULL_RANGE;
++ break;
++ case SURFACE_COLOR_SPACE_BT601:
++ case SURFACE_COLOR_SPACE_XVYCC_BT601:
++ color_space = COLOR_SPACE_YCBCR601;
++ break;
++ case SURFACE_COLOR_SPACE_BT709:
++ case SURFACE_COLOR_SPACE_XVYCC_BT709:
++ color_space = COLOR_SPACE_YCBCR709;
++ break;
++ }
++
++ return color_space;
++}
++
++/*******************************FMT**************************************/
++static void program_fmt(
++ struct output_pixel_processor *opp,
++ struct bit_depth_reduction_params *fmt_bit_depth,
++ struct clamping_and_pixel_encoding_params *clamping)
++{
++ /* dithering is affected by <CrtcSourceSelect>, hence should be
++ * programmed afterwards */
++
++ dce110_opp_program_bit_depth_reduction(
++ opp,
++ fmt_bit_depth);
++
++ dce110_opp_program_clamping_and_pixel_encoding(
++ opp,
++ clamping);
++
++ return;
++}
++
++/***************************PIPE_CONTROL***********************************/
++static void enable_fe_clock(
++ struct dc_context *ctx, uint8_t controller_id, bool enable)
++{
++ uint32_t value = 0;
++ uint32_t addr;
++
++ /*TODO: proper offset*/
++ addr = HW_REG_DCFE(mmDCFE_CLOCK_CONTROL, controller_id);
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ enable,
++ DCFE_CLOCK_CONTROL,
++ DCFE_CLOCK_ENABLE);
++
++ dal_write_reg(ctx, addr, value);
++}
++/*
++static void enable_stereo_mixer(
++ struct dc_context *ctx,
++ const struct crtc_mixer_params *params)
++{
++ TODO
++}
++*/
++static void disable_stereo_mixer(
++ struct dc_context *ctx)
++{
++ /*TODO*/
++}
++
++static void init_pte(struct dc_context *ctx)
++{
++ uint32_t addr;
++ uint32_t value = 0;
++ uint32_t chunk_int = 0;
++ uint32_t chunk_mul = 0;
++
++ addr = mmUNP_DVMM_PTE_CONTROL;
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DVMM_PTE_CONTROL,
++ DVMM_USE_SINGLE_PTE);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DVMM_PTE_CONTROL,
++ DVMM_PTE_BUFFER_MODE0);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DVMM_PTE_CONTROL,
++ DVMM_PTE_BUFFER_MODE1);
++
++ dal_write_reg(ctx, addr, value);
++
++ addr = mmDVMM_PTE_REQ;
++ value = dal_read_reg(ctx, addr);
++
++ chunk_int = get_reg_field_value(
++ value,
++ DVMM_PTE_REQ,
++ HFLIP_PTEREQ_PER_CHUNK_INT);
++
++ chunk_mul = get_reg_field_value(
++ value,
++ DVMM_PTE_REQ,
++ HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
++
++ if (chunk_int != 0x4 || chunk_mul != 0x4) {
++
++ set_reg_field_value(
++ value,
++ 255,
++ DVMM_PTE_REQ,
++ MAX_PTEREQ_TO_ISSUE);
++
++ set_reg_field_value(
++ value,
++ 4,
++ DVMM_PTE_REQ,
++ HFLIP_PTEREQ_PER_CHUNK_INT);
++
++ set_reg_field_value(
++ value,
++ 4,
++ DVMM_PTE_REQ,
++ HFLIP_PTEREQ_PER_CHUNK_MULTIPLIER);
++
++ dal_write_reg(ctx, addr, value);
++ }
++}
++
++/**
++ *****************************************************************************
++ * Function: enable_disp_power_gating
++ *
++ * @brief
++ * enable or disable power gating
++ *
++ * @param [in] enum pipe_gating_control power_gating true - power down,
++ * false - power up
++ *****************************************************************************
++ */
++
++
++/* this is a workaround for hw bug - it is a trigger on r/w */
++
++static void trigger_write_crtc_h_blank_start_end(
++ struct dc_context *ctx,
++ uint8_t controller_id)
++{
++ uint32_t value;
++ uint32_t addr;
++
++ addr = HW_REG_CRTC(mmCRTC_H_BLANK_START_END, controller_id);
++ value = dal_read_reg(ctx, addr);
++ dal_write_reg(ctx, addr, value);
++}
++
++static bool pipe_control_lock(
++ struct dc_context *ctx,
++ uint8_t controller_idx,
++ uint32_t control_mask,
++ bool lock)
++{
++ uint32_t addr = HW_REG_BLND(mmBLND_V_UPDATE_LOCK, controller_idx);
++ uint32_t value = dal_read_reg(ctx, addr);
++ bool need_to_wait = false;
++
++ if (control_mask & PIPE_LOCK_CONTROL_GRAPHICS)
++ set_reg_field_value(
++ value,
++ lock,
++ BLND_V_UPDATE_LOCK,
++ BLND_DCP_GRPH_V_UPDATE_LOCK);
++
++ if (control_mask & PIPE_LOCK_CONTROL_SCL)
++ set_reg_field_value(
++ value,
++ lock,
++ BLND_V_UPDATE_LOCK,
++ BLND_SCL_V_UPDATE_LOCK);
++
++ if (control_mask & PIPE_LOCK_CONTROL_SURFACE)
++ set_reg_field_value(
++ value,
++ lock,
++ BLND_V_UPDATE_LOCK,
++ BLND_DCP_GRPH_SURF_V_UPDATE_LOCK);
++
++ if (control_mask & PIPE_LOCK_CONTROL_BLENDER) {
++ set_reg_field_value(
++ value,
++ lock,
++ BLND_V_UPDATE_LOCK,
++ BLND_BLND_V_UPDATE_LOCK);
++ need_to_wait = true;
++ }
++
++ if (control_mask & PIPE_LOCK_CONTROL_MODE)
++ set_reg_field_value(
++ value,
++ lock,
++ BLND_V_UPDATE_LOCK,
++ BLND_V_UPDATE_LOCK_MODE);
++
++ dal_write_reg(ctx, addr, value);
++
++ if (!lock && need_to_wait) {
++ uint8_t counter = 0;
++ const uint8_t counter_limit = 100;
++ const uint16_t delay_us = 1000;
++
++ uint8_t pipe_pending;
++
++ addr = HW_REG_BLND(mmBLND_REG_UPDATE_STATUS,
++ controller_idx);
++
++ while (counter < counter_limit) {
++ value = dal_read_reg(ctx, addr);
++
++ pipe_pending = 0;
++
++ if (control_mask & PIPE_LOCK_CONTROL_BLENDER) {
++ pipe_pending |=
++ get_reg_field_value(
++ value,
++ BLND_REG_UPDATE_STATUS,
++ BLND_BLNDC_UPDATE_PENDING);
++ pipe_pending |= get_reg_field_value(
++ value,
++ BLND_REG_UPDATE_STATUS,
++ BLND_BLNDO_UPDATE_PENDING);
++ }
++
++ if (control_mask & PIPE_LOCK_CONTROL_SCL) {
++ pipe_pending |=
++ get_reg_field_value(
++ value,
++ BLND_REG_UPDATE_STATUS,
++ SCL_BLNDC_UPDATE_PENDING);
++ pipe_pending |=
++ get_reg_field_value(
++ value,
++ BLND_REG_UPDATE_STATUS,
++ SCL_BLNDO_UPDATE_PENDING);
++ }
++ if (control_mask & PIPE_LOCK_CONTROL_GRAPHICS) {
++ pipe_pending |=
++ get_reg_field_value(
++ value,
++ BLND_REG_UPDATE_STATUS,
++ DCP_BLNDC_GRPH_UPDATE_PENDING);
++ pipe_pending |=
++ get_reg_field_value(
++ value,
++ BLND_REG_UPDATE_STATUS,
++ DCP_BLNDO_GRPH_UPDATE_PENDING);
++ }
++ if (control_mask & PIPE_LOCK_CONTROL_SURFACE) {
++ pipe_pending |= get_reg_field_value(
++ value,
++ BLND_REG_UPDATE_STATUS,
++ DCP_BLNDC_GRPH_SURF_UPDATE_PENDING);
++ pipe_pending |= get_reg_field_value(
++ value,
++ BLND_REG_UPDATE_STATUS,
++ DCP_BLNDO_GRPH_SURF_UPDATE_PENDING);
++ }
++
++ if (pipe_pending == 0)
++ break;
++
++ counter++;
++ dc_service_delay_in_microseconds(ctx, delay_us);
++ }
++
++ if (counter == counter_limit) {
++ dal_logger_write(
++ ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: wait for update exceeded (wait %d us)\n",
++ __func__,
++ counter * delay_us);
++ dal_logger_write(
++ ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: control %d, remain value %x\n",
++ __func__,
++ control_mask,
++ value);
++ } else {
++ /* OK. */
++ }
++ }
++
++ if (!lock && (control_mask & PIPE_LOCK_CONTROL_BLENDER))
++ trigger_write_crtc_h_blank_start_end(ctx, controller_idx);
++
++ return true;
++}
++
++static void set_blender_mode(
++ struct dc_context *ctx,
++ uint8_t controller_id,
++ enum blender_mode mode)
++{
++ uint32_t value;
++ uint32_t addr = HW_REG_BLND(mmBLND_CONTROL, controller_id);
++ uint32_t blnd_mode;
++ uint32_t feedthrough = 0;
++
++ switch (mode) {
++ case BLENDER_MODE_OTHER_PIPE:
++ feedthrough = 0;
++ blnd_mode = 1;
++ break;
++ case BLENDER_MODE_BLENDING:
++ feedthrough = 0;
++ blnd_mode = 2;
++ break;
++ case BLENDER_MODE_CURRENT_PIPE:
++ default:
++ feedthrough = 1;
++ blnd_mode = 0;
++ break;
++ }
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ feedthrough,
++ BLND_CONTROL,
++ BLND_FEEDTHROUGH_EN);
++
++ set_reg_field_value(
++ value,
++ blnd_mode,
++ BLND_CONTROL,
++ BLND_MODE);
++
++ dal_write_reg(ctx, addr, value);
++}
++/**************************************************************************/
++static void update_bios_scratch_critical_state(struct adapter_service *as,
++ bool state)
++{
++ dal_bios_parser_set_scratch_critical_state(
++ dal_adapter_service_get_bios_parser(as),
++ state);
++}
++
++static void update_info_frame(struct core_stream *stream)
++{
++ dce110_stream_encoder_update_info_packets(
++ stream->stream_enc,
++ stream->signal,
++ &stream->encoder_info_frame);
++}
++
++
++static void enable_stream(struct core_stream *stream)
++{
++ enum lane_count lane_count = LANE_COUNT_ONE;
++
++ struct dc_crtc_timing *timing = &stream->public.timing;
++ struct core_link *link = stream->sink->link;
++
++ /* 1. update AVI info frame (HDMI, DP)
++ * we always need to update info frame
++ */
++ uint32_t active_total_with_borders;
++ uint32_t early_control = 0;
++ struct timing_generator *tg = stream->tg;
++
++ update_info_frame(stream);
++ /* enable early control to avoid corruption on DP monitor*/
++ active_total_with_borders =
++ timing->h_addressable
++ + timing->h_border_left
++ + timing->h_border_right;
++
++ early_control = active_total_with_borders % lane_count;
++
++ if (early_control == 0)
++ early_control = lane_count;
++
++ dce110_timing_generator_set_early_control(tg, early_control);
++
++ /* enable audio only within mode set */
++ if (stream->audio != NULL) {
++ dal_audio_enable_output(
++ stream->audio,
++ stream->stream_enc->id,
++ stream->signal);
++ }
++
++ /* For MST, there are multiply stream go to only one link.
++ * connect DIG back_end to front_end while enable_stream and
++ * disconnect them during disable_stream
++ * BY this, it is logic clean to separate stream and link */
++ dce110_link_encoder_connect_dig_be_to_fe(link->link_enc,
++ stream->stream_enc->id, true);
++
++}
++
++static void disable_stream(struct core_stream *stream)
++{
++ struct core_link *link = stream->sink->link;
++
++ dce110_stream_encoder_stop_info_packets(
++ stream->stream_enc,
++ stream->stream_enc->id,
++ stream->signal);
++
++ if (stream->audio) {
++ /* mute audio */
++ dal_audio_mute(stream->audio, stream->stream_enc->id,
++ stream->signal);
++
++ /* TODO: notify audio driver for if audio modes list changed
++ * add audio mode list change flag */
++ /* dal_audio_disable_azalia_audio_jack_presence(stream->audio,
++ * stream->stream_engine_id);
++ */
++ }
++
++ /* blank at encoder level */
++ dce110_stream_encoder_blank(stream->stream_enc, stream->signal);
++ dce110_link_encoder_connect_dig_be_to_fe(
++ link->link_enc,
++ stream->stream_enc->id,
++ false);
++
++}
++
++static void unblank_stream(struct core_stream *stream,
++ struct link_settings *link_settings)
++{
++ struct encoder_unblank_param params = { { 0 } };
++
++ /* only 3 items below are used by unblank */
++ params.crtc_timing.pixel_clock =
++ stream->public.timing.pix_clk_khz;
++ params.link_settings.link_rate = link_settings->link_rate;
++ params.signal = stream->signal;
++ dce110_stream_encoder_unblank(
++ stream->stream_enc, &params);
++}
++
++static enum color_space get_output_color_space(
++ const struct dc_crtc_timing *dc_crtc_timing)
++{
++ enum color_space color_space = COLOR_SPACE_SRGB_FULL_RANGE;
++
++ switch (dc_crtc_timing->pixel_encoding) {
++ case PIXEL_ENCODING_YCBCR422:
++ case PIXEL_ENCODING_YCBCR444:
++ case PIXEL_ENCODING_YCBCR420:
++ {
++ if ((dc_crtc_timing->timing_standard ==
++ TIMING_STANDARD_CEA770) ||
++ (dc_crtc_timing->timing_standard ==
++ TIMING_STANDARD_CEA861)) {
++ if (dc_crtc_timing->pix_clk_khz > 27030) {
++ if (dc_crtc_timing->flags.Y_ONLY)
++ color_space =
++ COLOR_SPACE_YCBCR709_YONLY;
++ else
++ color_space = COLOR_SPACE_YCBCR709;
++ } else {
++ if (dc_crtc_timing->flags.Y_ONLY)
++ color_space =
++ COLOR_SPACE_YCBCR601_YONLY;
++ else
++ color_space = COLOR_SPACE_YCBCR601;
++ }
++ }
++ }
++ break;
++
++ default:
++ break;
++ }
++
++ return color_space;
++}
++
++static enum dc_status allocate_mst_payload(struct core_stream *stream)
++{
++ struct link_encoder *link_encoder = stream->sink->link->link_enc;
++ struct stream_encoder *stream_encoder = stream->stream_enc;
++ struct dp_mst_stream_allocation_table table;
++ struct fixed31_32 avg_time_slots_per_mtp;
++
++ /* TODO: remove hardcode */
++ table.stream_count = 1;
++ table.stream_allocations[0].engine = stream_encoder->id;
++
++ dc_helpers_dp_mst_write_payload_allocation_table(
++ stream->ctx,
++ &stream->sink->public,
++ &table.stream_allocations[0],
++ true);
++
++ dce110_link_encoder_update_mst_stream_allocation_table(
++ link_encoder,
++ &table,
++ false);
++
++ dc_helpers_dp_mst_poll_for_allocation_change_trigger(
++ stream->ctx,
++ &stream->sink->public);
++
++ dc_helpers_dp_mst_send_payload_allocation(
++ stream->ctx,
++ &stream->sink->public,
++ true);
++
++ avg_time_slots_per_mtp = dal_fixed31_32_from_fraction(
++ table.stream_allocations[0].pbn,
++ table.stream_allocations[0].pbn_per_slot);
++
++ dce110_link_encoder_set_mst_bandwidth(
++ link_encoder,
++ stream_encoder->id,
++ avg_time_slots_per_mtp);
++
++ return DC_OK;
++
++}
++
++static enum dc_status deallocate_mst_payload(struct core_stream *stream)
++{
++ struct link_encoder *link_encoder = stream->sink->link->link_enc;
++ struct stream_encoder *stream_encoder = stream->stream_enc;
++ struct dp_mst_stream_allocation_table table;
++ struct fixed31_32 avg_time_slots_per_mtp = dal_fixed31_32_from_int(0);
++
++ /* TODO: remove hardcode */
++ table.stream_count = 1;
++ table.stream_allocations[0].slot_count = 0;
++
++ dce110_link_encoder_set_mst_bandwidth(
++ link_encoder,
++ stream_encoder->id,
++ avg_time_slots_per_mtp);
++
++ dc_helpers_dp_mst_write_payload_allocation_table(
++ stream->ctx,
++ &stream->sink->public,
++ &table.stream_allocations[0],
++ false);
++
++ dce110_link_encoder_update_mst_stream_allocation_table(
++ link_encoder,
++ &table,
++ false);
++
++ dc_helpers_dp_mst_poll_for_allocation_change_trigger(
++ stream->ctx,
++ &stream->sink->public);
++
++ dc_helpers_dp_mst_send_payload_allocation(
++ stream->ctx,
++ &stream->sink->public,
++ false);
++
++
++ return DC_OK;
++
++}
++
++static enum dc_status apply_single_controller_ctx_to_hw(uint8_t controller_idx,
++ struct validate_context *context,
++ const struct dc *dc)
++{
++ struct core_stream *stream =
++ context->res_ctx.controller_ctx[controller_idx].stream;
++
++ struct output_pixel_processor *opp =
++ context->res_ctx.pool.opps[controller_idx];
++ bool timing_changed = context->res_ctx.controller_ctx[controller_idx]
++ .flags.timing_changed;
++ enum color_space color_space;
++
++ if (timing_changed) {
++
++ disable_stream(stream);
++ core_link_disable(stream);
++
++ /*TODO: AUTO check if timing changed*/
++ if (false == dal_clock_source_program_pix_clk(
++ stream->clock_source,
++ &stream->pix_clk_params,
++ &stream->pll_settings)) {
++ BREAK_TO_DEBUGGER();
++ return DC_ERROR_UNEXPECTED;
++ }
++
++
++ if (false == dce110_timing_generator_program_timing_generator(
++ stream->tg,
++ &stream->public.timing)) {
++ BREAK_TO_DEBUGGER();
++ return DC_ERROR_UNEXPECTED;
++ }
++ }
++
++ /*TODO: mst support - use total stream count*/
++ dce110_allocate_dmif_buffer(stream->mi,
++ &stream->public.timing,
++ context->target_count);
++
++ if (timing_changed) {
++ if (false == dce110_timing_generator_enable_crtc(
++ stream->tg)) {
++ BREAK_TO_DEBUGGER();
++ return DC_ERROR_UNEXPECTED;
++ }
++ }
++
++ if (DC_OK != bios_parser_crtc_source_select(stream)) {
++ BREAK_TO_DEBUGGER();
++ return DC_ERROR_UNEXPECTED;
++ }
++
++ dce110_opp_set_dyn_expansion(
++ opp,
++ COLOR_SPACE_YCBCR601,
++ stream->public.timing.display_color_depth,
++ stream->sink->public.sink_signal);
++
++ program_fmt(
++ opp,
++ &stream->fmt_bit_depth,
++ &stream->clamping);
++
++ dce110_link_encoder_setup(
++ stream->sink->link->link_enc,
++ stream->signal);
++ if (ENCODER_RESULT_OK != dce110_stream_encoder_setup(
++ stream->stream_enc,
++ &stream->public.timing,
++ stream->signal,
++ stream->audio != NULL)) {
++ BREAK_TO_DEBUGGER();
++ return DC_ERROR_UNEXPECTED;
++ }
++
++ if (stream->audio != NULL) {
++ if (AUDIO_RESULT_OK != dal_audio_setup(
++ stream->audio,
++ &stream->audio_output,
++ &stream->public.audio_info)) {
++ BREAK_TO_DEBUGGER();
++ return DC_ERROR_UNEXPECTED;
++ }
++ }
++
++ /* Setup audio rate clock source */
++ if (stream->audio != NULL)
++ dal_audio_setup_audio_wall_dto(
++ stream->audio,
++ stream->signal,
++ &stream->audio_output.crtc_info,
++ &stream->audio_output.pll_info);
++
++ /* program blank color */
++ color_space = get_output_color_space(
++ &stream->public.timing);
++
++ dce110_timing_generator_program_blank_color(
++ context->res_ctx.pool.timing_generators[controller_idx],
++ color_space);
++
++ if (timing_changed) {
++ enable_stream(stream);
++
++ if (DC_OK != core_link_enable(stream)) {
++ BREAK_TO_DEBUGGER();
++ return DC_ERROR_UNEXPECTED;
++ }
++ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
++ allocate_mst_payload(stream);
++
++ }
++
++ unblank_stream(stream, &stream->sink->link->cur_link_settings);
++
++ return DC_OK;
++}
++
++
++/******************************************************************************/
++
++static void power_down_encoders(struct validate_context *context)
++{
++ int i;
++ struct core_target *target;
++ struct core_stream *stream;
++
++ for (i = 0; i < context->target_count; i++) {
++ target = context->targets[i];
++ stream = target->streams[0];
++ core_link_disable(stream);
++ }
++}
++
++static void power_down_controllers(struct validate_context *context)
++{
++ int i;
++ struct core_target *target;
++ struct core_stream *stream;
++
++ for (i = 0; i < context->target_count; i++) {
++ target = context->targets[i];
++ stream = target->streams[0];
++
++ dce110_timing_generator_disable_crtc(stream->tg);
++ }
++}
++
++static void power_down_clock_sources(struct validate_context *context)
++{
++ int i;
++ struct core_target *target;
++ struct core_stream *stream;
++
++ for (i = 0; i < context->target_count; i++) {
++ target = context->targets[i];
++ stream = target->streams[0];
++
++ if (false == dal_clock_source_power_down_pll(
++ stream->clock_source,
++ stream->controller_idx + 1)) {
++ dal_error(
++ "Failed to power down pll! (clk src index=%d)\n",
++ i);
++ }
++ }
++}
++
++static void power_down_all_hw_blocks(struct validate_context *context)
++{
++ power_down_encoders(context);
++
++ power_down_controllers(context);
++
++ power_down_clock_sources(context);
++}
++
++static void disable_vga_and_power_gate_all_controllers(
++ struct validate_context *context)
++{
++ int i;
++ struct core_target *target;
++ struct core_stream *stream;
++ struct timing_generator *tg;
++ struct bios_parser *bp;
++ struct dc_context *ctx;
++ uint8_t controller_id;
++
++ bp = dal_adapter_service_get_bios_parser(
++ context->res_ctx.pool.adapter_srv);
++
++ for (i = 0; i < context->target_count; i++) {
++ target = context->targets[i];
++ stream = target->streams[0];
++ tg = stream->tg;
++ ctx = stream->ctx;
++ controller_id = stream->controller_idx;
++
++ dce110_timing_generator_disable_vga(tg);
++
++ /* Enable CLOCK gating for each pipe BEFORE controller
++ * powergating. */
++ dce110_enable_display_pipe_clock_gating(ctx,
++ true);
++ dce110_enable_display_power_gating(ctx, controller_id, bp,
++ PIPE_GATING_CONTROL_ENABLE);
++ }
++}
++
++/**
++ * When ASIC goes from VBIOS/VGA mode to driver/accelerated mode we need:
++ * 1. Power down all DC HW blocks
++ * 2. Disable VGA engine on all controllers
++ * 3. Enable power gating for controller
++ * 4. Set acc_mode_change bit (VBIOS will clear this bit when going to FSDOS)
++ */
++static void enable_accelerated_mode(struct validate_context *context)
++{
++ struct bios_parser *bp;
++
++ bp = dal_adapter_service_get_bios_parser(
++ context->res_ctx.pool.adapter_srv);
++
++ power_down_all_hw_blocks(context);
++
++ disable_vga_and_power_gate_all_controllers(context);
++
++ dal_bios_parser_set_scratch_acc_mode_change(bp);
++}
++
++#if 0
++static enum clocks_state get_required_clocks_state(
++ struct display_clock *display_clock,
++ struct state_dependent_clocks *req_state_dep_clks)
++{
++ enum clocks_state clocks_required_state;
++ enum clocks_state dp_link_required_state;
++ enum clocks_state overall_required_state;
++
++ clocks_required_state = dal_display_clock_get_required_clocks_state(
++ display_clock, req_state_dep_clks);
++
++ dp_link_required_state = CLOCKS_STATE_ULTRA_LOW;
++
++ /* overall required state is the max of required state for clocks
++ * (pixel, display clock) and the required state for DP link. */
++ overall_required_state =
++ clocks_required_state > dp_link_required_state ?
++ clocks_required_state : dp_link_required_state;
++
++ /* return the min required state */
++ return overall_required_state;
++}
++
++static bool dc_pre_clock_change(
++ struct dc_context *ctx,
++ struct minimum_clocks_calculation_result *min_clk_in,
++ enum clocks_state required_clocks_state,
++ struct power_to_dal_info *output)
++{
++ struct dal_to_power_info input = {0};
++
++ input.min_deep_sleep_sclk = min_clk_in->min_deep_sleep_sclk;
++ input.min_mclk = min_clk_in->min_mclk_khz;
++ input.min_sclk = min_clk_in->min_sclk_khz;
++
++ switch (required_clocks_state) {
++ case CLOCKS_STATE_ULTRA_LOW:
++ input.required_clock = PP_CLOCKS_STATE_ULTRA_LOW;
++ break;
++ case CLOCKS_STATE_LOW:
++ input.required_clock = PP_CLOCKS_STATE_LOW;
++ break;
++ case CLOCKS_STATE_NOMINAL:
++ input.required_clock = PP_CLOCKS_STATE_NOMINAL;
++ break;
++ case CLOCKS_STATE_PERFORMANCE:
++ input.required_clock = PP_CLOCKS_STATE_PERFORMANCE;
++ break;
++ default:
++ input.required_clock = PP_CLOCKS_STATE_NOMINAL;
++ break;
++ }
++
++ if (!dc_service_pp_pre_dce_clock_change(ctx, &input, output)) {
++ dal_error("DC: dc_service_pp_pre_dce_clock_change failed!\n");
++ return false;
++ }
++
++ return true;
++}
++
++static bool dc_set_clocks_and_clock_state (
++ struct validate_context *context)
++{
++ struct power_to_dal_info output = {0};
++
++ struct display_clock *disp_clk = context->res_ctx.pool.display_clock;
++ struct dc_context *ctx = context->targets[0]->ctx;
++
++
++ if (!dc_pre_clock_change(
++ ctx,
++ &context->res_ctx.min_clocks,
++ get_required_clocks_state(
++ context->res_ctx.pool.display_clock,
++ &context->res_ctx.state_clocks),
++ &output)) {
++ /* "output" was not updated by PPLib.
++ * DAL will use default values for set mode.
++ *
++ * Do NOT fail this call. */
++ return true;
++ }
++
++ /* PPLib accepted the "clock state" that we need, that means we
++ * can store it as minimum state because PPLib guarantees not go below
++ * that state.
++ *
++ * Update the clock state here (prior to setting Pixel clock,
++ * DVO clock, or Display clock) */
++ if (!dal_display_clock_set_min_clocks_state(
++ disp_clk, context->res_ctx.required_clocks_state)) {
++ BREAK_TO_DEBUGGER();
++ dal_error("DC: failed to set minimum clock state!\n");
++ }
++
++
++ /*bm_clk_info.max_mclk_khz = output.max_mclk;
++ bm_clk_info.min_mclk_khz = output.min_mclk;
++ bm_clk_info.max_sclk_khz = output.max_sclk;
++ bm_clk_info.min_sclk_khz = output.min_sclk;*/
++
++ /* Now let Bandwidth Manager know about values we got from PPLib. */
++ /*dal_bandwidth_manager_set_dynamic_clock_info(bw_mgr, &bm_clk_info);*/
++
++ return true;
++}
++#endif
++
++/**
++ * Call display_engine_clock_dce80 to perform the Dclk programming.
++ */
++static void set_display_clock(struct validate_context *context)
++{
++ /* Program the display engine clock.
++ * Check DFS bypass mode support or not. DFSbypass feature is only when
++ * BIOS GPU info table reports support. */
++
++ if (/*dal_adapter_service_is_dfs_bypass_enabled()*/ false) {
++ /*TODO: set_display_clock_dfs_bypass(
++ hws,
++ path_set,
++ context->res_ctx.pool.display_clock,
++ context->res_ctx.min_clocks.min_dclk_khz);*/
++ } else
++ dal_display_clock_set_clock(context->res_ctx.pool.display_clock,
++ context->bw_results.dispclk);
++
++ /* TODO: When changing display engine clock, DMCU WaitLoop must be
++ * reconfigured in order to maintain the same delays within DMCU
++ * programming sequences. */
++
++ /* TODO: Start GTC counter */
++}
++
++static void set_displaymarks(
++ const struct dc *dc, struct validate_context *context)
++{
++ uint8_t i, j;
++ uint8_t total_streams = 0;
++ uint8_t target_count = context->target_count;
++
++ for (i = 0; i < target_count; i++) {
++ struct core_target *target = context->targets[i];
++
++ for (j = 0; j < target->stream_count; j++) {
++ struct core_stream *stream = target->streams[j];
++
++ dce110_program_nbp_watermark(
++ stream->mi,
++ context->bw_results
++ .nbp_state_change_watermark[total_streams]);
++
++ dce110_program_stutter_watermark(
++ stream->mi,
++ context->bw_results
++ .stutter_exit_watermark[total_streams]);
++
++ dce110_program_urgency_watermark(
++ stream->mi,
++ context->bw_results
++ .urgent_watermark[total_streams],
++ stream->public.timing.h_total,
++ stream->public.timing.pix_clk_khz,
++ 1000 * dc->bw_vbios.blackout_duration
++ .value >> 24);
++ total_streams++;
++ }
++ }
++}
++
++static void set_safe_displaymarks(struct validate_context *context)
++{
++ uint8_t i, j;
++ uint8_t target_count = context->target_count;
++
++ for (i = 0; i < target_count; i++) {
++ struct core_target *target = context->targets[i];
++
++ for (j = 0; j < target->stream_count; j++) {
++ struct core_stream *stream = target->streams[j];
++
++ dce110_program_safe_display_marks(stream->mi);
++ }
++ }
++}
++
++static void dce110_program_bw(struct dc *dc, struct validate_context *context)
++{
++ set_safe_displaymarks(&dc->current_context);
++ /*TODO: when pplib works*/
++ /*dc_set_clocks_and_clock_state(context);*/
++
++ set_display_clock(&dc->current_context);
++ set_displaymarks(dc, &dc->current_context);
++}
++
++/*TODO: break out clock sources like timing gen/ encoder*/
++static void dce110_switch_dp_clk_src(
++ const struct dc_context *ctx,
++ const struct core_stream *stream)
++{
++ uint32_t pixel_rate_cntl_value;
++ uint32_t addr;
++ enum clock_source_id id = dal_clock_source_get_id(stream->clock_source);
++
++ /*TODO: proper offset*/
++ addr = mmCRTC0_PIXEL_RATE_CNTL + stream->controller_idx *
++ (mmCRTC1_PIXEL_RATE_CNTL - mmCRTC0_PIXEL_RATE_CNTL);
++
++ pixel_rate_cntl_value = dal_read_reg(ctx, addr);
++
++ if (id == CLOCK_SOURCE_ID_EXTERNAL) {
++
++ if (!get_reg_field_value(pixel_rate_cntl_value,
++ CRTC0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE)) {
++
++ set_reg_field_value(pixel_rate_cntl_value, 1,
++ CRTC0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE);
++ }
++
++ } else {
++ set_reg_field_value(pixel_rate_cntl_value,
++ 0,
++ CRTC0_PIXEL_RATE_CNTL,
++ DP_DTO0_ENABLE);
++
++ set_reg_field_value(pixel_rate_cntl_value,
++ id - 1,
++ CRTC0_PIXEL_RATE_CNTL,
++ CRTC0_PIXEL_RATE_SOURCE);
++ }
++ dal_write_reg(ctx, addr, pixel_rate_cntl_value);
++}
++
++static void switch_dp_clock_sources(
++ const struct dc_context *ctx,
++ struct validate_context *val_context)
++{
++ uint8_t i, j;
++ for (i = 0; i < val_context->target_count; i++) {
++ struct core_target *target = val_context->targets[i];
++ for (j = 0; j < target->stream_count; j++) {
++ struct core_stream *stream = target->streams[j];
++
++ if (dc_is_dp_signal(stream->signal)) {
++ struct clock_source *clk_src =
++ find_used_clk_src_for_sharing(
++ val_context, stream);
++
++ if (clk_src != stream->clock_source) {
++ unreference_clock_source(
++ &val_context->res_ctx,
++ stream->clock_source);
++ stream->clock_source = clk_src;
++ reference_clock_source(
++ &val_context->res_ctx, clk_src);
++ dce110_switch_dp_clk_src(ctx, stream);
++ }
++ }
++ }
++ }
++}
++
++/*******************************************************************************
++ * Public functions
++ ******************************************************************************/
++
++/*TODO: const validate_context*/
++static enum dc_status apply_ctx_to_hw(
++ const struct dc *dc,
++ struct validate_context *context)
++{
++ enum dc_status status;
++ uint8_t i;
++ struct resource_pool *pool = &context->res_ctx.pool;
++
++ update_bios_scratch_critical_state(context->res_ctx.pool.adapter_srv,
++ true);
++ set_safe_displaymarks(context);
++ /*TODO: when pplib works*/
++ /*dc_set_clocks_and_clock_state(context);*/
++
++ set_display_clock(context);
++
++ for (i = 0; i < pool->controller_count; i++) {
++ struct controller_ctx *ctlr_ctx
++ = &context->res_ctx.controller_ctx[i];
++ if (ctlr_ctx->flags.unchanged || !ctlr_ctx->stream)
++ continue;
++
++ status = apply_single_controller_ctx_to_hw(
++ i,
++ context,
++ dc);
++
++ if (DC_OK != status)
++ return status;
++ }
++ set_displaymarks(dc, context);
++
++ update_bios_scratch_critical_state(context->res_ctx.pool.adapter_srv,
++ false);
++
++ switch_dp_clock_sources(dc->ctx, context);
++
++ return DC_OK;
++}
++
++
++/*******************************************************************************
++ * Front End programming
++ ******************************************************************************/
++
++static bool setup_line_buffer_pixel_depth(
++ const struct core_stream *stream,
++ enum lb_pixel_depth depth,
++ bool blank)
++{
++ enum lb_pixel_depth current_depth;
++
++ struct timing_generator *tg = stream->tg;
++ struct transform *xfm = stream->xfm;
++
++ if (!dce110_transform_get_current_pixel_storage_depth(
++ xfm,
++ &current_depth))
++ return false;
++
++ if (current_depth != depth) {
++ if (blank)
++ dce110_timing_generator_wait_for_vblank(tg);
++
++ return dce110_transform_set_pixel_storage_depth(xfm, depth);
++ }
++
++ return false;
++}
++
++static void hw_sequencer_build_scaler_parameter_plane(
++ const struct core_stream *stream,
++ struct scaler_data *scaler_data)
++{
++ /*TODO: per pipe not per stream*/
++ /*TODO: get from feature from adapterservice*/
++ scaler_data->flags.bits.SHOW_COLOURED_BORDER = false;
++
++ scaler_data->flags.bits.SHOULD_PROGRAM_ALPHA = 1;
++
++ scaler_data->flags.bits.SHOULD_PROGRAM_VIEWPORT = 0;
++
++ scaler_data->flags.bits.SHOULD_UNLOCK = 0;
++
++ scaler_data->flags.bits.INTERLACED = 0;
++
++ scaler_data->dal_pixel_format = stream->format;
++
++ scaler_data->taps = stream->taps;
++
++ scaler_data->viewport = stream->viewport;
++
++ scaler_data->overscan = stream->overscan;
++
++ scaler_data->ratios = &stream->ratios;
++
++ /*TODO rotation and adjustment */
++ scaler_data->h_sharpness = 0;
++ scaler_data->v_sharpness = 0;
++
++}
++
++static void set_default_colors(
++ struct input_pixel_processor *ipp,
++ struct output_pixel_processor *opp,
++ enum pixel_format format,
++ enum color_space input_color_space,
++ enum color_space output_color_space,
++ enum dc_color_depth color_depth)
++{
++ struct default_adjustment default_adjust = { 0 };
++
++ default_adjust.force_hw_default = false;
++ default_adjust.color_space = output_color_space;
++ default_adjust.csc_adjust_type = GRAPHICS_CSC_ADJUST_TYPE_SW;
++ default_adjust.surface_pixel_format = format;
++
++ /* display color depth */
++ default_adjust.color_depth = color_depth;
++
++ /* Lb color depth */
++ default_adjust.lb_color_depth = LB_PIXEL_DEPTH_24BPP;
++ /*dal_hw_sequencer_translate_to_lb_color_depth(
++ build_params->
++ line_buffer_params[path_id][plane_id].depth);*/
++
++ dce110_opp_set_csc_default(opp, &default_adjust);
++}
++
++static void program_scaler(
++ uint8_t controller_idx,
++ struct timing_generator *tg,
++ struct transform *xfm,
++ const struct core_surface *surface,
++ const struct core_stream *stream)
++{
++ struct scaler_data scaler_data = { { 0 } };
++
++ hw_sequencer_build_scaler_parameter_plane(
++ stream,
++ &scaler_data);
++
++ setup_line_buffer_pixel_depth(
++ stream,
++ LB_PIXEL_DEPTH_24BPP,
++ false);
++
++ dce110_timing_generator_set_overscan_color_black(
++ tg,
++ surface->public.colorimetry.color_space);
++
++ dce110_transform_set_scaler(xfm, &scaler_data);
++
++ dce110_transform_update_viewport(
++ xfm,
++ &scaler_data.viewport,
++ false);
++}
++
++
++
++static void configure_locking(struct dc_context *ctx, uint8_t controller_id)
++{
++ /* main controller should be in mode 0 (master pipe) */
++ pipe_control_lock(
++ ctx,
++ controller_id,
++ PIPE_LOCK_CONTROL_MODE,
++ false);
++
++ /* TODO: for MPO finish the non-root controllers */
++}
++
++/**
++ * Program the Front End of the Pipe.
++ * The Back End was already programmed by Set Mode.
++ */
++static bool set_plane_config(
++ struct core_surface *surface,
++ struct core_target *target)
++{
++ const struct dc_crtc_timing *dc_crtc_timing =
++ &target->streams[0]->public.timing;
++ struct mem_input *mi = target->streams[0]->mi;
++ struct input_pixel_processor *ipp = target->streams[0]->ipp;
++ struct timing_generator *tg = target->streams[0]->tg;
++ struct transform *xfm = target->streams[0]->xfm;
++ struct output_pixel_processor *opp = target->streams[0]->opp;
++ struct dc_context *ctx = target->streams[0]->ctx;
++ uint8_t controller_idx = target->streams[0]->controller_idx;
++
++ /* TODO: Clean up change, possibly change to use same type */
++ enum color_space input_color_space =
++ surface_color_to_color_space(&(surface->public.colorimetry));
++
++ configure_locking(ctx, controller_idx);
++
++ /* While a non-root controller is programmed we
++ * have to lock the root controller. */
++ pipe_control_lock(
++ ctx,
++ controller_idx,
++ PIPE_LOCK_CONTROL_GRAPHICS |
++ PIPE_LOCK_CONTROL_SCL |
++ PIPE_LOCK_CONTROL_BLENDER |
++ PIPE_LOCK_CONTROL_SURFACE,
++ true);
++
++ dce110_program_pix_dur(mi, dc_crtc_timing->pix_clk_khz);
++
++ dce110_timing_generator_program_blanking(tg, dc_crtc_timing);
++
++ enable_fe_clock(ctx, controller_idx, true);
++
++ set_default_colors(
++ ipp,
++ opp,
++ target->streams[0]->format,
++ input_color_space,
++ get_output_color_space(dc_crtc_timing),
++ dc_crtc_timing->display_color_depth);
++
++ /* program Scaler */
++ program_scaler(
++ controller_idx, tg, xfm, surface, target->streams[0]);
++
++ set_blender_mode(
++ ctx,
++ controller_idx,
++ BLENDER_MODE_CURRENT_PIPE);
++
++#if 0
++ program_alpha_mode(
++ crtc,
++ &pl_cfg->attributes.blend_flags,
++ path_mode->mode.timing.pixel_encoding);
++#endif
++
++ dce110_mem_input_program_surface_config(
++ mi,
++ &surface->public);
++
++ pipe_control_lock(
++ ctx,
++ controller_idx,
++ PIPE_LOCK_CONTROL_GRAPHICS |
++ PIPE_LOCK_CONTROL_SCL |
++ PIPE_LOCK_CONTROL_BLENDER |
++ PIPE_LOCK_CONTROL_SURFACE,
++ false);
++
++ return true;
++}
++
++static bool update_plane_address(
++ const struct core_surface *surface,
++ struct core_target *target)
++{
++ struct dc_context *ctx = target->streams[0]->ctx;
++ struct mem_input *mi = target->streams[0]->mi;
++ uint8_t controller_id = target->streams[0]->controller_idx;
++
++ /* TODO: crtc should be per surface, NOT per-target */
++ pipe_control_lock(
++ ctx,
++ controller_id,
++ PIPE_LOCK_CONTROL_SURFACE,
++ true);
++
++ if (false == dce110_mem_input_program_surface_flip_and_addr(
++ mi, &surface->public.address, surface->public.flip_immediate))
++ return false;
++
++ pipe_control_lock(
++ ctx,
++ controller_id,
++ PIPE_LOCK_CONTROL_SURFACE,
++ false);
++
++ return true;
++}
++
++static void reset_single_stream_hw_ctx(struct core_stream *stream,
++ struct validate_context *context)
++{
++ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
++ deallocate_mst_payload(stream);
++
++ disable_stream(stream);
++ if (stream->audio) {
++ dal_audio_disable_output(stream->audio,
++ stream->stream_enc->id,
++ stream->signal);
++ stream->audio = NULL;
++ }
++
++ core_link_disable(stream);
++ dce110_timing_generator_blank_crtc(stream->tg);
++ dce110_timing_generator_disable_crtc(stream->tg);
++ dce110_deallocate_dmif_buffer(stream->mi, context->target_count);
++ dce110_transform_set_scaler_bypass(stream->xfm);
++ disable_stereo_mixer(stream->ctx);
++ unreference_clock_source(&context->res_ctx, stream->clock_source);
++}
++
++static void reset_hw_ctx(struct dc *dc,
++ struct validate_context *context,
++ uint8_t target_count)
++{
++ uint8_t i;
++ /* look up the targets that have been removed since last commit */
++ for (i = 0; i < dc->current_context.target_count; i++) {
++ uint8_t controller_idx = dc->current_context.targets[i]->
++ streams[0]->controller_idx;
++
++ if (context->res_ctx.controller_ctx[controller_idx].stream &&
++ !context->res_ctx.controller_ctx[controller_idx]
++ .flags.timing_changed)
++ continue;
++
++ reset_single_stream_hw_ctx(
++ dc->current_context.targets[i]->streams[0],
++ &dc->current_context);
++ }
++}
++
++static void power_down(struct validate_context *context)
++{
++ power_down_all_hw_blocks(context);
++ disable_vga_and_power_gate_all_controllers(context);
++
++}
++
++static bool wait_for_reset_trigger_to_occur(
++ struct dc_context *dc_ctx,
++ struct timing_generator *tg)
++{
++ bool rc = false;
++
++ /* To avoid endless loop we wait at most
++ * frames_to_wait_on_triggered_reset frames for the reset to occur. */
++ const uint32_t frames_to_wait_on_triggered_reset = 10;
++ uint32_t i;
++
++ for (i = 0; i < frames_to_wait_on_triggered_reset; i++) {
++
++ if (!dce110_timing_generator_is_counter_moving(tg)) {
++ DC_ERROR("TG counter is not moving!\n");
++ break;
++ }
++
++ if (dce110_timing_generator_did_triggered_reset_occur(tg)) {
++ rc = true;
++ /* usually occurs at i=1 */
++ DC_SYNC_INFO("GSL: reset occurred at wait count: %d\n",
++ i);
++ break;
++ }
++
++ /* Wait for one frame. */
++ dce110_timing_generator_wait_for_vactive(tg);
++ dce110_timing_generator_wait_for_vblank(tg);
++ }
++
++ if (false == rc)
++ DC_ERROR("GSL: Timeout on reset trigger!\n");
++
++ return rc;
++}
++
++/* Enable timing synchronization for a group of Timing Generators. */
++static void enable_timing_synchronization(
++ struct dc_context *dc_ctx,
++ uint32_t timing_generator_num,
++ struct timing_generator *tgs[])
++{
++ struct dcp_gsl_params gsl_params = { 0 };
++ struct trigger_params trigger_params;
++ uint32_t i;
++
++ DC_SYNC_INFO("GSL: Setting-up...\n");
++
++ gsl_params.gsl_group = SYNC_SOURCE_GSL_GROUP0;
++ gsl_params.gsl_purpose = DCP_GSL_PURPOSE_SURFACE_FLIP;
++
++ for (i = 0; i < timing_generator_num; i++) {
++ /* Designate a single TG in the group as a master.
++ * Since HW doesn't care which one, we always assign
++ * the 1st one in the group. */
++ gsl_params.timing_server = (0 == i ? true : false);
++
++ dce110_timing_generator_setup_global_swap_lock(tgs[i],
++ &gsl_params);
++ }
++
++ /* Reset slave controllers on master VSync */
++ DC_SYNC_INFO("GSL: enabling trigger-reset\n");
++ dc_service_memset(&trigger_params, 0, sizeof(trigger_params));
++
++ trigger_params.edge = TRIGGER_EDGE_DEFAULT;
++ trigger_params.source = SYNC_SOURCE_GSL_GROUP0;
++
++ for (i = 1 /* skip the master */; i < timing_generator_num; i++) {
++ dce110_timing_generator_enable_reset_trigger(tgs[i],
++ &trigger_params);
++
++ DC_SYNC_INFO("GSL: waiting for reset to occur.\n");
++ wait_for_reset_trigger_to_occur(dc_ctx, tgs[i]);
++
++ /* Regardless of success of the wait above, remove the reset or
++ * the driver will start timing out on Display requests. */
++ DC_SYNC_INFO("GSL: disabling trigger-reset.\n");
++ dce110_timing_generator_disable_reset_trigger(tgs[i]);
++ }
++
++ /* GSL Vblank synchronization is a one time sync mechanism, assumption
++ * is that the sync'ed displays will not drift out of sync over time*/
++ DC_SYNC_INFO("GSL: Restoring register states.\n");
++ for (i = 0; i < timing_generator_num; i++)
++ dce110_timing_generator_tear_down_global_swap_lock(tgs[i]);
++
++ DC_SYNC_INFO("GSL: Set-up complete.\n");
++}
++
++
++static const struct hw_sequencer_funcs dce110_funcs = {
++ .apply_ctx_to_hw = apply_ctx_to_hw,
++ .reset_hw_ctx = reset_hw_ctx,
++ .set_plane_config = set_plane_config,
++ .update_plane_address = update_plane_address,
++ .enable_memory_requests = dce110_timing_generator_unblank_crtc,
++ .disable_memory_requests = dce110_timing_generator_blank_crtc,
++ .cursor_set_attributes = dce110_ipp_cursor_set_attributes,
++ .cursor_set_position = dce110_ipp_cursor_set_position,
++ .set_gamma_ramp = set_gamma_ramp,
++ .power_down = power_down,
++ .enable_accelerated_mode = enable_accelerated_mode,
++ .get_crtc_positions = dce110_timing_generator_get_crtc_positions,
++ .get_vblank_counter = dce110_timing_generator_get_vblank_counter,
++ .enable_timing_synchronization = enable_timing_synchronization,
++ .disable_vga = dce110_timing_generator_disable_vga,
++ .encoder_create = dce110_link_encoder_create,
++ .encoder_destroy = dce110_link_encoder_destroy,
++ .encoder_power_up = dce110_link_encoder_power_up,
++ .encoder_enable_output = dce110_link_encoder_enable_output,
++ .encoder_disable_output = dce110_link_encoder_disable_output,
++ .encoder_set_dp_phy_pattern = dce110_link_encoder_set_dp_phy_pattern,
++ .encoder_dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings,
++ .encoder_set_lcd_backlight_level = dce110_link_encoder_set_lcd_backlight_level,
++ .clock_gating_power_up = dal_dc_clock_gating_dce110_power_up,
++ .transform_power_up = dce110_transform_power_up,
++ .construct_resource_pool = dce110_construct_resource_pool,
++ .destruct_resource_pool = dce110_destruct_resource_pool,
++ .validate_with_context = dce110_validate_with_context,
++ .validate_bandwidth = dce110_validate_bandwidth,
++ .set_afmt_memory_power_state = dce110_set_afmt_memory_power_state,
++ .enable_display_pipe_clock_gating = dce110_enable_display_pipe_clock_gating,
++ .enable_display_power_gating = dce110_enable_display_power_gating,
++ .program_bw = dce110_program_bw
++};
++
++bool dce110_hw_sequencer_construct(struct dc *dc)
++{
++ dc->hwss = dce110_funcs;
++
++ return true;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.h
+new file mode 100644
+index 0000000..def54df
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_hw_sequencer.h
+@@ -0,0 +1,36 @@
++/*
++* Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_HWSS_DCE110_H__
++#define __DC_HWSS_DCE110_H__
++
++#include "core_types.h"
++
++struct dc;
++
++bool dce110_hw_sequencer_construct(struct dc *dc);
++
++#endif /* __DC_HWSS_DCE110_H__ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c
+new file mode 100644
+index 0000000..04105ed
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.c
+@@ -0,0 +1,85 @@
++/*
++ * 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 "dal_services.h"
++#include "include/logger_interface.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_ipp.h"
++
++static const struct dce110_ipp_reg_offsets reg_offsets[] = {
++{
++ .dcp_offset = (mmDCP0_CUR_CONTROL - mmDCP0_CUR_CONTROL),
++},
++{
++ .dcp_offset = (mmDCP1_CUR_CONTROL - mmDCP0_CUR_CONTROL),
++},
++{
++ .dcp_offset = (mmDCP2_CUR_CONTROL - mmDCP0_CUR_CONTROL),
++}
++};
++
++bool dce110_ipp_construct(
++ struct dce110_ipp* ipp,
++ struct dc_context *ctx,
++ uint32_t inst)
++{
++ if ((inst < 1) || (inst > ARRAY_SIZE(reg_offsets)))
++ return false;
++
++ ipp->base.ctx = ctx;
++
++ ipp->base.inst = inst;
++
++ ipp->offsets = reg_offsets[inst-1];
++
++ return true;
++}
++
++void dce110_ipp_destroy(struct input_pixel_processor **ipp)
++{
++ dc_service_free((*ipp)->ctx, TO_DCE110_IPP(*ipp));
++ *ipp = NULL;
++}
++
++struct input_pixel_processor *dce110_ipp_create(
++ struct dc_context *ctx,
++ uint32_t inst)
++{
++ struct dce110_ipp *ipp =
++ dc_service_alloc(ctx, sizeof(struct dce110_ipp));
++
++ if (!ipp)
++ return NULL;
++
++ if (dce110_ipp_construct(ipp, ctx, inst))
++ return &ipp->base;
++
++ BREAK_TO_DEBUGGER();
++ dc_service_free(ctx, ipp);
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h
+new file mode 100644
+index 0000000..1da42ff
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp.h
+@@ -0,0 +1,90 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_IPP_DCE110_H__
++#define __DC_IPP_DCE110_H__
++
++#include "inc/ipp.h"
++
++#define TO_DCE110_IPP(input_pixel_processor)\
++ container_of(input_pixel_processor, struct dce110_ipp, base)
++
++struct dce110_ipp_reg_offsets {
++ uint32_t dcp_offset;
++};
++
++struct dce110_ipp {
++ struct input_pixel_processor base;
++ struct dce110_ipp_reg_offsets offsets;
++ struct dev_c_lut saved_palette[RGB_256X3X16];
++};
++
++bool dce110_ipp_construct(
++ struct dce110_ipp* ipp,
++ struct dc_context *ctx,
++ enum controller_id id);
++
++void dce110_ipp_destroy(struct input_pixel_processor **ipp);
++
++struct input_pixel_processor *dce110_ipp_create(
++ struct dc_context *ctx,
++ enum controller_id id);
++
++/* CURSOR RELATED */
++bool dce110_ipp_cursor_set_position(
++ struct input_pixel_processor *ipp,
++ const struct dc_cursor_position *position);
++
++bool dce110_ipp_cursor_set_attributes(
++ struct input_pixel_processor *ipp,
++ const struct dc_cursor_attributes *attributes);
++
++/* DEGAMMA RELATED */
++bool dce110_ipp_set_degamma(
++ struct input_pixel_processor *ipp,
++ const struct gamma_parameters *params,
++ bool force_bypass);
++
++void dce110_ipp_program_prescale(
++ struct input_pixel_processor *ipp,
++ enum pixel_format pixel_format);
++
++void dce110_ipp_set_legacy_input_gamma_mode(
++ struct input_pixel_processor *ipp,
++ bool is_legacy);
++
++bool dce110_ipp_set_legacy_input_gamma_ramp(
++ struct input_pixel_processor *ipp,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params);
++
++bool dce110_ipp_set_palette(
++ struct input_pixel_processor *ipp,
++ const struct dev_c_lut *palette,
++ uint32_t start,
++ uint32_t length,
++ enum pixel_format surface_pixel_format);
++
++#endif /*__DC_IPP_DCE110_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c
+new file mode 100644
+index 0000000..08b7940
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_cursor.c
+@@ -0,0 +1,256 @@
++/*
++ * 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 "dal_services.h"
++#include "include/logger_interface.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_ipp.h"
++
++#define CURSOR_COLOR_BLACK 0x00000000
++#define CURSOR_COLOR_WHITE 0xFFFFFFFF
++
++#define DCP_REG(reg)\
++ (reg + ipp110->offsets.dcp_offset)
++
++static void enable(
++ struct dce110_ipp *ipp110,
++ bool enable);
++
++static void lock(
++ struct dce110_ipp *ipp110,
++ bool enable);
++
++static void program_position(
++ struct dce110_ipp *ipp110,
++ uint32_t x,
++ uint32_t y);
++
++static bool program_control(
++ struct dce110_ipp *ipp110,
++ enum dc_cursor_color_format color_format,
++ bool enable_magnification,
++ bool inverse_transparent_clamping);
++
++static void program_hotspot(
++ struct dce110_ipp *ipp110,
++ uint32_t x,
++ uint32_t y);
++
++static void program_size(
++ struct dce110_ipp *ipp110,
++ uint32_t width,
++ uint32_t height);
++
++static void program_address(
++ struct dce110_ipp *ipp110,
++ PHYSICAL_ADDRESS_LOC address);
++
++
++bool dce110_ipp_cursor_set_position(
++ struct input_pixel_processor *ipp,
++ const struct dc_cursor_position *position)
++{
++ struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
++
++ /* lock cursor registers */
++ lock(ipp110, true);
++
++ /* Flag passed in structure differentiates cursor enable/disable. */
++ /* Update if it differs from cached state. */
++ enable(ipp110, position->enable);
++
++ program_position(ipp110, position->x, position->y);
++
++ if (position->hot_spot_enable)
++ program_hotspot(
++ ipp110,
++ position->x_origin,
++ position->y_origin);
++
++ /* unlock cursor registers */
++ lock(ipp110, false);
++
++ return true;
++}
++
++bool dce110_ipp_cursor_set_attributes(
++ struct input_pixel_processor *ipp,
++ const struct dc_cursor_attributes *attributes)
++{
++ struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
++ /* Lock cursor registers */
++ lock(ipp110, true);
++
++ /* Program cursor control */
++ program_control(
++ ipp110,
++ attributes->color_format,
++ attributes->attribute_flags.bits.ENABLE_MAGNIFICATION,
++ attributes->attribute_flags.bits.INVERSE_TRANSPARENT_CLAMPING);
++
++ /* Program hot spot coordinates */
++ program_hotspot(ipp110, attributes->x_hot, attributes->y_hot);
++
++ /*
++ * Program cursor size -- NOTE: HW spec specifies that HW register
++ * stores size as (height - 1, width - 1)
++ */
++ program_size(ipp110, attributes->width, attributes->height);
++
++ /* Program cursor surface address */
++ program_address(ipp110, attributes->address);
++
++ /* Unlock Cursor registers. */
++ lock(ipp110, false);
++
++ return true;
++}
++
++static void enable(
++ struct dce110_ipp *ipp110, bool enable)
++{
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmCUR_CONTROL);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++ set_reg_field_value(value, enable, CUR_CONTROL, CURSOR_EN);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++}
++
++static void lock(
++ struct dce110_ipp *ipp110, bool lock)
++{
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmCUR_UPDATE);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++ set_reg_field_value(value, lock, CUR_UPDATE, CURSOR_UPDATE_LOCK);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++}
++
++static void program_position(
++ struct dce110_ipp *ipp110,
++ uint32_t x,
++ uint32_t y)
++{
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmCUR_POSITION);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++ set_reg_field_value(value, x, CUR_POSITION, CURSOR_X_POSITION);
++ set_reg_field_value(value, y, CUR_POSITION, CURSOR_Y_POSITION);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++}
++
++static bool program_control(
++ struct dce110_ipp *ipp110,
++ enum dc_cursor_color_format color_format,
++ bool enable_magnification,
++ bool inverse_transparent_clamping)
++{
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmCUR_CONTROL);
++ uint32_t mode = 0;
++
++ switch (color_format) {
++ case CURSOR_MODE_MONO:
++ mode = 0;
++ break;
++ case CURSOR_MODE_COLOR_1BIT_AND:
++ mode = 1;
++ break;
++ case CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA:
++ mode = 2;
++ break;
++ case CURSOR_MODE_COLOR_UN_PRE_MULTIPLIED_ALPHA:
++ mode = 3;
++ break;
++ default:
++ return false;
++ }
++
++ set_reg_field_value(value, mode, CUR_CONTROL, CURSOR_MODE);
++ set_reg_field_value(value, enable_magnification,
++ CUR_CONTROL, CURSOR_2X_MAGNIFY);
++ set_reg_field_value(value, inverse_transparent_clamping,
++ CUR_CONTROL, CUR_INV_TRANS_CLAMP);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++
++ if (color_format == CURSOR_MODE_MONO) {
++ addr = DCP_REG(mmCUR_COLOR1);
++ dal_write_reg(ipp110->base.ctx, addr, CURSOR_COLOR_BLACK);
++ addr = DCP_REG(mmCUR_COLOR2);
++ dal_write_reg(ipp110->base.ctx, addr, CURSOR_COLOR_WHITE);
++ }
++ return true;
++}
++
++static void program_hotspot(
++ struct dce110_ipp *ipp110,
++ uint32_t x,
++ uint32_t y)
++{
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmCUR_HOT_SPOT);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++ set_reg_field_value(value, x, CUR_HOT_SPOT, CURSOR_HOT_SPOT_X);
++ set_reg_field_value(value, y, CUR_HOT_SPOT, CURSOR_HOT_SPOT_Y);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++}
++
++static void program_size(
++ struct dce110_ipp *ipp110,
++ uint32_t width,
++ uint32_t height)
++{
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmCUR_SIZE);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++ set_reg_field_value(value, width, CUR_SIZE, CURSOR_WIDTH);
++ set_reg_field_value(value, height, CUR_SIZE, CURSOR_HEIGHT);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++}
++
++static void program_address(
++ struct dce110_ipp *ipp110,
++ PHYSICAL_ADDRESS_LOC address)
++{
++ uint32_t addr = DCP_REG(mmCUR_SURFACE_ADDRESS_HIGH);
++ /* SURFACE_ADDRESS_HIGH: Higher order bits (39:32) of hardware cursor
++ * surface base address in byte. It is 4K byte aligned.
++ * The correct way to program cursor surface address is to first write
++ * to CUR_SURFACE_ADDRESS_HIGH, and then write to CUR_SURFACE_ADDRESS */
++
++ dal_write_reg(ipp110->base.ctx, addr, address.high_part);
++
++ addr = DCP_REG(mmCUR_SURFACE_ADDRESS);
++ dal_write_reg(ipp110->base.ctx, addr, address.low_part);
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c
+new file mode 100644
+index 0000000..f2e8ef4
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_ipp_gamma.c
+@@ -0,0 +1,877 @@
++/*
++ * 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 "dal_services.h"
++#include "include/logger_interface.h"
++#include "include/fixed31_32.h"
++#include "basics/conversion.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_ipp.h"
++
++#define DCP_REG(reg)\
++ (reg + ipp110->offsets.dcp_offset)
++
++enum {
++ MAX_INPUT_LUT_ENTRY = 256
++};
++
++/* CALCULATION OPERATIONS*/
++static void convert_256_lut_entries_to_gxo_format(
++ const struct gamma_ramp_rgb256x3x16 *lut,
++ struct dev_c_lut16 *gamma)
++{
++ uint32_t i = 0;
++
++ ASSERT(lut);
++ ASSERT(gamma);
++
++ do {
++ gamma->red = lut->red[i];
++ gamma->green = lut->green[i];
++ gamma->blue = lut->blue[i];
++
++ ++gamma;
++ ++i;
++ } while (i != MAX_INPUT_LUT_ENTRY);
++}
++
++static void convert_udx_gamma_entries_to_gxo_format(
++ const struct gamma_ramp_dxgi_1 *lut,
++ struct dev_c_lut16 *gamma)
++{
++ /* TODO here we deal with DXGI gamma table,
++ * originally, values was expressed as 'float',
++ * now values expressed as 'dal_fixed20_12'. */
++}
++
++/*PROTOTYPE DECLARATIONS*/
++static void set_lut_inc(
++ struct dce110_ipp *ipp110,
++ uint8_t inc,
++ bool is_float,
++ bool is_signed);
++
++static void select_lut(struct dce110_ipp *ipp110);
++
++static void program_black_offsets(
++ struct dce110_ipp *ipp110,
++ struct dev_c_lut16 *offset);
++
++static void program_white_offsets(
++ struct dce110_ipp *ipp110,
++ struct dev_c_lut16 *offset);
++
++static void program_black_white_offset(
++ struct dce110_ipp *ipp110,
++ enum pixel_format surface_pixel_format);
++
++static void program_lut_gamma(
++ struct dce110_ipp *ipp110,
++ const struct dev_c_lut16 *gamma,
++ const struct gamma_parameters *params);
++
++static void program_prescale(
++ struct dce110_ipp *ipp110,
++ enum pixel_format pixel_format);
++
++static void set_legacy_input_gamma_mode(
++ struct dce110_ipp *ipp110,
++ bool is_legacy);
++
++static bool set_legacy_input_gamma_ramp_rgb256x3x16(
++ struct dce110_ipp *ipp110,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params);
++
++static bool set_legacy_input_gamma_ramp_dxgi1(
++ struct dce110_ipp *ipp110,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params);
++
++static bool set_default_gamma(
++ struct dce110_ipp *ipp110,
++ enum pixel_format surface_pixel_format);
++
++static void set_degamma(
++ struct dce110_ipp *ipp110,
++ const struct gamma_parameters *params,
++ bool force_bypass);
++
++bool dce110_ipp_set_legacy_input_gamma_ramp(
++ struct input_pixel_processor *ipp,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params)
++{
++ struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
++
++ switch (gamma_ramp->type) {
++ case GAMMA_RAMP_RBG256X3X16:
++ return set_legacy_input_gamma_ramp_rgb256x3x16(
++ ipp110, gamma_ramp, params);
++ case GAMMA_RAMP_DXGI_1:
++ return set_legacy_input_gamma_ramp_dxgi1(
++ ipp110, gamma_ramp, params);
++ default:
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++}
++
++bool dce110_ipp_set_palette(
++ struct input_pixel_processor *ipp,
++ const struct dev_c_lut *palette,
++ uint32_t start,
++ uint32_t length,
++ enum pixel_format surface_pixel_format)
++{
++ struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
++ uint32_t i;
++
++ if (((start + length) > MAX_INPUT_LUT_ENTRY) || (NULL == palette)) {
++ BREAK_TO_DEBUGGER();
++ /* wrong input */
++ return false;
++ }
++
++ for (i = start; i < start + length; i++) {
++ ipp110->saved_palette[i] = palette[i];
++ ipp110->saved_palette[i] = palette[i];
++ ipp110->saved_palette[i] = palette[i];
++ }
++
++ return set_default_gamma(ipp110, surface_pixel_format);
++}
++
++bool dce110_ipp_set_degamma(
++ struct input_pixel_processor *ipp,
++ const struct gamma_parameters *params,
++ bool force_bypass)
++{
++ struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
++
++ set_degamma(ipp110, params, force_bypass);
++
++ return true;
++}
++
++void dce110_ipp_program_prescale(
++ struct input_pixel_processor *ipp,
++ enum pixel_format pixel_format)
++{
++ struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
++
++ program_prescale(ipp110, pixel_format);
++}
++
++void dce110_ipp_set_legacy_input_gamma_mode(
++ struct input_pixel_processor *ipp,
++ bool is_legacy)
++{
++ struct dce110_ipp *ipp110 = TO_DCE110_IPP(ipp);
++
++ set_legacy_input_gamma_mode(ipp110, is_legacy);
++}
++
++static void set_lut_inc(
++ struct dce110_ipp *ipp110,
++ uint8_t inc,
++ bool is_float,
++ bool is_signed)
++{
++ const uint32_t addr = DCP_REG(mmDC_LUT_CONTROL);
++
++ uint32_t value = dal_read_reg(ipp110->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ inc,
++ DC_LUT_CONTROL,
++ DC_LUT_INC_R);
++
++ set_reg_field_value(
++ value,
++ inc,
++ DC_LUT_CONTROL,
++ DC_LUT_INC_G);
++
++ set_reg_field_value(
++ value,
++ inc,
++ DC_LUT_CONTROL,
++ DC_LUT_INC_B);
++
++ set_reg_field_value(
++ value,
++ is_float,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_R_FLOAT_POINT_EN);
++
++ set_reg_field_value(
++ value,
++ is_float,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_G_FLOAT_POINT_EN);
++
++ set_reg_field_value(
++ value,
++ is_float,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_B_FLOAT_POINT_EN);
++
++ set_reg_field_value(
++ value,
++ is_signed,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_R_SIGNED_EN);
++
++ set_reg_field_value(
++ value,
++ is_signed,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_G_SIGNED_EN);
++
++ set_reg_field_value(
++ value,
++ is_signed,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_B_SIGNED_EN);
++
++ dal_write_reg(ipp110->base.ctx, addr, value);
++}
++
++static void select_lut(struct dce110_ipp *ipp110)
++{
++ uint32_t value = 0;
++
++ set_lut_inc(ipp110, 0, false, false);
++
++ {
++ const uint32_t addr = DCP_REG(mmDC_LUT_WRITE_EN_MASK);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++
++ /* enable all */
++ set_reg_field_value(
++ value,
++ 0x7,
++ DC_LUT_WRITE_EN_MASK,
++ DC_LUT_WRITE_EN_MASK);
++
++ dal_write_reg(ipp110->base.ctx, addr, value);
++ }
++
++ {
++ const uint32_t addr = DCP_REG(mmDC_LUT_RW_MODE);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_LUT_RW_MODE,
++ DC_LUT_RW_MODE);
++
++ dal_write_reg(ipp110->base.ctx, addr, value);
++ }
++
++ {
++ const uint32_t addr = DCP_REG(mmDC_LUT_CONTROL);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++
++ /* 00 - new u0.12 */
++ set_reg_field_value(
++ value,
++ 3,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_R_FORMAT);
++
++ set_reg_field_value(
++ value,
++ 3,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_G_FORMAT);
++
++ set_reg_field_value(
++ value,
++ 3,
++ DC_LUT_CONTROL,
++ DC_LUT_DATA_B_FORMAT);
++
++ dal_write_reg(ipp110->base.ctx, addr, value);
++ }
++
++ {
++ const uint32_t addr = DCP_REG(mmDC_LUT_RW_INDEX);
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_LUT_RW_INDEX,
++ DC_LUT_RW_INDEX);
++
++ dal_write_reg(ipp110->base.ctx, addr, value);
++ }
++}
++
++static void program_black_offsets(
++ struct dce110_ipp *ipp110,
++ struct dev_c_lut16 *offset)
++{
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmDC_LUT_BLACK_OFFSET_RED),
++ offset->red);
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmDC_LUT_BLACK_OFFSET_GREEN),
++ offset->green);
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmDC_LUT_BLACK_OFFSET_BLUE),
++ offset->blue);
++}
++
++static void program_white_offsets(
++ struct dce110_ipp *ipp110,
++ struct dev_c_lut16 *offset)
++{
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmDC_LUT_WHITE_OFFSET_RED),
++ offset->red);
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmDC_LUT_WHITE_OFFSET_GREEN),
++ offset->green);
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmDC_LUT_WHITE_OFFSET_BLUE),
++ offset->blue);
++}
++
++static void program_black_white_offset(
++ struct dce110_ipp *ipp110,
++ enum pixel_format surface_pixel_format)
++{
++ struct dev_c_lut16 black_offset;
++ struct dev_c_lut16 white_offset;
++
++ /* get black offset */
++
++ switch (surface_pixel_format) {
++ case PIXEL_FORMAT_FP16:
++ /* sRGB gamut, [0.0...1.0] */
++ black_offset.red = 0;
++ black_offset.green = 0;
++ black_offset.blue = 0;
++ break;
++
++ case PIXEL_FORMAT_ARGB2101010_XRBIAS:
++ /* [-1.0...3.0] */
++ black_offset.red = 0x100;
++ black_offset.green = 0x100;
++ black_offset.blue = 0x100;
++ break;
++
++ default:
++ black_offset.red = 0;
++ black_offset.green = 0;
++ black_offset.blue = 0;
++ }
++
++ /* get white offset */
++
++ switch (surface_pixel_format) {
++ case PIXEL_FORMAT_FP16:
++ white_offset.red = 0x3BFF;
++ white_offset.green = 0x3BFF;
++ white_offset.blue = 0x3BFF;
++ break;
++
++ case PIXEL_FORMAT_ARGB2101010_XRBIAS:
++ white_offset.red = 0x37E;
++ white_offset.green = 0x37E;
++ white_offset.blue = 0x37E;
++ break;
++
++ case PIXEL_FORMAT_ARGB8888:
++ white_offset.red = 0xFF;
++ white_offset.green = 0xFF;
++ white_offset.blue = 0xFF;
++ break;
++
++ default:
++ white_offset.red = 0x3FF;
++ white_offset.green = 0x3FF;
++ white_offset.blue = 0x3FF;
++ }
++
++ program_black_offsets(ipp110, &black_offset);
++ program_white_offsets(ipp110, &white_offset);
++}
++
++static void program_lut_gamma(
++ struct dce110_ipp *ipp110,
++ const struct dev_c_lut16 *gamma,
++ const struct gamma_parameters *params)
++{
++ uint32_t i = 0;
++ uint32_t value = 0;
++ uint32_t addr;
++
++ {
++ uint8_t max_tries = 10;
++ uint8_t counter = 0;
++
++ /* Power on LUT memory */
++ value = dal_read_reg(
++ ipp110->base.ctx, DCP_REG(mmDCFE_MEM_PWR_CTRL));
++
++ set_reg_field_value(
++ value,
++ 1,
++ DCFE_MEM_PWR_CTRL,
++ DCP_REGAMMA_MEM_PWR_DIS);
++
++ dal_write_reg(
++ ipp110->base.ctx, DCP_REG(mmDCFE_MEM_PWR_CTRL), value);
++
++ while (counter < max_tries) {
++ value =
++ dal_read_reg(
++ ipp110->base.ctx,
++ DCP_REG(mmDCFE_MEM_PWR_STATUS));
++
++ if (get_reg_field_value(
++ value,
++ DCFE_MEM_PWR_STATUS,
++ DCP_REGAMMA_MEM_PWR_STATE) == 0)
++ break;
++
++ ++counter;
++ }
++
++ if (counter == max_tries) {
++ dal_logger_write(ipp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: regamma lut was not powered on in a timely manner, programming still proceeds\n",
++ __func__);
++ }
++ }
++
++ program_black_white_offset(ipp110, params->surface_pixel_format);
++
++ select_lut(ipp110);
++
++ if (params->surface_pixel_format == PIXEL_FORMAT_INDEX8) {
++ addr = DCP_REG(mmDC_LUT_SEQ_COLOR);
++
++ do {
++ struct dev_c_lut *index =
++ ipp110->saved_palette + i;
++
++ set_reg_field_value(
++ value,
++ gamma[index->red].red,
++ DC_LUT_SEQ_COLOR,
++ DC_LUT_SEQ_COLOR);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++
++
++ set_reg_field_value(
++ value,
++ gamma[index->green].green,
++ DC_LUT_SEQ_COLOR,
++ DC_LUT_SEQ_COLOR);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++
++
++ set_reg_field_value(
++ value,
++ gamma[index->blue].blue,
++ DC_LUT_SEQ_COLOR,
++ DC_LUT_SEQ_COLOR);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++
++ ++i;
++ } while (i != RGB_256X3X16);
++ } else {
++ addr = DCP_REG(mmDC_LUT_SEQ_COLOR);
++
++ do {
++ set_reg_field_value(
++ value,
++ gamma[i].red,
++ DC_LUT_SEQ_COLOR,
++ DC_LUT_SEQ_COLOR);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++
++
++ set_reg_field_value(
++ value,
++ gamma[i].green,
++ DC_LUT_SEQ_COLOR,
++ DC_LUT_SEQ_COLOR);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++
++
++ set_reg_field_value(
++ value,
++ gamma[i].blue,
++ DC_LUT_SEQ_COLOR,
++ DC_LUT_SEQ_COLOR);
++ dal_write_reg(ipp110->base.ctx, addr, value);
++
++ ++i;
++ } while (i != RGB_256X3X16);
++ }
++
++ /* we are done with DCP LUT memory; re-enable low power mode */
++ value = dal_read_reg(ipp110->base.ctx, DCP_REG(mmDCFE_MEM_PWR_CTRL));
++
++ set_reg_field_value(
++ value,
++ 0,
++ DCFE_MEM_PWR_CTRL,
++ DCP_REGAMMA_MEM_PWR_DIS);
++
++ dal_write_reg(ipp110->base.ctx, DCP_REG(mmDCFE_MEM_PWR_CTRL), value);
++}
++
++static void program_prescale(
++ struct dce110_ipp *ipp110,
++ enum pixel_format pixel_format)
++{
++ uint32_t prescale_control;
++ uint32_t prescale_values_grph_r = 0;
++ uint32_t prescale_values_grph_g = 0;
++ uint32_t prescale_values_grph_b = 0;
++
++ uint32_t prescale_num;
++ uint32_t prescale_denom = 1;
++ uint16_t prescale_hw;
++ uint32_t bias_num = 0;
++ uint32_t bias_denom = 1;
++ uint16_t bias_hw;
++
++ const uint32_t addr_control = DCP_REG(mmPRESCALE_GRPH_CONTROL);
++
++ prescale_control = dal_read_reg(ipp110->base.ctx, addr_control);
++
++ set_reg_field_value(
++ prescale_control,
++ 0,
++ PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_BYPASS);
++
++ switch (pixel_format) {
++ case PIXEL_FORMAT_RGB565:
++ prescale_num = 64;
++ prescale_denom = 63;
++ break;
++
++ case PIXEL_FORMAT_ARGB8888:
++ /* This function should only be called when using regamma
++ * and bypassing legacy INPUT GAMMA LUT (function name is
++ * misleading)
++ */
++ prescale_num = 256;
++ prescale_denom = 255;
++ break;
++
++ case PIXEL_FORMAT_ARGB2101010:
++ prescale_num = 1024;
++ prescale_denom = 1023;
++ break;
++
++ case PIXEL_FORMAT_ARGB2101010_XRBIAS:
++ prescale_num = 1024;
++ prescale_denom = 510;
++ bias_num = 384;
++ bias_denom = 1024;
++ break;
++
++ case PIXEL_FORMAT_FP16:
++ prescale_num = 1;
++ break;
++
++ default:
++ prescale_num = 1;
++
++ set_reg_field_value(
++ prescale_control,
++ 1,
++ PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_BYPASS);
++ }
++
++ prescale_hw = fixed_point_to_int_frac(
++ dal_fixed31_32_from_fraction(prescale_num, prescale_denom),
++ 2, 13);
++
++ bias_hw = fixed_point_to_int_frac(
++ dal_fixed31_32_from_fraction(bias_num, bias_denom),
++ 2, 13);
++
++
++ set_reg_field_value(
++ prescale_values_grph_r,
++ prescale_hw,
++ PRESCALE_VALUES_GRPH_R,
++ GRPH_PRESCALE_SCALE_R);
++
++ set_reg_field_value(
++ prescale_values_grph_r,
++ bias_hw,
++ PRESCALE_VALUES_GRPH_R,
++ GRPH_PRESCALE_BIAS_R);
++
++
++ set_reg_field_value(
++ prescale_values_grph_g,
++ prescale_hw,
++ PRESCALE_VALUES_GRPH_G,
++ GRPH_PRESCALE_SCALE_G);
++
++ set_reg_field_value(
++ prescale_values_grph_g,
++ bias_hw,
++ PRESCALE_VALUES_GRPH_G,
++ GRPH_PRESCALE_BIAS_G);
++
++
++ set_reg_field_value(
++ prescale_values_grph_b,
++ prescale_hw,
++ PRESCALE_VALUES_GRPH_B,
++ GRPH_PRESCALE_SCALE_B);
++
++ set_reg_field_value(
++ prescale_values_grph_b,
++ bias_hw,
++ PRESCALE_VALUES_GRPH_B,
++ GRPH_PRESCALE_BIAS_B);
++
++ dal_write_reg(ipp110->base.ctx,
++ addr_control, prescale_control);
++
++ {
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmPRESCALE_VALUES_GRPH_R),
++ prescale_values_grph_r);
++ }
++
++ {
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmPRESCALE_VALUES_GRPH_G),
++ prescale_values_grph_g);
++ }
++
++ {
++ dal_write_reg(ipp110->base.ctx,
++ DCP_REG(mmPRESCALE_VALUES_GRPH_B),
++ prescale_values_grph_b);
++ }
++}
++
++static void set_legacy_input_gamma_mode(
++ struct dce110_ipp *ipp110,
++ bool is_legacy)
++{
++ const uint32_t addr = DCP_REG(mmINPUT_GAMMA_CONTROL);
++ uint32_t value = dal_read_reg(ipp110->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ !is_legacy,
++ INPUT_GAMMA_CONTROL,
++ GRPH_INPUT_GAMMA_MODE);
++
++ dal_write_reg(ipp110->base.ctx, addr, value);
++}
++
++static bool set_legacy_input_gamma_ramp_rgb256x3x16(
++ struct dce110_ipp *ipp110,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params)
++{
++ struct dev_c_lut16 *gamma16 =
++ dc_service_alloc(
++ ipp110->base.ctx,
++ sizeof(struct dev_c_lut16) * MAX_INPUT_LUT_ENTRY);
++
++ if (!gamma16)
++ return false;
++
++ convert_256_lut_entries_to_gxo_format(
++ &gamma_ramp->gamma_ramp_rgb256x3x16, gamma16);
++
++ if ((params->surface_pixel_format != PIXEL_FORMAT_ARGB2101010) &&
++ (params->surface_pixel_format !=
++ PIXEL_FORMAT_ARGB2101010_XRBIAS) &&
++ (params->surface_pixel_format != PIXEL_FORMAT_FP16)) {
++ program_lut_gamma(ipp110, gamma16, params);
++ dc_service_free(ipp110->base.ctx, gamma16);
++ return true;
++ }
++
++ /* TODO process DirectX-specific formats*/
++ dc_service_free(ipp110->base.ctx, gamma16);
++ return false;
++}
++
++static bool set_legacy_input_gamma_ramp_dxgi1(
++ struct dce110_ipp *ipp110,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params)
++{
++ struct dev_c_lut16 *gamma16 =
++ dc_service_alloc(
++ ipp110->base.ctx,
++ sizeof(struct dev_c_lut16) * MAX_INPUT_LUT_ENTRY);
++
++ if (!gamma16)
++ return false;
++
++ convert_udx_gamma_entries_to_gxo_format(
++ &gamma_ramp->gamma_ramp_dxgi1, gamma16);
++
++ if ((params->surface_pixel_format != PIXEL_FORMAT_ARGB2101010) &&
++ (params->surface_pixel_format !=
++ PIXEL_FORMAT_ARGB2101010_XRBIAS) &&
++ (params->surface_pixel_format != PIXEL_FORMAT_FP16)) {
++ program_lut_gamma(ipp110, gamma16, params);
++ dc_service_free(ipp110->base.ctx, gamma16);
++ return true;
++ }
++
++ /* TODO process DirectX-specific formats*/
++ dc_service_free(ipp110->base.ctx, gamma16);
++ return false;
++}
++
++static bool set_default_gamma(
++ struct dce110_ipp *ipp110,
++ enum pixel_format surface_pixel_format)
++{
++ uint32_t i;
++
++ struct dev_c_lut16 *gamma16 = NULL;
++ struct gamma_parameters *params = NULL;
++
++ gamma16 = dc_service_alloc(
++ ipp110->base.ctx,
++ sizeof(struct dev_c_lut16) * MAX_INPUT_LUT_ENTRY);
++
++ if (!gamma16)
++ return false;
++
++ params = dc_service_alloc(ipp110->base.ctx, sizeof(*params));
++
++ if (!params) {
++ dc_service_free(ipp110->base.ctx, gamma16);
++ return false;
++ }
++
++ for (i = 0; i < MAX_INPUT_LUT_ENTRY; i++) {
++ gamma16[i].red = gamma16[i].green =
++ gamma16[i].blue = (uint16_t) (i << 8);
++ }
++
++ params->surface_pixel_format = surface_pixel_format;
++ params->regamma_adjust_type = GRAPHICS_REGAMMA_ADJUST_HW;
++ params->degamma_adjust_type = GRAPHICS_DEGAMMA_ADJUST_HW;
++ params->selected_gamma_lut = GRAPHICS_GAMMA_LUT_REGAMMA;
++ params->disable_adjustments = false;
++
++ params->regamma.features.value = 0;
++
++ params->regamma.features.bits.GAMMA_RAMP_ARRAY = 0;
++ params->regamma.features.bits.GRAPHICS_DEGAMMA_SRGB = 1;
++ params->regamma.features.bits.OVERLAY_DEGAMMA_SRGB = 1;
++
++ for (i = 0; i < 3; i++) {
++ params->regamma.gamma_coeff.a0[i] = 31308;
++ params->regamma.gamma_coeff.a1[i] = 12920;
++ params->regamma.gamma_coeff.a2[i] = 55;
++ params->regamma.gamma_coeff.a3[i] = 55;
++ params->regamma.gamma_coeff.gamma[i] = 2400;
++
++ }
++
++ program_lut_gamma(ipp110, gamma16, params);
++
++ dc_service_free(ipp110->base.ctx, gamma16);
++ dc_service_free(ipp110->base.ctx, params);
++
++ return true;
++}
++
++static void set_degamma(
++ struct dce110_ipp *ipp110,
++ const struct gamma_parameters *params,
++ bool force_bypass)
++{
++ uint32_t value;
++ const uint32_t addr = DCP_REG(mmDEGAMMA_CONTROL);
++ uint32_t degamma_type =
++ params->regamma.features.bits.GRAPHICS_DEGAMMA_SRGB == 1 ?
++ 1 : 2;
++
++ value = dal_read_reg(ipp110->base.ctx, addr);
++
++ /* if by pass - no degamma
++ * when legacy and regamma LUT's we do degamma */
++ if (params->degamma_adjust_type == GRAPHICS_DEGAMMA_ADJUST_BYPASS ||
++ (params->surface_pixel_format == PIXEL_FORMAT_FP16 &&
++ params->selected_gamma_lut ==
++ GRAPHICS_GAMMA_LUT_REGAMMA))
++ degamma_type = 0;
++
++ if (force_bypass)
++ degamma_type = 0;
++
++ set_reg_field_value(
++ value,
++ degamma_type,
++ DEGAMMA_CONTROL,
++ GRPH_DEGAMMA_MODE);
++
++ set_reg_field_value(
++ value,
++ degamma_type,
++ DEGAMMA_CONTROL,
++ CURSOR_DEGAMMA_MODE);
++
++ set_reg_field_value(
++ value,
++ degamma_type,
++ DEGAMMA_CONTROL,
++ CURSOR2_DEGAMMA_MODE);
++
++ dal_write_reg(ipp110->base.ctx, addr, value);
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
+new file mode 100644
+index 0000000..0297bd3
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.c
+@@ -0,0 +1,2049 @@
++/*
++ * 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 "dal_services.h"
++#include "core_types.h"
++#include "link_encoder_types.h"
++#include "dce110_link_encoder.h"
++#include "i2caux_interface.h"
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++#include "dce/dce_11_0_enum.h"
++
++#define DELAY_AFTER_PIXEL_FORMAT_CHANGE 0 /* ms */
++/* For current ASICs pixel clock - 600MHz */
++#define MAX_ENCODER_CLK 600000
++
++#define DCE11_UNIPHY_MAX_PIXEL_CLK_IN_KHZ 600000
++
++#define DEFAULT_AUX_MAX_DATA_SIZE 16
++#define AUX_MAX_DEFER_WRITE_RETRY 20
++/*
++ * @brief
++ * Trigger Source Select
++ * ASIC-dependent, actual values for register programming
++ */
++#define DCE110_DIG_FE_SOURCE_SELECT_INVALID 0x0
++#define DCE110_DIG_FE_SOURCE_SELECT_DIGA 0x1
++#define DCE110_DIG_FE_SOURCE_SELECT_DIGB 0x2
++#define DCE110_DIG_FE_SOURCE_SELECT_DIGC 0x4
++
++/* all values are in milliseconds */
++/* For eDP, after power-up/power/down,
++ * 300/500 msec max. delay from LCDVCC to black video generation */
++#define PANEL_POWER_UP_TIMEOUT 300
++#define PANEL_POWER_DOWN_TIMEOUT 500
++#define HPD_CHECK_INTERVAL 10
++
++/* Minimum pixel clock, in KHz. For TMDS signal is 25.00 MHz */
++#define TMDS_MIN_PIXEL_CLOCK 25000
++/* Maximum pixel clock, in KHz. For TMDS signal is 165.00 MHz */
++#define TMDS_MAX_PIXEL_CLOCK 165000
++/* For current ASICs pixel clock - 600MHz */
++#define MAX_ENCODER_CLOCK 600000
++
++enum {
++ DP_MST_UPDATE_MAX_RETRY = 50
++};
++
++#ifndef mmDP_DPHY_INTERNAL_CTRL
++ #define mmDP_DPHY_INTERNAL_CTRL 0x4aa7
++ #define mmDP0_DP_DPHY_INTERNAL_CTRL 0x4aa7
++ #define mmDP1_DP_DPHY_INTERNAL_CTRL 0x4ba7
++ #define mmDP2_DP_DPHY_INTERNAL_CTRL 0x4ca7
++ #define mmDP3_DP_DPHY_INTERNAL_CTRL 0x4da7
++ #define mmDP4_DP_DPHY_INTERNAL_CTRL 0x4ea7
++ #define mmDP5_DP_DPHY_INTERNAL_CTRL 0x4fa7
++ #define mmDP6_DP_DPHY_INTERNAL_CTRL 0x54a7
++ #define mmDP7_DP_DPHY_INTERNAL_CTRL 0x56a7
++ #define mmDP8_DP_DPHY_INTERNAL_CTRL 0x57a7
++#endif
++
++
++static const uint32_t fe_engine_offsets[] = {
++ mmDIG0_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG1_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG2_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++};
++
++
++static enum transmitter translate_encoder_to_transmitter(
++ struct graphics_object_id encoder)
++{
++ switch (encoder.id) {
++ case ENCODER_ID_INTERNAL_UNIPHY:
++ switch (encoder.enum_id) {
++ case ENUM_ID_1:
++ return TRANSMITTER_UNIPHY_A;
++ case ENUM_ID_2:
++ return TRANSMITTER_UNIPHY_B;
++ default:
++ return TRANSMITTER_UNKNOWN;
++ }
++ break;
++ case ENCODER_ID_INTERNAL_UNIPHY1:
++ switch (encoder.enum_id) {
++ case ENUM_ID_1:
++ return TRANSMITTER_UNIPHY_C;
++ case ENUM_ID_2:
++ return TRANSMITTER_UNIPHY_D;
++ default:
++ return TRANSMITTER_UNKNOWN;
++ }
++ break;
++ case ENCODER_ID_INTERNAL_UNIPHY2:
++ switch (encoder.enum_id) {
++ case ENUM_ID_1:
++ return TRANSMITTER_UNIPHY_E;
++ case ENUM_ID_2:
++ return TRANSMITTER_UNIPHY_F;
++ default:
++ return TRANSMITTER_UNKNOWN;
++ }
++ break;
++ case ENCODER_ID_INTERNAL_UNIPHY3:
++ switch (encoder.enum_id) {
++ case ENUM_ID_1:
++ return TRANSMITTER_UNIPHY_G;
++ default:
++ return TRANSMITTER_UNKNOWN;
++ }
++ break;
++ case ENCODER_ID_EXTERNAL_NUTMEG:
++ switch (encoder.enum_id) {
++ case ENUM_ID_1:
++ return TRANSMITTER_NUTMEG_CRT;
++ default:
++ return TRANSMITTER_UNKNOWN;
++ }
++ break;
++ case ENCODER_ID_EXTERNAL_TRAVIS:
++ switch (encoder.enum_id) {
++ case ENUM_ID_1:
++ return TRANSMITTER_TRAVIS_CRT;
++ case ENUM_ID_2:
++ return TRANSMITTER_TRAVIS_LCD;
++ default:
++ return TRANSMITTER_UNKNOWN;
++ }
++ break;
++ default:
++ return TRANSMITTER_UNKNOWN;
++ }
++}
++
++static void enable_phy_bypass_mode(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset,
++ bool enable)
++{
++ /* This register resides in DP back end block;
++ * transmitter is used for the offset */
++
++ const uint32_t addr = mmDP_DPHY_CNTL + be_addr_offset;
++
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, enable, DP_DPHY_CNTL, DPHY_BYPASS);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void disable_prbs_symbols(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset,
++ bool disable)
++{
++ /* This register resides in DP back end block;
++ * transmitter is used for the offset */
++
++ const uint32_t addr = mmDP_DPHY_CNTL + be_addr_offset;
++
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, disable,
++ DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE0);
++
++ set_reg_field_value(value, disable,
++ DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE1);
++
++ set_reg_field_value(value, disable,
++ DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE2);
++
++ set_reg_field_value(value, disable,
++ DP_DPHY_CNTL, DPHY_ATEST_SEL_LANE3);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void disable_prbs_mode(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset)
++{
++ /* This register resides in DP back end block;
++ * transmitter is used for the offset */
++
++ const uint32_t addr = mmDP_DPHY_PRBS_CNTL + be_addr_offset;
++ uint32_t value;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, 0, DP_DPHY_PRBS_CNTL, DPHY_PRBS_EN);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void program_pattern_symbols(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset,
++ uint16_t pattern_symbols[8])
++{
++ uint32_t addr;
++ uint32_t value;
++
++ /* This register resides in DP back end block;
++ * transmitter is used for the offset */
++
++ addr = mmDP_DPHY_SYM0 + be_addr_offset;
++
++ value = 0;
++ set_reg_field_value(value, pattern_symbols[0],
++ DP_DPHY_SYM0, DPHY_SYM1);
++ set_reg_field_value(value, pattern_symbols[1],
++ DP_DPHY_SYM0, DPHY_SYM2);
++ set_reg_field_value(value, pattern_symbols[2],
++ DP_DPHY_SYM0, DPHY_SYM3);
++ dal_write_reg(ctx, addr, value);
++
++ /* This register resides in DP back end block;
++ * transmitter is used for the offset */
++
++ addr = mmDP_DPHY_SYM1 + be_addr_offset;
++
++ value = 0;
++ set_reg_field_value(value, pattern_symbols[3],
++ DP_DPHY_SYM1, DPHY_SYM4);
++ set_reg_field_value(value, pattern_symbols[4],
++ DP_DPHY_SYM1, DPHY_SYM5);
++ set_reg_field_value(value, pattern_symbols[5],
++ DP_DPHY_SYM1, DPHY_SYM6);
++ dal_write_reg(ctx, addr, value);
++
++ /* This register resides in DP back end block;
++ * transmitter is used for the offset */
++ addr = mmDP_DPHY_SYM2 + be_addr_offset;
++ value = 0;
++ set_reg_field_value(value, pattern_symbols[6],
++ DP_DPHY_SYM2, DPHY_SYM7);
++ set_reg_field_value(value, pattern_symbols[6],
++ DP_DPHY_SYM2, DPHY_SYM8);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void set_dp_phy_pattern_d102(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset)
++{
++ /* Disable PHY Bypass mode to setup the test pattern */
++
++ enable_phy_bypass_mode(ctx, be_addr_offset, false);
++
++ /* For 10-bit PRBS or debug symbols
++ * please use the following sequence: */
++
++ /* Enable debug symbols on the lanes */
++
++ disable_prbs_symbols(ctx, be_addr_offset, true);
++
++ /* Disable PRBS mode,
++ * make sure DPHY_PRBS_CNTL.DPHY_PRBS_EN=0 */
++
++ disable_prbs_mode(ctx, be_addr_offset);
++
++ /* Program debug symbols to be output */
++ {
++ uint16_t pattern_symbols[8] = {
++ 0x2AA, 0x2AA, 0x2AA, 0x2AA,
++ 0x2AA, 0x2AA, 0x2AA, 0x2AA
++ };
++
++ program_pattern_symbols(ctx,
++ be_addr_offset, pattern_symbols);
++ }
++
++ /* Enable phy bypass mode to enable the test pattern */
++
++ enable_phy_bypass_mode(ctx, be_addr_offset, true);
++}
++
++static void set_link_training_complete(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset,
++ bool complete)
++{
++ /* This register resides in DP back end block;
++ * transmitter is used for the offset */
++
++ const uint32_t addr = mmDP_LINK_CNTL + be_addr_offset;
++
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, complete,
++ DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void set_dp_phy_pattern_training_pattern(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset,
++ uint32_t index)
++{
++ /* Write Training Pattern */
++
++ dal_write_reg(ctx,
++ mmDP_DPHY_TRAINING_PATTERN_SEL + be_addr_offset, index);
++
++ /* Set HW Register Training Complete to false */
++
++ set_link_training_complete(ctx, be_addr_offset, false);
++
++ /* Disable PHY Bypass mode to output Training Pattern */
++
++ enable_phy_bypass_mode(ctx, be_addr_offset, false);
++
++ /* Disable PRBS mode,
++ * make sure DPHY_PRBS_CNTL.DPHY_PRBS_EN=0 */
++
++ disable_prbs_mode(ctx, be_addr_offset);
++}
++
++static void set_dp_phy_pattern_symbol_error(
++ struct dc_context *ctx,
++ const int32_t addr_offset)
++{
++ /* Disable PHY Bypass mode to setup the test pattern */
++
++ enable_phy_bypass_mode(ctx, addr_offset, false);
++
++ /* program correct panel mode*/
++ {
++ const uint32_t addr = mmDP_DPHY_INTERNAL_CTRL + addr_offset;
++ uint32_t value = 0x0;
++ dal_write_reg(ctx, addr, value);
++ }
++
++ /* A PRBS23 pattern is used for most DP electrical measurements. */
++
++ /* Enable PRBS symbols on the lanes */
++
++ disable_prbs_symbols(ctx, addr_offset, false);
++
++ /* For PRBS23 Set bit DPHY_PRBS_SEL=1 and Set bit DPHY_PRBS_EN=1 */
++ {
++ const uint32_t addr = mmDP_DPHY_PRBS_CNTL + addr_offset;
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, 1,
++ DP_DPHY_PRBS_CNTL, DPHY_PRBS_SEL);
++ set_reg_field_value(value, 1,
++ DP_DPHY_PRBS_CNTL, DPHY_PRBS_EN);
++ dal_write_reg(ctx, addr, value);
++ }
++
++ /* Enable phy bypass mode to enable the test pattern */
++
++ enable_phy_bypass_mode(ctx, addr_offset, true);
++}
++
++static void set_dp_phy_pattern_prbs7(
++ struct dc_context *ctx,
++ const int32_t addr_offset)
++{
++ /* Disable PHY Bypass mode to setup the test pattern */
++
++ enable_phy_bypass_mode(ctx, addr_offset, false);
++
++ /* A PRBS7 pattern is used for most DP electrical measurements. */
++
++ /* Enable PRBS symbols on the lanes */
++
++ disable_prbs_symbols(ctx, addr_offset, false);
++
++ /* For PRBS7 Set bit DPHY_PRBS_SEL=0 and Set bit DPHY_PRBS_EN=1 */
++ {
++ const uint32_t addr = mmDP_DPHY_PRBS_CNTL + addr_offset;
++
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, 0,
++ DP_DPHY_PRBS_CNTL, DPHY_PRBS_SEL);
++
++ set_reg_field_value(value, 1,
++ DP_DPHY_PRBS_CNTL, DPHY_PRBS_EN);
++
++ dal_write_reg(ctx, addr, value);
++ }
++
++ /* Enable phy bypass mode to enable the test pattern */
++
++ enable_phy_bypass_mode(ctx, addr_offset, true);
++}
++
++static void set_dp_phy_pattern_80bit_custom(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset,
++ const uint8_t *pattern)
++{
++ /* Disable PHY Bypass mode to setup the test pattern */
++
++ enable_phy_bypass_mode(ctx, be_addr_offset, false);
++
++ /* Enable debug symbols on the lanes */
++
++ disable_prbs_symbols(ctx, be_addr_offset, true);
++
++ /* Enable PHY bypass mode to enable the test pattern */
++ /* TODO is it really needed ? */
++
++ enable_phy_bypass_mode(ctx, be_addr_offset, true);
++
++ /* Program 80 bit custom pattern */
++ {
++ uint16_t pattern_symbols[8];
++
++ pattern_symbols[0] =
++ ((pattern[1] & 0x03) << 8) | pattern[0];
++ pattern_symbols[1] =
++ ((pattern[2] & 0x0f) << 6) | ((pattern[1] >> 2) & 0x3f);
++ pattern_symbols[2] =
++ ((pattern[3] & 0x3f) << 4) | ((pattern[2] >> 4) & 0x0f);
++ pattern_symbols[3] =
++ (pattern[4] << 2) | ((pattern[3] >> 6) & 0x03);
++ pattern_symbols[4] =
++ ((pattern[6] & 0x03) << 8) | pattern[5];
++ pattern_symbols[5] =
++ ((pattern[7] & 0x0f) << 6) | ((pattern[6] >> 2) & 0x3f);
++ pattern_symbols[6] =
++ ((pattern[8] & 0x3f) << 4) | ((pattern[7] >> 4) & 0x0f);
++ pattern_symbols[7] =
++ (pattern[9] << 2) | ((pattern[8] >> 6) & 0x03);
++
++ program_pattern_symbols(ctx,
++ be_addr_offset, pattern_symbols);
++ }
++
++ /* Enable phy bypass mode to enable the test pattern */
++
++ enable_phy_bypass_mode(ctx, be_addr_offset, true);
++}
++
++void dce110_link_encoder_setup(
++ struct link_encoder *enc,
++ enum signal_type signal)
++{
++ const uint32_t addr = mmDIG_BE_CNTL + enc->be_engine_offset;
++ uint32_t value = dal_read_reg(enc->ctx, addr);
++
++ switch (signal) {
++ case SIGNAL_TYPE_EDP:
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ /* DP SST */
++ set_reg_field_value(value, 0, DIG_BE_CNTL, DIG_MODE);
++ break;
++ case SIGNAL_TYPE_LVDS:
++ /* LVDS */
++ set_reg_field_value(value, 1, DIG_BE_CNTL, DIG_MODE);
++ break;
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ /* TMDS-DVI */
++ set_reg_field_value(value, 2, DIG_BE_CNTL, DIG_MODE);
++ break;
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ /* TMDS-HDMI */
++ set_reg_field_value(value, 3, DIG_BE_CNTL, DIG_MODE);
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ /* DP MST */
++ set_reg_field_value(value, 5, DIG_BE_CNTL, DIG_MODE);
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ /* invalid mode ! */
++ break;
++ }
++
++ dal_write_reg(enc->ctx, addr, value);
++}
++
++static void set_dp_phy_pattern_hbr2_compliance(
++ struct link_encoder *enc,
++ const int32_t be_addr_offset)
++{
++ /*const int32_t fe_addr_offset = fe_engine_offsets[param->engine];
++ const int32_t be_addr_offset = enc->be_engine_offset;*/
++
++ uint32_t addr;
++ uint32_t value;
++
++ /* previously there is a register DP_HBR2_EYE_PATTERN
++ * that is enabled to get the pattern.
++ * But it does not work with the latest spec change,
++ * so we are programming the following registers manually.
++ *
++ * The following settings have been confirmed
++ * by Nick Chorney and Sandra Liu */
++
++ /* Disable PHY Bypass mode to setup the test pattern */
++
++ enable_phy_bypass_mode(enc->ctx, be_addr_offset, false);
++
++ /* Setup DIG encoder in DP SST mode */
++
++ dce110_link_encoder_setup(enc, SIGNAL_TYPE_DISPLAY_PORT);
++
++ /* program correct panel mode*/
++ {
++ const uint32_t addr = mmDP_DPHY_INTERNAL_CTRL + be_addr_offset;
++ uint32_t value = 0x0;
++ dal_write_reg(enc->ctx, addr, value);
++ }
++
++ /* no vbid after BS (SR)
++ * DP_LINK_FRAMING_CNTL changed history Sandra Liu
++ * 11000260 / 11000104 / 110000FC */
++
++ /* TODO DP_LINK_FRAMING_CNTL should always use hardware default value
++ * output except output hbr2_compliance pattern for physical PHY
++ * measurement. This is not normal usage case. SW should reset this
++ * register to hardware default value after end use of HBR2 eye
++ */
++ BREAK_TO_DEBUGGER();
++ /* TODO: do we still need this, find out at compliance test
++ addr = mmDP_LINK_FRAMING_CNTL + fe_addr_offset;
++
++ value = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(value, 0xFC,
++ DP_LINK_FRAMING_CNTL, DP_IDLE_BS_INTERVAL);
++ set_reg_field_value(value, 1,
++ DP_LINK_FRAMING_CNTL, DP_VBID_DISABLE);
++ set_reg_field_value(value, 1,
++ DP_LINK_FRAMING_CNTL, DP_VID_ENHANCED_FRAME_MODE);
++
++ dal_write_reg(enc->ctx, addr, value);
++ */
++
++ /*TODO add support for this test pattern
++ * support_dp_hbr2_eye_pattern
++ */
++
++ /* set link training complete */
++ set_link_training_complete(enc->ctx, be_addr_offset, true);
++ /* do not enable video stream */
++ addr = mmDP_VID_STREAM_CNTL + be_addr_offset;
++
++ value = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(value, 0, DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE);
++
++ dal_write_reg(enc->ctx, addr, value);
++
++ /* Disable PHY Bypass mode to setup the test pattern */
++
++ enable_phy_bypass_mode(enc->ctx, be_addr_offset, false);
++}
++
++static void set_dp_phy_pattern_passthrough_mode(
++ struct dc_context *ctx,
++ const int32_t be_addr_offset,
++ enum dp_panel_mode panel_mode)
++{
++
++ /* program correct panel mode */
++ {
++ const uint32_t addr = mmDP_DPHY_INTERNAL_CTRL + be_addr_offset;
++
++ uint32_t value;
++
++ value = dal_read_reg(ctx, addr);
++
++ switch (panel_mode) {
++ case DP_PANEL_MODE_EDP:
++ value = 0x1;
++ break;
++ case DP_PANEL_MODE_SPECIAL:
++ value = 0x11;
++ break;
++ default:
++ value = 0x0;
++ break;
++ }
++
++ dal_write_reg(ctx, addr, value);
++ }
++
++ /* set link training complete */
++
++ set_link_training_complete(ctx, be_addr_offset, true);
++
++ /* Disable PHY Bypass mode to setup the test pattern */
++
++ enable_phy_bypass_mode(ctx, be_addr_offset, false);
++
++ /* Disable PRBS mode,
++ * make sure DPHY_PRBS_CNTL.DPHY_PRBS_EN=0 */
++
++ disable_prbs_mode(ctx, be_addr_offset);
++}
++
++static void construct(
++ struct link_encoder *enc,
++ const struct encoder_init_data *init_data)
++{
++ struct graphics_object_encoder_cap_info enc_cap_info = {0};
++
++ enc->ctx = init_data->ctx;
++ enc->id = init_data->encoder;
++
++ enc->hpd_source = init_data->hpd_source;
++ enc->connector = init_data->connector;
++ enc->input_signals = SIGNAL_TYPE_ALL;
++
++ enc->adapter_service = init_data->adapter_service;
++
++ enc->preferred_engine = ENGINE_ID_UNKNOWN;
++
++ enc->features.flags.raw = 0;
++
++ enc->transmitter = translate_encoder_to_transmitter(
++ init_data->encoder);
++
++ enc->features.flags.bits.IS_AUDIO_CAPABLE = true;
++
++ enc->features.max_pixel_clock = DCE11_UNIPHY_MAX_PIXEL_CLK_IN_KHZ;
++
++ /* set the flag to indicate whether driver poll the I2C data pin
++ * while doing the DP sink detect */
++
++ if (dal_adapter_service_is_feature_supported(
++ FEATURE_DP_SINK_DETECT_POLL_DATA_PIN))
++ enc->features.flags.bits.DP_SINK_DETECT_POLL_DATA_PIN = true;
++
++ enc->output_signals =
++ SIGNAL_TYPE_DVI_SINGLE_LINK |
++ SIGNAL_TYPE_DVI_DUAL_LINK |
++ SIGNAL_TYPE_LVDS |
++ SIGNAL_TYPE_DISPLAY_PORT |
++ SIGNAL_TYPE_DISPLAY_PORT_MST |
++ SIGNAL_TYPE_EDP |
++ SIGNAL_TYPE_HDMI_TYPE_A;
++
++ /* For DCE 8.0 and 8.1, by design, UNIPHY is hardwired to DIG_BE.
++ * SW always assign DIG_FE 1:1 mapped to DIG_FE for non-MST UNIPHY.
++ * SW assign DIG_FE to non-MST UNIPHY first and MST last. So prefer
++ * DIG is per UNIPHY and used by SST DP, eDP, HDMI, DVI and LVDS.
++ * Prefer DIG assignment is decided by board design.
++ * For DCE 8.0, there are only max 6 UNIPHYs, we assume board design
++ * and VBIOS will filter out 7 UNIPHY for DCE 8.0.
++ * By this, adding DIGG should not hurt DCE 8.0.
++ * This will let DCE 8.1 share DCE 8.0 as much as possible */
++
++ switch (enc->transmitter) {
++ case TRANSMITTER_UNIPHY_A:
++ enc->preferred_engine = ENGINE_ID_DIGA;
++ enc->transmitter_offset = 0;
++ enc->be_engine_offset = 0;
++ break;
++ case TRANSMITTER_UNIPHY_B:
++ enc->preferred_engine = ENGINE_ID_DIGB;
++
++ enc->transmitter_offset =
++ mmBPHYC_UNIPHY1_UNIPHY_TX_CONTROL1 -
++ mmBPHYC_UNIPHY0_UNIPHY_TX_CONTROL1;
++ enc->be_engine_offset =
++ mmDIG1_DIG_BE_CNTL - mmDIG0_DIG_BE_CNTL;
++ break;
++ case TRANSMITTER_UNIPHY_C:
++ enc->preferred_engine = ENGINE_ID_DIGC;
++ enc->transmitter_offset =
++ mmBPHYC_UNIPHY2_UNIPHY_TX_CONTROL1 -
++ mmBPHYC_UNIPHY0_UNIPHY_TX_CONTROL1;
++ enc->be_engine_offset =
++ mmDIG2_DIG_BE_CNTL - mmDIG0_DIG_BE_CNTL;
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ enc->preferred_engine = ENGINE_ID_UNKNOWN;
++ enc->transmitter_offset = 0;
++ enc->be_engine_offset = 0;
++ }
++
++ dal_logger_write(init_data->ctx->logger,
++ LOG_MAJOR_I2C_AUX,
++ LOG_MINOR_I2C_AUX_CFG,
++ "Using channel: %s [%d]\n",
++ DECODE_CHANNEL_ID(init_data->channel),
++ init_data->channel);
++
++ switch (init_data->channel) {
++ case CHANNEL_ID_DDC1:
++ enc->aux_channel_offset = 0;
++ break;
++ case CHANNEL_ID_DDC2:
++ enc->aux_channel_offset =
++ mmDP_AUX1_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL;
++ break;
++ case CHANNEL_ID_DDC3:
++ enc->aux_channel_offset =
++ mmDP_AUX2_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL;
++ break;
++ default:
++ /* check BIOS object table ! */
++ dal_logger_write(init_data->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_ENCODER,
++ "%s: Invalid channel ID\n",
++ __func__);
++ enc->aux_channel_offset = 0;
++ }
++
++ /* Override features with DCE-specific values */
++ if (dal_adapter_service_get_encoder_cap_info(enc->adapter_service,
++ enc->id, &enc_cap_info))
++ enc->features.flags.bits.IS_HBR2_CAPABLE =
++ enc_cap_info.dp_hbr2_cap;
++
++ /* test pattern 3 support */
++ enc->features.flags.bits.IS_TPS3_CAPABLE = true;
++ enc->features.max_deep_color = COLOR_DEPTH_121212;
++
++ enc->features.flags.bits.IS_Y_ONLY_CAPABLE =
++ dal_adapter_service_is_feature_supported(
++ FEATURE_SUPPORT_DP_Y_ONLY);
++
++ enc->features.flags.bits.IS_YCBCR_CAPABLE =
++ dal_adapter_service_is_feature_supported(
++ FEATURE_SUPPORT_DP_YUV);
++}
++
++struct link_encoder *dce110_link_encoder_create(
++ const struct encoder_init_data *init)
++{
++ struct link_encoder *enc =
++ dc_service_alloc(init->ctx, sizeof(struct link_encoder));
++
++ if (!enc)
++ goto enc_create_fail;
++
++ construct(enc, init);
++
++ return enc;
++
++enc_create_fail:
++ return NULL;
++}
++
++void dce110_link_encoder_destroy(struct link_encoder **enc)
++{
++ struct link_encoder *encoder = *enc;
++ dc_service_free(encoder->ctx, encoder);
++ *enc = NULL;
++}
++
++void dce110_link_encoder_set_dp_phy_pattern(
++ struct link_encoder *enc,
++ const struct encoder_set_dp_phy_pattern_param *param)
++{
++ const int32_t offset = enc->be_engine_offset;
++
++
++ switch (param->dp_phy_pattern) {
++ case DP_TEST_PATTERN_TRAINING_PATTERN1:
++ set_dp_phy_pattern_training_pattern(enc->ctx,
++ offset, 0);
++ break;
++ case DP_TEST_PATTERN_TRAINING_PATTERN2:
++ set_dp_phy_pattern_training_pattern(enc->ctx,
++ offset, 1);
++ break;
++ case DP_TEST_PATTERN_TRAINING_PATTERN3:
++ set_dp_phy_pattern_training_pattern(enc->ctx,
++ offset, 2);
++ break;
++ case DP_TEST_PATTERN_D102:
++ set_dp_phy_pattern_d102(enc->ctx, offset);
++ break;
++ case DP_TEST_PATTERN_SYMBOL_ERROR:
++ set_dp_phy_pattern_symbol_error(enc->ctx, offset);
++ break;
++ case DP_TEST_PATTERN_PRBS7:
++ set_dp_phy_pattern_prbs7(enc->ctx, offset);
++ break;
++ case DP_TEST_PATTERN_80BIT_CUSTOM:
++ set_dp_phy_pattern_80bit_custom(
++ enc->ctx,
++ offset, param->custom_pattern);
++ break;
++ case DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE:
++ set_dp_phy_pattern_hbr2_compliance(
++ enc, offset);
++ break;
++ case DP_TEST_PATTERN_VIDEO_MODE: {
++ set_dp_phy_pattern_passthrough_mode(
++ enc->ctx,
++ offset,
++ param->dp_panel_mode);
++ break;
++ }
++
++
++ default:
++ /* invalid phy pattern */
++ ASSERT_CRITICAL(false);
++ break;
++ }
++}
++
++enum encoder_result dce110_link_encoder_dp_set_lane_settings(
++ struct link_encoder *enc,
++ const struct link_training_settings *link_settings)
++{
++ union dpcd_training_lane_set training_lane_set = { { 0 } };
++
++ int32_t lane = 0;
++
++ struct bp_transmitter_control cntl = { 0 };
++
++ if (!link_settings) {
++ BREAK_TO_DEBUGGER();
++ return ENCODER_RESULT_ERROR;
++ }
++
++ cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
++ cntl.transmitter = enc->transmitter;
++ cntl.connector_obj_id = enc->connector;
++ cntl.lanes_number = link_settings->link_settings.lane_count;
++ cntl.hpd_sel = enc->hpd_source;
++ cntl.pixel_clock = link_settings->link_settings.link_rate *
++ LINK_RATE_REF_FREQ_IN_KHZ;
++
++ for (lane = 0; lane < link_settings->link_settings.lane_count; ++lane) {
++ /* translate lane settings */
++
++ training_lane_set.bits.VOLTAGE_SWING_SET =
++ link_settings->lane_settings[lane].VOLTAGE_SWING;
++ training_lane_set.bits.PRE_EMPHASIS_SET =
++ link_settings->lane_settings[lane].PRE_EMPHASIS;
++
++ /* post cursor 2 setting only applies to HBR2 link rate */
++ if (link_settings->link_settings.link_rate == LINK_RATE_HIGH2) {
++ /* this is passed to VBIOS
++ * to program post cursor 2 level */
++
++ training_lane_set.bits.POST_CURSOR2_SET =
++ link_settings->lane_settings[lane].POST_CURSOR2;
++ }
++
++ cntl.lane_select = lane;
++ cntl.lane_settings = training_lane_set.raw;
++
++ /* call VBIOS table to set voltage swing and pre-emphasis */
++
++ dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service), &cntl);
++ }
++
++ return ENCODER_RESULT_OK;
++}
++
++/* return value is bit-vector */
++static uint8_t get_frontend_source(
++ enum engine_id engine)
++{
++ switch (engine) {
++ case ENGINE_ID_DIGA:
++ return DCE110_DIG_FE_SOURCE_SELECT_DIGA;
++ case ENGINE_ID_DIGB:
++ return DCE110_DIG_FE_SOURCE_SELECT_DIGB;
++ case ENGINE_ID_DIGC:
++ return DCE110_DIG_FE_SOURCE_SELECT_DIGC;
++ default:
++ ASSERT_CRITICAL(false);
++ return DCE110_DIG_FE_SOURCE_SELECT_INVALID;
++ }
++}
++
++static void configure_encoder(
++ struct link_encoder *enc,
++ enum engine_id engine,
++ const struct link_settings *link_settings)
++{
++ uint32_t addr;
++ uint32_t value;
++
++ /* set number of lanes */
++ addr = mmDP_CONFIG + enc->be_engine_offset;
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, link_settings->lane_count - LANE_COUNT_ONE,
++ DP_CONFIG, DP_UDI_LANES);
++ dal_write_reg(enc->ctx, addr, value);
++
++}
++
++static bool is_panel_powered_on(struct link_encoder *link_enc)
++{
++ uint32_t value;
++ bool ret;
++
++ value = dal_read_reg(link_enc->ctx,
++ mmLVTMA_PWRSEQ_STATE);
++
++ ret = get_reg_field_value(value,
++ LVTMA_PWRSEQ_STATE, LVTMA_PWRSEQ_TARGET_STATE_R);
++
++ return ret == 1;
++}
++
++/*
++ * @brief
++ * eDP only. Control the power of the eDP panel.
++ */
++static enum encoder_result link_encoder_edp_power_control(
++ struct link_encoder *link_enc,
++ bool power_up)
++{
++ struct bp_transmitter_control cntl = { 0 };
++ enum bp_result bp_result;
++
++ if (dal_graphics_object_id_get_connector_id(link_enc->connector) !=
++ CONNECTOR_ID_EDP) {
++ BREAK_TO_DEBUGGER();
++ return ENCODER_RESULT_ERROR;
++ }
++
++ if ((power_up && !is_panel_powered_on(link_enc)) ||
++ (!power_up && is_panel_powered_on(link_enc))) {
++
++ /* Send VBIOS command to prompt eDP panel power */
++
++ dal_logger_write(link_enc->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_RESUME_S3,
++ "%s: Panel Power action: %s\n",
++ __func__, (power_up ? "On":"Off"));
++
++ cntl.action = power_up ?
++ TRANSMITTER_CONTROL_POWER_ON :
++ TRANSMITTER_CONTROL_POWER_OFF;
++ cntl.transmitter = link_enc->transmitter;
++ cntl.connector_obj_id = link_enc->connector;
++ cntl.coherent = false;
++ cntl.lanes_number = LANE_COUNT_FOUR;
++ cntl.hpd_sel = link_enc->hpd_source;
++
++ bp_result = dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ link_enc->adapter_service), &cntl);
++
++ if (BP_RESULT_OK != bp_result) {
++
++ dal_logger_write(link_enc->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_HW_TRACE_RESUME_S3,
++ "%s: Panel Power bp_result: %d\n",
++ __func__, bp_result);
++ }
++ } else {
++ dal_logger_write(link_enc->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_RESUME_S3,
++ "%s: Skipping Panel Power action: %s\n",
++ __func__, (power_up ? "On":"Off"));
++ }
++
++ return ENCODER_RESULT_OK;
++}
++
++/*
++ * @brief
++ * eDP only.
++ */
++static void link_encoder_edp_wait_for_hpd_ready(
++ struct link_encoder *link_enc,
++ struct graphics_object_id connector,
++ bool power_up)
++{
++ struct adapter_service *as = link_enc->adapter_service;
++ struct irq *hpd;
++ bool edp_hpd_high = false;
++ uint32_t time_elapsed = 0;
++ uint32_t timeout = power_up ?
++ PANEL_POWER_UP_TIMEOUT : PANEL_POWER_DOWN_TIMEOUT;
++
++ if (dal_graphics_object_id_get_connector_id(connector) !=
++ CONNECTOR_ID_EDP) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ if (!power_up && dal_adapter_service_is_feature_supported(
++ FEATURE_NO_HPD_LOW_POLLING_VCC_OFF))
++ /* from KV, we will not HPD low after turning off VCC -
++ * instead, we will check the SW timer in power_up(). */
++ return;
++
++ /* when we power on/off the eDP panel,
++ * we need to wait until SENSE bit is high/low */
++
++ /* obtain HPD */
++
++ hpd = dal_adapter_service_obtain_hpd_irq(as, connector);
++
++ if (!hpd) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ dal_irq_open(hpd);
++
++ /* wait until timeout or panel detected */
++
++ do {
++ uint32_t detected = 0;
++
++ dal_irq_get_value(hpd, &detected);
++
++ if (!(detected ^ power_up)) {
++ edp_hpd_high = true;
++ break;
++ }
++
++ dc_service_sleep_in_milliseconds(link_enc->ctx, HPD_CHECK_INTERVAL);
++
++ time_elapsed += HPD_CHECK_INTERVAL;
++ } while (time_elapsed < timeout);
++
++ dal_irq_close(hpd);
++
++ dal_adapter_service_release_irq(as, hpd);
++
++ if (false == edp_hpd_high) {
++ dal_logger_write(link_enc->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_HW_TRACE_RESUME_S3,
++ "%s: wait timed out!\n", __func__);
++ }
++}
++
++static void aux_initialize(
++ struct link_encoder *link_enc,
++ enum hpd_source_id hpd_source)
++{
++ uint32_t addr = mmAUX_CONTROL + link_enc->aux_channel_offset;
++
++ uint32_t value = dal_read_reg(link_enc->ctx, addr);
++
++ set_reg_field_value(value, hpd_source, AUX_CONTROL, AUX_HPD_SEL);
++ set_reg_field_value(value, 0, AUX_CONTROL, AUX_LS_READ_EN);
++ dal_write_reg(link_enc->ctx, addr, value);
++
++ addr = mmAUX_DPHY_RX_CONTROL0 + link_enc->aux_channel_offset;
++ value = dal_read_reg(link_enc->ctx, addr);
++
++ /* 1/4 window (the maximum allowed) */
++ set_reg_field_value(value, 1,
++ AUX_DPHY_RX_CONTROL0, AUX_RX_RECEIVE_WINDOW);
++ dal_write_reg(link_enc->ctx,
++ mmAUX_DPHY_RX_CONTROL0 + link_enc->aux_channel_offset,
++ value);
++
++}
++
++/*todo: cloned in stream enc, fix*/
++static bool is_panel_backlight_on(struct link_encoder *link_enc)
++{
++ uint32_t value;
++
++ value = dal_read_reg(link_enc->ctx, mmLVTMA_PWRSEQ_CNTL);
++
++ return get_reg_field_value(value, LVTMA_PWRSEQ_CNTL, LVTMA_BLON);
++}
++
++/*todo: cloned in stream enc, fix*/
++/*
++ * @brief
++ * eDP only. Control the backlight of the eDP panel
++ */
++static enum encoder_result link_encoder_edp_backlight_control(
++ struct link_encoder *link_enc,
++ bool enable)
++{
++ struct bp_transmitter_control cntl = { 0 };
++
++ if (dal_graphics_object_id_get_connector_id(link_enc->connector)
++ != CONNECTOR_ID_EDP) {
++ BREAK_TO_DEBUGGER();
++ return ENCODER_RESULT_ERROR;
++ }
++
++ if (enable && is_panel_backlight_on(link_enc)) {
++ dal_logger_write(link_enc->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_RESUME_S3,
++ "%s: panel already powered up. Do nothing.\n",
++ __func__);
++ return ENCODER_RESULT_OK;
++ }
++
++ if (!enable && !is_panel_powered_on(link_enc)) {
++ dal_logger_write(link_enc->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_RESUME_S3,
++ "%s: panel already powered down. Do nothing.\n",
++ __func__);
++ return ENCODER_RESULT_OK;
++ }
++
++ /* Send VBIOS command to control eDP panel backlight */
++
++ dal_logger_write(link_enc->ctx->logger,
++ LOG_MAJOR_HW_TRACE,
++ LOG_MINOR_HW_TRACE_RESUME_S3,
++ "%s: backlight action: %s\n",
++ __func__, (enable ? "On":"Off"));
++
++ cntl.action = enable ?
++ TRANSMITTER_CONTROL_BACKLIGHT_ON :
++ TRANSMITTER_CONTROL_BACKLIGHT_OFF;
++ /*cntl.engine_id = ctx->engine;*/
++ cntl.transmitter = link_enc->transmitter;
++ cntl.connector_obj_id = link_enc->connector;
++ /*todo: unhardcode*/
++ cntl.lanes_number = LANE_COUNT_FOUR;
++ cntl.hpd_sel = link_enc->hpd_source;
++
++ /* For eDP, the following delays might need to be considered
++ * after link training completed:
++ * idle period - min. accounts for required BS-Idle pattern,
++ * max. allows for source frame synchronization);
++ * 50 msec max. delay from valid video data from source
++ * to video on dislpay or backlight enable.
++ *
++ * Disable the delay for now.
++ * Enable it in the future if necessary.
++ */
++ /* dc_service_sleep_in_milliseconds(50); */
++
++ dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ link_enc->adapter_service), &cntl);
++
++ return ENCODER_RESULT_OK;
++}
++
++/*
++ * @brief
++ * Configure digital transmitter and enable both encoder and transmitter
++ * Actual output will be available after calling unblank()
++ */
++enum encoder_result dce110_link_encoder_enable_output(
++ struct link_encoder *enc,
++ const struct link_settings *link_settings,
++ enum engine_id engine,
++ enum clock_source_id clock_source,
++ enum signal_type signal,
++ enum dc_color_depth color_depth,
++ uint32_t pixel_clock)
++{
++ struct bp_transmitter_control cntl = { 0 };
++
++ if (enc->connector.id == CONNECTOR_ID_EDP) {
++ /* power up eDP panel */
++
++ link_encoder_edp_power_control(
++ enc, true);
++
++ link_encoder_edp_wait_for_hpd_ready(
++ enc, enc->connector, true);
++
++ /* have to turn off the backlight
++ * before power down eDP panel */
++ link_encoder_edp_backlight_control(
++ enc, true);
++ }
++
++ /* Enable the PHY */
++
++ /* number_of_lanes is used for pixel clock adjust,
++ * but it's not passed to asic_control.
++ * We need to set number of lanes manually. */
++ if (dc_is_dp_signal(signal))
++ configure_encoder(enc, engine, link_settings);
++
++ cntl.action = TRANSMITTER_CONTROL_ENABLE;
++ cntl.engine_id = engine;
++ cntl.transmitter = enc->transmitter;
++ cntl.pll_id = clock_source;
++ cntl.signal = signal;
++ cntl.lanes_number = link_settings->lane_count;
++ cntl.hpd_sel = enc->hpd_source;
++ if (dc_is_dp_signal(signal))
++ cntl.pixel_clock = link_settings->link_rate
++ * LINK_RATE_REF_FREQ_IN_KHZ;
++ else
++ cntl.pixel_clock = pixel_clock;
++ cntl.color_depth = color_depth;
++
++ if (DELAY_AFTER_PIXEL_FORMAT_CHANGE)
++ dc_service_sleep_in_milliseconds(
++ enc->ctx,
++ DELAY_AFTER_PIXEL_FORMAT_CHANGE);
++
++ dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service),
++ &cntl);
++
++ return ENCODER_RESULT_OK;
++}
++
++static bool is_dig_enabled(const struct link_encoder *link_enc)
++{
++ uint32_t value;
++
++ value = dal_read_reg(link_enc->ctx,
++ mmDIG_BE_EN_CNTL + link_enc->be_engine_offset);
++
++ return get_reg_field_value(value, DIG_BE_EN_CNTL, DIG_ENABLE);
++}
++
++static void link_encoder_disable(struct link_encoder *link_enc)
++{
++ uint32_t addr;
++ uint32_t value;
++
++ /* reset training pattern */
++ addr = mmDP_DPHY_TRAINING_PATTERN_SEL + link_enc->be_engine_offset;
++ value = dal_read_reg(link_enc->ctx, addr);
++ set_reg_field_value(value, 0,
++ DP_DPHY_TRAINING_PATTERN_SEL,
++ DPHY_TRAINING_PATTERN_SEL);
++ dal_write_reg(link_enc->ctx, addr, value);
++
++ /* reset training complete */
++ addr = mmDP_LINK_CNTL + link_enc->be_engine_offset;
++ value = dal_read_reg(link_enc->ctx, addr);
++ set_reg_field_value(value, 0, DP_LINK_CNTL, DP_LINK_TRAINING_COMPLETE);
++ dal_write_reg(link_enc->ctx, addr, value);
++
++ /* reset panel mode */
++ addr = mmDP_DPHY_INTERNAL_CTRL + link_enc->be_engine_offset;
++ value = 0;
++ dal_write_reg(link_enc->ctx, addr, value);
++}
++
++/*
++ * @brief
++ * Disable transmitter and its encoder
++ */
++enum encoder_result dce110_link_encoder_disable_output(
++ struct link_encoder *link_enc,
++ enum signal_type signal)
++{
++ struct bp_transmitter_control cntl = { 0 };
++
++ if (link_enc->connector.id == CONNECTOR_ID_EDP) {
++ /* have to turn off the backlight
++ * before power down eDP panel */
++ link_encoder_edp_backlight_control(
++ link_enc, false);
++ }
++
++ if (!is_dig_enabled(link_enc) &&
++ dal_adapter_service_should_optimize(link_enc->adapter_service,
++ OF_SKIP_POWER_DOWN_INACTIVE_ENCODER)) {
++ return ENCODER_RESULT_OK;
++ }
++ /* Power-down RX and disable GPU PHY should be paired.
++ * Disabling PHY without powering down RX may cause
++ * symbol lock loss, on which we will get DP Sink interrupt. */
++
++ /* There is a case for the DP active dongles
++ * where we want to disable the PHY but keep RX powered,
++ * for those we need to ignore DP Sink interrupt
++ * by checking lane count that has been set
++ * on the last do_enable_output(). */
++
++ /* disable transmitter */
++ cntl.action = TRANSMITTER_CONTROL_DISABLE;
++ cntl.transmitter = link_enc->transmitter;
++ cntl.hpd_sel = link_enc->hpd_source;
++ cntl.signal = signal;
++ cntl.connector_obj_id = link_enc->connector;
++
++ dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ link_enc->adapter_service), &cntl);
++
++ /* disable encoder */
++ if (dc_is_dp_signal(signal))
++ link_encoder_disable(link_enc);
++
++ if (link_enc->connector.id == CONNECTOR_ID_EDP) {
++ /* power down eDP panel */
++ /* TODO: Power control cause regression, we should implement
++ * it properly, for now just comment it.
++ *
++ * link_encoder_edp_wait_for_hpd_ready(
++ link_enc,
++ link_enc->connector,
++ false);
++
++ * link_encoder_edp_power_control(
++ link_enc, false); */
++ }
++
++ return ENCODER_RESULT_OK;
++}
++
++static void hpd_initialize(
++ struct link_encoder *enc,
++ enum hpd_source_id hpd_source)
++{
++ /* Associate HPD with DIG_BE */
++ const uint32_t addr = mmDIG_BE_CNTL + enc->be_engine_offset;
++ uint32_t value = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(value, hpd_source, DIG_BE_CNTL, DIG_HPD_SELECT);
++ dal_write_reg(enc->ctx, addr, value);
++}
++
++enum encoder_result dce110_link_encoder_power_up(
++ struct link_encoder *enc)
++{
++ struct bp_transmitter_control cntl = { 0 };
++
++ enum bp_result result;
++
++ cntl.action = TRANSMITTER_CONTROL_INIT;
++ cntl.engine_id = ENGINE_ID_UNKNOWN;
++ cntl.transmitter = enc->transmitter;
++ cntl.connector_obj_id = enc->connector;
++ cntl.lanes_number = LANE_COUNT_FOUR;
++ cntl.coherent = false;
++ cntl.hpd_sel = enc->hpd_source;
++
++ result = dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service),
++ &cntl);
++
++ if (result != BP_RESULT_OK) {
++ dal_logger_write(enc->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_ENCODER,
++ "%s: Failed to execute VBIOS command table!\n",
++ __func__);
++ BREAK_TO_DEBUGGER();
++ return ENCODER_RESULT_ERROR;
++ }
++
++ if (enc->connector.id == CONNECTOR_ID_LVDS) {
++ cntl.action = TRANSMITTER_CONTROL_BACKLIGHT_BRIGHTNESS;
++
++ result = dal_bios_parser_transmitter_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service),
++ &cntl);
++ ASSERT(result == BP_RESULT_OK);
++
++ } else if (enc->connector.id == CONNECTOR_ID_EDP) {
++ link_encoder_edp_power_control(enc, true);
++
++ link_encoder_edp_wait_for_hpd_ready(
++ enc, enc->connector, true);
++
++ }
++ aux_initialize(enc, enc->hpd_source);
++
++ /* reinitialize HPD.
++ * hpd_initialize() will pass DIG_FE id to HW context.
++ * All other routine within HW context will use fe_engine_offset
++ * as DIG_FE id even caller pass DIG_FE id.
++ * So this routine must be called first. */
++ hpd_initialize(enc, enc->hpd_source);
++
++ return ENCODER_RESULT_OK;
++}
++
++
++static bool validate_dvi_output(
++ const struct link_encoder *enc,
++ enum signal_type connector_signal,
++ enum signal_type signal,
++ const struct dc_crtc_timing *crtc_timing)
++{
++ uint32_t max_pixel_clock = TMDS_MAX_PIXEL_CLOCK;
++
++ if (enc->features.max_pixel_clock < TMDS_MAX_PIXEL_CLOCK)
++ max_pixel_clock = enc->features.max_pixel_clock;
++
++ if (signal == SIGNAL_TYPE_DVI_DUAL_LINK)
++ max_pixel_clock <<= 1;
++
++ /* This handles the case of HDMI downgrade to DVI we don't want to
++ * we don't want to cap the pixel clock if the DDI is not DVI.
++ */
++ if (connector_signal != SIGNAL_TYPE_DVI_DUAL_LINK &&
++ connector_signal != SIGNAL_TYPE_DVI_SINGLE_LINK)
++ max_pixel_clock = enc->features.max_pixel_clock;
++
++ /* DVI only support RGB pixel encoding */
++ if (crtc_timing->pixel_encoding != PIXEL_ENCODING_RGB)
++ return false;
++
++ if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK)
++ return false;
++
++ if (crtc_timing->pix_clk_khz > max_pixel_clock)
++ return false;
++
++ /* DVI supports 6/8bpp single-link and 10/16bpp dual-link */
++ switch (crtc_timing->display_color_depth) {
++ case COLOR_DEPTH_666:
++ case COLOR_DEPTH_888:
++ break;
++ case COLOR_DEPTH_101010:
++ case COLOR_DEPTH_161616:
++ if (signal != SIGNAL_TYPE_DVI_DUAL_LINK)
++ return false;
++ break;
++ default:
++ return false;
++ }
++
++ return true;
++}
++
++static bool validate_hdmi_output(
++ const struct link_encoder *enc,
++ const struct dc_crtc_timing *crtc_timing,
++ uint32_t max_tmds_clk_from_edid_in_mhz,
++ enum dc_color_depth max_hdmi_deep_color,
++ uint32_t max_hdmi_pixel_clock)
++{
++ enum dc_color_depth max_deep_color = max_hdmi_deep_color;
++
++ /* expressed in KHz */
++ uint32_t pixel_clock = 0;
++
++ if (max_deep_color > enc->features.max_deep_color)
++ max_deep_color = enc->features.max_deep_color;
++
++ if (max_deep_color < crtc_timing->display_color_depth)
++ return false;
++
++ if (crtc_timing->pix_clk_khz < TMDS_MIN_PIXEL_CLOCK)
++ return false;
++
++ switch (crtc_timing->display_color_depth) {
++ case COLOR_DEPTH_666:
++ pixel_clock = (crtc_timing->pix_clk_khz * 3) >> 2;
++ break;
++ case COLOR_DEPTH_888:
++ pixel_clock = crtc_timing->pix_clk_khz;
++ break;
++ case COLOR_DEPTH_101010:
++ pixel_clock = (crtc_timing->pix_clk_khz * 10) >> 3;
++ break;
++ case COLOR_DEPTH_121212:
++ pixel_clock = (crtc_timing->pix_clk_khz * 3) >> 1;
++ break;
++ case COLOR_DEPTH_161616:
++ pixel_clock = crtc_timing->pix_clk_khz << 1;
++ break;
++ default:
++ break;
++ }
++
++ if (max_tmds_clk_from_edid_in_mhz > 0)
++ if (pixel_clock > max_tmds_clk_from_edid_in_mhz * 1000)
++ return false;
++
++ if ((pixel_clock == 0) ||
++ (pixel_clock > max_hdmi_pixel_clock) ||
++ (pixel_clock > enc->features.max_pixel_clock))
++ return false;
++
++ /*
++ * Restriction: allow non-CE mode (IT mode) to support RGB only.
++ * When it is IT mode, the format mode will be 0,
++ * but currently the code is broken,
++ * VIDEO FORMAT is always 0 in validatepathMode().
++ * Due to overscan change - need fix there and test the impact - to do.
++ */
++ if (crtc_timing->timing_standard != TIMING_STANDARD_CEA861 &&
++ crtc_timing->timing_standard != TIMING_STANDARD_HDMI)
++ if (crtc_timing->pixel_encoding !=
++ PIXEL_ENCODING_RGB)
++ return false;
++
++ return true;
++}
++
++static bool validate_rgb_output(
++ const struct link_encoder *enc,
++ const struct dc_crtc_timing *crtc_timing)
++{
++ if (crtc_timing->pix_clk_khz > enc->features.max_pixel_clock)
++ return false;
++
++ if (crtc_timing->pixel_encoding != PIXEL_ENCODING_RGB)
++ return false;
++
++ return true;
++}
++
++static bool validate_dp_output(
++ const struct link_encoder *enc,
++ const struct dc_crtc_timing *crtc_timing)
++{
++ if (crtc_timing->pix_clk_khz > enc->features.max_pixel_clock)
++ return false;
++
++ /* default RGB only */
++ if (crtc_timing->pixel_encoding == PIXEL_ENCODING_RGB)
++ return true;
++
++ if (enc->features.flags.bits.IS_YCBCR_CAPABLE)
++ return true;
++
++ /* for DCE 8.x or later DP Y-only feature,
++ * we need ASIC cap + FeatureSupportDPYonly, not support 666 */
++ if (crtc_timing->flags.Y_ONLY &&
++ enc->features.flags.bits.IS_YCBCR_CAPABLE &&
++ crtc_timing->display_color_depth != COLOR_DEPTH_666)
++ return true;
++
++ return false;
++}
++
++static bool validate_wireless_output(
++ const struct link_encoder *enc,
++ const struct dc_crtc_timing *crtc_timing)
++{
++ if (crtc_timing->pix_clk_khz > enc->features.max_pixel_clock)
++ return false;
++
++ /* Wireless only supports YCbCr444 */
++ if (crtc_timing->pixel_encoding ==
++ PIXEL_ENCODING_YCBCR444)
++ return true;
++
++ return false;
++}
++
++enum encoder_result dce110_link_encoder_validate_output_with_stream(
++ struct link_encoder *enc,
++ const struct core_stream *stream)
++{
++ bool is_valid;
++
++ switch (stream->signal) {
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ is_valid = validate_dvi_output(
++ enc,
++ stream->sink->link->public.connector_signal,
++ stream->signal,
++ &stream->public.timing);
++ break;
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ is_valid = validate_hdmi_output(
++ enc,
++ &stream->public.timing,
++ stream->max_tmds_clk_from_edid_in_mhz,
++ stream->max_hdmi_deep_color,
++ stream->max_hdmi_pixel_clock);
++ break;
++ case SIGNAL_TYPE_RGB:
++ is_valid = validate_rgb_output(
++ enc, &stream->public.timing);
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ is_valid = validate_dp_output(
++ enc, &stream->public.timing);
++ break;
++ case SIGNAL_TYPE_WIRELESS:
++ is_valid = validate_wireless_output(
++ enc, &stream->public.timing);
++ break;
++ default:
++ is_valid = true;
++ break;
++ }
++
++ return is_valid ? ENCODER_RESULT_OK : ENCODER_RESULT_ERROR;
++}
++
++/*
++ * get_supported_stream_engines
++ *
++ * @brief
++ * get a list of supported engine
++ *
++ * @param
++ * const struct encoder_impl *enc - not used.
++ *
++ * @return
++ * list of engines with supported ones enabled.
++ */
++union supported_stream_engines dce110_get_supported_stream_engines(
++ const struct link_encoder *enc)
++{
++ union supported_stream_engines result = {.u_all = 0};
++
++ result.engine.ENGINE_ID_DIGA = 1;
++ result.engine.ENGINE_ID_DIGB = 1;
++ result.engine.ENGINE_ID_DIGC = 1;
++
++ if (enc->connector.id == CONNECTOR_ID_EDP /*|| wireless*/)
++ result.u_all = (1 << enc->preferred_engine);
++
++ return result;
++}
++
++void dce110_link_encoder_set_lcd_backlight_level(
++ struct link_encoder *enc,
++ uint32_t level)
++{
++ struct dc_context *ctx = enc->ctx;
++
++ const uint32_t backlight_update_pending_max_retry = 1000;
++
++ uint32_t backlight;
++ uint32_t backlight_period;
++ uint32_t backlight_lock;
++
++ uint32_t i;
++ uint32_t backlight_24bit;
++ uint32_t backlight_17bit;
++ uint32_t backlight_16bit;
++ uint32_t masked_pwm_period;
++ uint8_t rounding_bit;
++ uint8_t bit_count;
++ uint64_t active_duty_cycle;
++
++ backlight = dal_read_reg(ctx, mmBL_PWM_CNTL);
++ backlight_period = dal_read_reg(ctx, mmBL_PWM_PERIOD_CNTL);
++ backlight_lock = dal_read_reg(ctx, mmBL_PWM_GRP1_REG_LOCK);
++
++ /*
++ * 1. Convert 8-bit value to 17 bit U1.16 format
++ * (1 integer, 16 fractional bits)
++ */
++
++ /* 1.1 multiply 8 bit value by 0x10101 to get a 24 bit value,
++ * effectively multiplying value by 256/255
++ * eg. for a level of 0xEF, backlight_24bit = 0xEF * 0x10101 = 0xEFEFEF
++ */
++ backlight_24bit = level * 0x10101;
++
++ /* 1.2 The upper 16 bits of the 24 bit value is the fraction, lower 8
++ * used for rounding, take most significant bit of fraction for
++ * rounding, e.g. for 0xEFEFEF, rounding bit is 1
++ */
++ rounding_bit = (backlight_24bit >> 7) & 1;
++
++ /* 1.3 Add the upper 16 bits of the 24 bit value with the rounding bit
++ * resulting in a 17 bit value e.g. 0xEFF0 = (0xEFEFEF >> 8) + 1
++ */
++ backlight_17bit = (backlight_24bit >> 8) + rounding_bit;
++
++ /*
++ * 2. Find 16 bit backlight active duty cycle, where 0 <= backlight
++ * active duty cycle <= backlight period
++ */
++
++ /* 2.1 Apply bitmask for backlight period value based on value of BITCNT
++ */
++ {
++ uint32_t pwm_period_bitcnt = get_reg_field_value(
++ backlight_period,
++ BL_PWM_PERIOD_CNTL,
++ BL_PWM_PERIOD_BITCNT);
++ if (pwm_period_bitcnt == 0)
++ bit_count = 16;
++ else
++ bit_count = pwm_period_bitcnt;
++ }
++
++ /* e.g. maskedPwmPeriod = 0x24 when bitCount is 6 */
++ masked_pwm_period =
++ get_reg_field_value(
++ backlight_period,
++ BL_PWM_PERIOD_CNTL,
++ BL_PWM_PERIOD) & ((1 << bit_count) - 1);
++
++ /* 2.2 Calculate integer active duty cycle required upper 16 bits
++ * contain integer component, lower 16 bits contain fractional component
++ * of active duty cycle e.g. 0x21BDC0 = 0xEFF0 * 0x24
++ */
++ active_duty_cycle = backlight_17bit * masked_pwm_period;
++
++ /* 2.3 Calculate 16 bit active duty cycle from integer and fractional
++ * components shift by bitCount then mask 16 bits and add rounding bit
++ * from MSB of fraction e.g. 0x86F7 = ((0x21BDC0 >> 6) & 0xFFF) + 0
++ */
++ backlight_16bit = active_duty_cycle >> bit_count;
++ backlight_16bit &= 0xFFFF;
++ backlight_16bit += (active_duty_cycle >> (bit_count - 1)) & 0x1;
++ set_reg_field_value(
++ backlight,
++ backlight_16bit,
++ BL_PWM_CNTL,
++ BL_ACTIVE_INT_FRAC_CNT);
++
++ /*
++ * 3. Program register with updated value
++ */
++
++ /* 3.1 Lock group 2 backlight registers */
++ set_reg_field_value(
++ backlight_lock,
++ 1,
++ BL_PWM_GRP1_REG_LOCK,
++ BL_PWM_GRP1_IGNORE_MASTER_LOCK_EN);
++ set_reg_field_value(
++ backlight_lock,
++ 1,
++ BL_PWM_GRP1_REG_LOCK,
++ BL_PWM_GRP1_REG_LOCK);
++ dal_write_reg(ctx, mmBL_PWM_GRP1_REG_LOCK, backlight_lock);
++
++ /* 3.2 Write new active duty cycle */
++ dal_write_reg(ctx, mmBL_PWM_CNTL, backlight);
++
++ /* 3.3 Unlock group 2 backlight registers */
++ set_reg_field_value(
++ backlight_lock,
++ 0,
++ BL_PWM_GRP1_REG_LOCK,
++ BL_PWM_GRP1_REG_LOCK);
++ dal_write_reg(ctx, mmBL_PWM_GRP1_REG_LOCK, backlight_lock);
++
++ /* 5.4.4 Wait for pending bit to be cleared */
++ for (i = 0; i < backlight_update_pending_max_retry; ++i) {
++ backlight_lock = dal_read_reg(ctx, mmBL_PWM_GRP1_REG_LOCK);
++ if (!get_reg_field_value(
++ backlight_lock,
++ BL_PWM_GRP1_REG_LOCK,
++ BL_PWM_GRP1_REG_UPDATE_PENDING))
++ break;
++
++ dc_service_delay_in_microseconds(ctx, 10);
++ }
++}
++
++/*TODO: move to correct dce specific file*/
++/**
++* set_afmt_memory_power_state
++*
++* @brief
++* Power up audio formatter memory that is mapped to specified DIG
++*/
++void dce110_set_afmt_memory_power_state(
++ const struct dc_context *ctx,
++ enum engine_id id,
++ bool enable)
++{
++ uint32_t value;
++ uint32_t mem_pwr_force;
++
++ value = dal_read_reg(ctx, mmDCO_MEM_PWR_CTRL);
++
++ if (enable)
++ mem_pwr_force = 0;
++ else
++ mem_pwr_force = 3;
++
++ /* force shutdown mode for appropriate AFMT memory */
++ switch (id) {
++ case ENGINE_ID_DIGA:
++ set_reg_field_value(
++ value,
++ mem_pwr_force,
++ DCO_MEM_PWR_CTRL,
++ HDMI0_MEM_PWR_FORCE);
++ break;
++ case ENGINE_ID_DIGB:
++ set_reg_field_value(
++ value,
++ mem_pwr_force,
++ DCO_MEM_PWR_CTRL,
++ HDMI1_MEM_PWR_FORCE);
++ break;
++ case ENGINE_ID_DIGC:
++ set_reg_field_value(
++ value,
++ mem_pwr_force,
++ DCO_MEM_PWR_CTRL,
++ HDMI2_MEM_PWR_FORCE);
++ break;
++ default:
++ dal_logger_write(
++ ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_ENCODER,
++ "%s: Invalid Engine Id\n",
++ __func__);
++ break;
++ }
++
++ dal_write_reg(ctx, mmDCO_MEM_PWR_CTRL, value);
++}
++
++void dce110_link_encoder_update_mst_stream_allocation_table(
++ struct link_encoder *enc,
++ const struct dp_mst_stream_allocation_table *table,
++ bool is_removal)
++{
++ int32_t addr_offset = enc->be_engine_offset;
++ uint32_t value0;
++ uint32_t value1;
++ uint32_t retries = 0;
++
++ /* For CZ, there are only 3 pipes. So Virtual channel is up 3.*/
++
++ /* --- Set MSE Stream Attribute -
++ * Setup VC Payload Table on Tx Side,
++ * Issue allocation change trigger
++ * to commit payload on both tx and rx side */
++
++ value0 = dal_read_reg(enc->ctx, mmDP_MSE_SAT0 + addr_offset);
++ value1 = dal_read_reg(enc->ctx, mmDP_MSE_SAT1 + addr_offset);
++
++ if (table->stream_count >= 1) {
++ set_reg_field_value(
++ value0,
++ table->stream_allocations[0].engine,
++ DP_MSE_SAT0,
++ DP_MSE_SAT_SRC0);
++
++ set_reg_field_value(
++ value0,
++ table->stream_allocations[0].slot_count,
++ DP_MSE_SAT0,
++ DP_MSE_SAT_SLOT_COUNT0);
++ }
++
++ if (table->stream_count >= 2) {
++ set_reg_field_value(
++ value0,
++ table->stream_allocations[1].engine,
++ DP_MSE_SAT0,
++ DP_MSE_SAT_SRC1);
++
++ set_reg_field_value(
++ value0,
++ table->stream_allocations[1].slot_count,
++ DP_MSE_SAT0,
++ DP_MSE_SAT_SLOT_COUNT1);
++ }
++
++ if (table->stream_count >= 3) {
++ set_reg_field_value(
++ value1,
++ table->stream_allocations[2].engine,
++ DP_MSE_SAT1,
++ DP_MSE_SAT_SRC2);
++
++ set_reg_field_value(
++ value1,
++ table->stream_allocations[2].slot_count,
++ DP_MSE_SAT1,
++ DP_MSE_SAT_SLOT_COUNT2);
++ }
++
++ /* update ASIC MSE stream allocation table */
++ dal_write_reg(enc->ctx, mmDP_MSE_SAT0 + addr_offset, value0);
++ dal_write_reg(enc->ctx, mmDP_MSE_SAT1 + addr_offset, value1);
++
++ /* --- wait for transaction finish */
++
++ /* send allocation change trigger (ACT) ?
++ * this step first sends the ACT,
++ * then double buffers the SAT into the hardware
++ * making the new allocation active on the DP MST mode link */
++
++ value0 = dal_read_reg(enc->ctx, mmDP_MSE_SAT_UPDATE + addr_offset);
++
++ /* DP_MSE_SAT_UPDATE:
++ * 0 - No Action
++ * 1 - Update SAT with trigger
++ * 2 - Update SAT without trigger */
++
++ set_reg_field_value(
++ value0,
++ 1,
++ DP_MSE_SAT_UPDATE,
++ DP_MSE_SAT_UPDATE);
++
++ dal_write_reg(enc->ctx, mmDP_MSE_SAT_UPDATE + addr_offset, value0);
++
++ /* wait for update to complete
++ * (i.e. DP_MSE_SAT_UPDATE field is reset to 0)
++ * then wait for the transmission
++ * of at least 16 MTP headers on immediate local link.
++ * i.e. DP_MSE_16_MTP_KEEPOUT field (read only) is reset to 0
++ * a value of 1 indicates that DP MST mode
++ * is in the 16 MTP keepout region after a VC has been added.
++ * MST stream bandwidth (VC rate) can be configured
++ * after this bit is cleared */
++
++ do {
++ dc_service_delay_in_microseconds(enc->ctx, 10);
++
++ value0 = dal_read_reg(enc->ctx,
++ mmDP_MSE_SAT_UPDATE + addr_offset);
++
++ value1 = get_reg_field_value(
++ value0,
++ DP_MSE_SAT_UPDATE,
++ DP_MSE_16_MTP_KEEPOUT);
++
++ /* bit field DP_MSE_SAT_UPDATE is set to 1 already */
++ if (value1)
++ break;
++ ++retries;
++ } while (retries < DP_MST_UPDATE_MAX_RETRY);
++
++ /* TODO should not need. clean this after light up
++ * if (is_removal)
++ * dal_write_reg(enc->ctx, addr, value);
++ */
++}
++
++void dce110_link_encoder_set_mst_bandwidth(
++ struct link_encoder *enc,
++ enum engine_id engine,
++ struct fixed31_32 avg_time_slots_per_mtp)
++{
++ uint32_t x = dal_fixed31_32_floor(
++ avg_time_slots_per_mtp);
++
++ uint32_t y = dal_fixed31_32_ceil(
++ dal_fixed31_32_shl(
++ dal_fixed31_32_sub_int(
++ avg_time_slots_per_mtp,
++ x),
++ 26));
++
++ {
++ const uint32_t addr = mmDP_MSE_RATE_CNTL +
++ fe_engine_offsets[engine];
++ uint32_t value = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(
++ value,
++ x,
++ DP_MSE_RATE_CNTL,
++ DP_MSE_RATE_X);
++
++ set_reg_field_value(
++ value,
++ y,
++ DP_MSE_RATE_CNTL,
++ DP_MSE_RATE_Y);
++
++ dal_write_reg(enc->ctx, addr, value);
++ }
++
++ /* wait for update to be completed on the link
++ * i.e. DP_MSE_RATE_UPDATE_PENDING field (read only)
++ * is reset to 0 (not pending) */
++ {
++ const uint32_t addr = mmDP_MSE_RATE_UPDATE +
++ fe_engine_offsets[engine];
++ uint32_t value, field;
++ uint32_t retries = 0;
++
++ do {
++ value = dal_read_reg(enc->ctx, addr);
++
++ field = get_reg_field_value(
++ value,
++ DP_MSE_RATE_UPDATE,
++ DP_MSE_RATE_UPDATE_PENDING);
++
++ if (!(field &
++ DP_MSE_RATE_UPDATE__DP_MSE_RATE_UPDATE_PENDING_MASK))
++ break;
++
++ dc_service_delay_in_microseconds(enc->ctx, 10);
++
++ ++retries;
++ } while (retries < DP_MST_UPDATE_MAX_RETRY);
++ }
++}
++
++void dce110_link_encoder_connect_dig_be_to_fe(
++ struct link_encoder *enc,
++ enum engine_id engine,
++ bool connect)
++{
++ uint32_t addr;
++ uint32_t value;
++ uint32_t field;
++
++ if (engine != ENGINE_ID_UNKNOWN) {
++ addr = mmDIG_BE_CNTL + enc->be_engine_offset;
++ value = dal_read_reg(enc->ctx, addr);
++
++ field = get_reg_field_value(
++ value,
++ DIG_BE_CNTL,
++ DIG_FE_SOURCE_SELECT);
++
++ if (connect)
++ field |= get_frontend_source(engine);
++ else
++ field &= ~get_frontend_source(engine);
++
++ set_reg_field_value(
++ value,
++ field,
++ DIG_BE_CNTL,
++ DIG_FE_SOURCE_SELECT);
++ dal_write_reg(enc->ctx, addr, value);
++ }
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
+new file mode 100644
+index 0000000..4331bf0
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_link_encoder.h
+@@ -0,0 +1,91 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_LINK_ENCODER__DCE110_H__
++#define __DC_LINK_ENCODER__DCE110_H__
++
++struct link_encoder *dce110_link_encoder_create(
++ const struct encoder_init_data *init);
++void dce110_link_encoder_destroy(struct link_encoder **enc);
++
++void dce110_link_encoder_set_dp_phy_pattern(
++ struct link_encoder *enc,
++ const struct encoder_set_dp_phy_pattern_param *param);
++
++enum encoder_result dce110_link_encoder_power_up(struct link_encoder *enc);
++
++enum encoder_result dce110_link_encoder_dp_set_lane_settings(
++ struct link_encoder *enc,
++ const struct link_training_settings *link_settings);
++
++union supported_stream_engines dce110_get_supported_stream_engines(
++ const struct link_encoder *enc);
++
++enum encoder_result dce110_link_encoder_validate_output_with_stream(
++ struct link_encoder *enc,
++ const struct core_stream *stream);
++
++void dce110_link_encoder_set_lcd_backlight_level(
++ struct link_encoder *enc,
++ uint32_t level);
++
++void dce110_link_encoder_setup(
++ struct link_encoder *enc,
++ enum signal_type signal);
++
++enum encoder_result dce110_link_encoder_enable_output(
++ struct link_encoder *enc,
++ const struct link_settings *link_settings,
++ enum engine_id engine,
++ enum clock_source_id clock_source,
++ enum signal_type signal,
++ enum dc_color_depth color_depth,
++ uint32_t pixel_clock);
++
++enum encoder_result dce110_link_encoder_disable_output(
++ struct link_encoder *link_enc,
++ enum signal_type signal);
++
++void dce110_set_afmt_memory_power_state(
++ const struct dc_context *ctx,
++ enum engine_id id,
++ bool enable);
++
++void dce110_link_encoder_update_mst_stream_allocation_table(
++ struct link_encoder *enc,
++ const struct dp_mst_stream_allocation_table *table,
++ bool is_removal);
++
++void dce110_link_encoder_set_mst_bandwidth(
++ struct link_encoder *enc,
++ enum engine_id engine,
++ struct fixed31_32 avg_time_slots_per_mtp);
++
++void dce110_link_encoder_connect_dig_be_to_fe(
++ struct link_encoder *enc,
++ enum engine_id engine,
++ bool connect);
++
++#endif /* __DC_LINK_ENCODER__DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
+new file mode 100644
+index 0000000..7391a0a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.c
+@@ -0,0 +1,969 @@
++/*
++ * 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 "dal_services.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++/* TODO: this needs to be looked at, used by Stella's workaround*/
++#include "gmc/gmc_8_2_d.h"
++#include "gmc/gmc_8_2_sh_mask.h"
++
++#include "include/logger_interface.h"
++#include "adapter_service_interface.h"
++#include "inc/bandwidth_calcs.h"
++
++#include "dce110_mem_input.h"
++
++#define MAX_WATERMARK 0xFFFF
++#define SAFE_NBP_MARK 0x7FFF
++
++#define DCP_REG(reg) (reg + mem_input110->offsets.dcp)
++#define DMIF_REG(reg) (reg + mem_input110->offsets.dmif)
++#define PIPE_REG(reg) (reg + mem_input110->offsets.pipe)
++
++static const struct dce110_mem_input_reg_offsets reg_offsets[] = {
++{
++ .dcp = 0,
++ .dmif = 0,
++ .pipe = 0,
++},
++{
++ .dcp = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .dmif = (mmDMIF_PG1_DPG_WATERMARK_MASK_CONTROL
++ - mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL),
++ .pipe = (mmPIPE1_DMIF_BUFFER_CONTROL - mmPIPE0_DMIF_BUFFER_CONTROL),
++},
++{
++ .dcp = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .dmif = (mmDMIF_PG2_DPG_WATERMARK_MASK_CONTROL
++ - mmDMIF_PG0_DPG_WATERMARK_MASK_CONTROL),
++ .pipe = (mmPIPE2_DMIF_BUFFER_CONTROL - mmPIPE0_DMIF_BUFFER_CONTROL),
++}
++};
++
++static void set_flip_control(
++ struct dce110_mem_input *mem_input110,
++ bool immediate)
++{
++ uint32_t value = 0;
++
++ value = dal_read_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_FLIP_CONTROL));
++ set_reg_field_value(value, 0,
++ GRPH_FLIP_CONTROL,
++ GRPH_SURFACE_UPDATE_IMMEDIATE_EN);
++ set_reg_field_value(value, 0,
++ GRPH_FLIP_CONTROL,
++ GRPH_SURFACE_UPDATE_H_RETRACE_EN);
++ if (immediate == true)
++ set_reg_field_value(value, 1,
++ GRPH_FLIP_CONTROL,
++ GRPH_SURFACE_UPDATE_IMMEDIATE_EN);
++
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_FLIP_CONTROL),
++ value);
++}
++
++static void program_sec_addr(
++ struct dce110_mem_input *mem_input110,
++ PHYSICAL_ADDRESS_LOC address)
++{
++ uint32_t value = 0;
++ uint32_t temp = 0;
++ /*high register MUST be programmed first*/
++ temp = address.high_part &
++GRPH_SECONDARY_SURFACE_ADDRESS_HIGH__GRPH_SECONDARY_SURFACE_ADDRESS_HIGH_MASK;
++
++ set_reg_field_value(value, temp,
++ GRPH_SECONDARY_SURFACE_ADDRESS_HIGH,
++ GRPH_SECONDARY_SURFACE_ADDRESS_HIGH);
++
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_SECONDARY_SURFACE_ADDRESS_HIGH),
++ value);
++
++ temp = 0;
++ value = 0;
++ temp = address.low_part >>
++ GRPH_SECONDARY_SURFACE_ADDRESS__GRPH_SECONDARY_SURFACE_ADDRESS__SHIFT;
++
++ set_reg_field_value(value, temp,
++ GRPH_SECONDARY_SURFACE_ADDRESS,
++ GRPH_SECONDARY_SURFACE_ADDRESS);
++
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_SECONDARY_SURFACE_ADDRESS),
++ value);
++}
++
++static void program_pri_addr(
++ struct dce110_mem_input *mem_input110,
++ PHYSICAL_ADDRESS_LOC address)
++{
++ uint32_t value = 0;
++ uint32_t temp = 0;
++
++ /*high register MUST be programmed first*/
++ temp = address.high_part &
++GRPH_PRIMARY_SURFACE_ADDRESS_HIGH__GRPH_PRIMARY_SURFACE_ADDRESS_HIGH_MASK;
++
++ set_reg_field_value(value, temp,
++ GRPH_PRIMARY_SURFACE_ADDRESS_HIGH,
++ GRPH_PRIMARY_SURFACE_ADDRESS_HIGH);
++
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_PRIMARY_SURFACE_ADDRESS_HIGH),
++ value);
++
++ temp = 0;
++ value = 0;
++ temp = address.low_part >>
++ GRPH_PRIMARY_SURFACE_ADDRESS__GRPH_PRIMARY_SURFACE_ADDRESS__SHIFT;
++
++ set_reg_field_value(value, temp,
++ GRPH_PRIMARY_SURFACE_ADDRESS,
++ GRPH_PRIMARY_SURFACE_ADDRESS);
++
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_PRIMARY_SURFACE_ADDRESS),
++ value);
++}
++
++static void program_addr(
++ struct dce110_mem_input *mem_input110,
++ const struct dc_plane_address *addr)
++{
++ switch (addr->type) {
++ case PLN_ADDR_TYPE_GRAPHICS:
++ program_pri_addr(
++ mem_input110,
++ addr->grph.addr);
++ break;
++ case PLN_ADDR_TYPE_GRPH_STEREO:
++ program_pri_addr(
++ mem_input110,
++ addr->grph_stereo.left_addr);
++ program_sec_addr(
++ mem_input110,
++ addr->grph_stereo.right_addr);
++ break;
++ case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE:
++ case PLN_ADDR_TYPE_VIDEO_INTERLACED:
++ case PLN_ADDR_TYPE_VIDEO_PROGRESSIVE_STEREO:
++ case PLN_ADDR_TYPE_VIDEO_INTERLACED_STEREO:
++ default:
++ /* not supported */
++ BREAK_TO_DEBUGGER();
++ }
++}
++
++static void enable(struct dce110_mem_input *mem_input110)
++{
++ uint32_t value = 0;
++
++ value = dal_read_reg(mem_input110->base.ctx, DCP_REG(mmGRPH_ENABLE));
++ set_reg_field_value(value, 1, GRPH_ENABLE, GRPH_ENABLE);
++ dal_write_reg(mem_input110->base.ctx,
++ DCP_REG(mmGRPH_ENABLE),
++ value);
++}
++
++static void program_tiling(
++ struct dce110_mem_input *mem_input110,
++ const union plane_tiling_info *info,
++ const enum surface_pixel_format pixel_format)
++{
++ uint32_t value = 0;
++
++ value = dal_read_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_CONTROL));
++
++ set_reg_field_value(value, info->grph.NUM_BANKS,
++ GRPH_CONTROL, GRPH_NUM_BANKS);
++
++ set_reg_field_value(value, info->grph.BANK_WIDTH,
++ GRPH_CONTROL, GRPH_BANK_WIDTH);
++
++ set_reg_field_value(value, info->grph.BANK_HEIGHT,
++ GRPH_CONTROL, GRPH_BANK_HEIGHT);
++
++ set_reg_field_value(value, info->grph.TILE_ASPECT,
++ GRPH_CONTROL, GRPH_MACRO_TILE_ASPECT);
++
++ set_reg_field_value(value, info->grph.TILE_SPLIT,
++ GRPH_CONTROL, GRPH_TILE_SPLIT);
++
++ set_reg_field_value(value, info->grph.TILE_MODE,
++ GRPH_CONTROL, GRPH_MICRO_TILE_MODE);
++
++ set_reg_field_value(value, info->grph.PIPE_CONFIG,
++ GRPH_CONTROL, GRPH_PIPE_CONFIG);
++
++ set_reg_field_value(value, info->grph.ARRAY_MODE,
++ GRPH_CONTROL, GRPH_ARRAY_MODE);
++
++ set_reg_field_value(value, 1,
++ GRPH_CONTROL, GRPH_COLOR_EXPANSION_MODE);
++
++ set_reg_field_value(value, 0,
++ GRPH_CONTROL, GRPH_Z);
++
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_CONTROL),
++ value);
++}
++
++static void program_size_and_rotation(
++ struct dce110_mem_input *mem_input110,
++ enum dc_rotation_angle rotation,
++ const union plane_size *plane_size)
++{
++ uint32_t value = 0;
++ union plane_size local_size = *plane_size;
++
++ if (rotation == ROTATION_ANGLE_90 ||
++ rotation == ROTATION_ANGLE_270) {
++
++ uint32_t swap;
++
++ swap = local_size.grph.surface_size.x;
++ local_size.grph.surface_size.x =
++ local_size.grph.surface_size.y;
++ local_size.grph.surface_size.y = swap;
++
++ swap = local_size.grph.surface_size.width;
++ local_size.grph.surface_size.width =
++ local_size.grph.surface_size.height;
++ local_size.grph.surface_size.height = swap;
++ }
++
++ set_reg_field_value(value, local_size.grph.surface_size.x,
++ GRPH_X_START, GRPH_X_START);
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_X_START),
++ value);
++
++ value = 0;
++ set_reg_field_value(value, local_size.grph.surface_size.y,
++ GRPH_Y_START, GRPH_Y_START);
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_Y_START),
++ value);
++
++ value = 0;
++ set_reg_field_value(value, local_size.grph.surface_size.width,
++ GRPH_X_END, GRPH_X_END);
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_X_END),
++ value);
++
++ value = 0;
++ set_reg_field_value(value, local_size.grph.surface_size.height,
++ GRPH_Y_END, GRPH_Y_END);
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_Y_END),
++ value);
++
++ value = 0;
++ set_reg_field_value(value, local_size.grph.surface_pitch,
++ GRPH_PITCH, GRPH_PITCH);
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_PITCH),
++ value);
++
++
++ value = 0;
++ switch (rotation) {
++ case ROTATION_ANGLE_90:
++ set_reg_field_value(value, 3,
++ HW_ROTATION, GRPH_ROTATION_ANGLE);
++ break;
++ case ROTATION_ANGLE_180:
++ set_reg_field_value(value, 2,
++ HW_ROTATION, GRPH_ROTATION_ANGLE);
++ break;
++ case ROTATION_ANGLE_270:
++ set_reg_field_value(value, 1,
++ HW_ROTATION, GRPH_ROTATION_ANGLE);
++ break;
++ default:
++ set_reg_field_value(value, 0,
++ HW_ROTATION, GRPH_ROTATION_ANGLE);
++ break;
++ }
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmHW_ROTATION),
++ value);
++}
++
++static void program_pixel_format(
++ struct dce110_mem_input *mem_input110,
++ enum surface_pixel_format format)
++{
++ if (format >= SURFACE_PIXEL_FORMAT_GRPH_BEGIN &&
++ format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
++ uint32_t value = 0;
++
++ /* handle colour twizzle formats, swapping R and B */
++ if (format == SURFACE_PIXEL_FORMAT_GRPH_BGRA8888 ||
++ format == SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010 ||
++ format ==
++ SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS ||
++ format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) {
++ set_reg_field_value(
++ value, 2, GRPH_SWAP_CNTL, GRPH_RED_CROSSBAR);
++ set_reg_field_value(
++ value, 2, GRPH_SWAP_CNTL, GRPH_BLUE_CROSSBAR);
++ }
++
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_SWAP_CNTL),
++ value);
++
++
++ value = dal_read_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_CONTROL));
++
++ switch (format) {
++ case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
++ set_reg_field_value(
++ value, 0, GRPH_CONTROL, GRPH_DEPTH);
++ set_reg_field_value(
++ value, 0, GRPH_CONTROL, GRPH_FORMAT);
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
++ set_reg_field_value(
++ value, 1, GRPH_CONTROL, GRPH_DEPTH);
++ set_reg_field_value(
++ value, 1, GRPH_CONTROL, GRPH_FORMAT);
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ARGB8888:
++ case SURFACE_PIXEL_FORMAT_GRPH_BGRA8888:
++ set_reg_field_value(
++ value, 2, GRPH_CONTROL, GRPH_DEPTH);
++ set_reg_field_value(
++ value, 0, GRPH_CONTROL, GRPH_FORMAT);
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
++ case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
++ case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
++ set_reg_field_value(
++ value, 2, GRPH_CONTROL, GRPH_DEPTH);
++ set_reg_field_value(
++ value, 1, GRPH_CONTROL, GRPH_FORMAT);
++ break;
++ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
++ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
++ set_reg_field_value(
++ value, 3, GRPH_CONTROL, GRPH_DEPTH);
++ set_reg_field_value(
++ value, 0, GRPH_CONTROL, GRPH_FORMAT);
++ break;
++ default:
++ break;
++ }
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmGRPH_CONTROL),
++ value);
++
++ /*TODO [hwentlan] MOVE THIS TO CONTROLLER GAMMA!!!!!*/
++ value = dal_read_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmPRESCALE_GRPH_CONTROL));
++
++ if (format == SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F) {
++ set_reg_field_value(
++ value, 1, PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_SELECT);
++ set_reg_field_value(
++ value, 1, PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_R_SIGN);
++ set_reg_field_value(
++ value, 1, PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_G_SIGN);
++ set_reg_field_value(
++ value, 1, PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_B_SIGN);
++ } else {
++ set_reg_field_value(
++ value, 0, PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_SELECT);
++ set_reg_field_value(
++ value, 0, PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_R_SIGN);
++ set_reg_field_value(
++ value, 0, PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_G_SIGN);
++ set_reg_field_value(
++ value, 0, PRESCALE_GRPH_CONTROL,
++ GRPH_PRESCALE_B_SIGN);
++ }
++ dal_write_reg(
++ mem_input110->base.ctx,
++ DCP_REG(mmPRESCALE_GRPH_CONTROL),
++ value);
++ }
++}
++
++bool dce110_mem_input_program_surface_flip_and_addr(
++ struct mem_input *mem_input,
++ const struct dc_plane_address *address,
++ bool flip_immediate)
++{
++ struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
++
++ set_flip_control(mem_input110, flip_immediate);
++ program_addr(mem_input110,
++ address);
++
++ return true;
++}
++
++bool dce110_mem_input_program_surface_config(
++ struct mem_input *mem_input,
++ const struct dc_surface *surface)
++{
++ struct dce110_mem_input *mem_input110 = TO_DCE110_MEM_INPUT(mem_input);
++
++ enable(mem_input110);
++ program_tiling(mem_input110, &surface->tiling_info, surface->format);
++ program_size_and_rotation(mem_input110,
++ surface->rotation, &surface->plane_size);
++ program_pixel_format(mem_input110, surface->format);
++
++ return true;
++}
++
++static void program_urgency_watermark(
++ const struct dc_context *ctx,
++ const uint32_t offset,
++ struct bw_watermarks marks_low,
++ uint32_t total_dest_line_time_ns)
++{
++ /* register value */
++ uint32_t urgency_cntl = 0;
++ uint32_t wm_mask_cntl = 0;
++
++ uint32_t urgency_addr = offset + mmDPG_PIPE_URGENCY_CONTROL;
++ uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++
++ /*Write mask to enable reading/writing of watermark set A*/
++ wm_mask_cntl = dal_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 1,
++ DPG_WATERMARK_MASK_CONTROL,
++ URGENCY_WATERMARK_MASK);
++ dal_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ urgency_cntl = dal_read_reg(ctx, urgency_addr);
++
++ set_reg_field_value(
++ urgency_cntl,
++ marks_low.a_mark,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_LOW_WATERMARK);
++
++ set_reg_field_value(
++ urgency_cntl,
++ total_dest_line_time_ns,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_HIGH_WATERMARK);
++ dal_write_reg(ctx, urgency_addr, urgency_cntl);
++
++
++ /*Write mask to enable reading/writing of watermark set B*/
++ wm_mask_cntl = dal_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 2,
++ DPG_WATERMARK_MASK_CONTROL,
++ URGENCY_WATERMARK_MASK);
++ dal_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ urgency_cntl = dal_read_reg(ctx, urgency_addr);
++
++ set_reg_field_value(urgency_cntl,
++ marks_low.b_mark,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_LOW_WATERMARK);
++
++ set_reg_field_value(urgency_cntl,
++ total_dest_line_time_ns,
++ DPG_PIPE_URGENCY_CONTROL,
++ URGENCY_HIGH_WATERMARK);
++ dal_write_reg(ctx, urgency_addr, urgency_cntl);
++}
++
++void dce110_program_stutter_watermark(
++ struct mem_input *mi,
++ struct bw_watermarks marks)
++{
++ const struct dc_context *ctx = mi->ctx;
++ const uint32_t offset = TO_DCE110_MEM_INPUT(mi)->offsets.dmif;
++ /* register value */
++ uint32_t stutter_cntl = 0;
++ uint32_t wm_mask_cntl = 0;
++
++ uint32_t stutter_addr = offset + mmDPG_PIPE_STUTTER_CONTROL;
++ uint32_t wm_addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++
++ /*Write mask to enable reading/writing of watermark set A*/
++
++ wm_mask_cntl = dal_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 1,
++ DPG_WATERMARK_MASK_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
++ dal_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ stutter_cntl = dal_read_reg(ctx, stutter_addr);
++
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_ENABLE);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_IGNORE_FBC);
++
++ /*Write watermark set A*/
++ set_reg_field_value(stutter_cntl,
++ marks.a_mark,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK);
++ dal_write_reg(ctx, stutter_addr, stutter_cntl);
++
++ /*Write mask to enable reading/writing of watermark set B*/
++ wm_mask_cntl = dal_read_reg(ctx, wm_addr);
++ set_reg_field_value(wm_mask_cntl,
++ 2,
++ DPG_WATERMARK_MASK_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK_MASK);
++ dal_write_reg(ctx, wm_addr, wm_mask_cntl);
++
++ stutter_cntl = dal_read_reg(ctx, stutter_addr);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_ENABLE);
++ set_reg_field_value(stutter_cntl,
++ 1,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_IGNORE_FBC);
++
++ /*Write watermark set B*/
++ set_reg_field_value(stutter_cntl,
++ marks.b_mark,
++ DPG_PIPE_STUTTER_CONTROL,
++ STUTTER_EXIT_SELF_REFRESH_WATERMARK);
++ dal_write_reg(ctx, stutter_addr, stutter_cntl);
++}
++
++void dce110_program_nbp_watermark(
++ struct mem_input *mi,
++ struct bw_watermarks marks)
++{
++ const struct dc_context *ctx = mi->ctx;
++ const uint32_t offset = TO_DCE110_MEM_INPUT(mi)->offsets.dmif;
++ uint32_t value;
++ uint32_t addr;
++ /* Write mask to enable reading/writing of watermark set A */
++ addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_WATERMARK_MASK_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK_MASK);
++ dal_write_reg(ctx, addr, value);
++
++ addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_ENABLE);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
++ dal_write_reg(ctx, addr, value);
++
++ /* Write watermark set A */
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ marks.a_mark,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK);
++ dal_write_reg(ctx, addr, value);
++
++ /* Write mask to enable reading/writing of watermark set B */
++ addr = offset + mmDPG_WATERMARK_MASK_CONTROL;
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 2,
++ DPG_WATERMARK_MASK_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK_MASK);
++ dal_write_reg(ctx, addr, value);
++
++ addr = offset + mmDPG_PIPE_NB_PSTATE_CHANGE_CONTROL;
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_ENABLE);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_URGENT_DURING_REQUEST);
++ set_reg_field_value(
++ value,
++ 1,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_NOT_SELF_REFRESH_DURING_REQUEST);
++ dal_write_reg(ctx, addr, value);
++
++ /* Write watermark set B */
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ marks.b_mark,
++ DPG_PIPE_NB_PSTATE_CHANGE_CONTROL,
++ NB_PSTATE_CHANGE_WATERMARK);
++ dal_write_reg(ctx, addr, value);
++}
++
++void dce110_program_safe_display_marks(struct mem_input *mi)
++{
++ struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mi);
++ struct bw_watermarks max_marks = { MAX_WATERMARK, MAX_WATERMARK };
++ struct bw_watermarks nbp_marks = { SAFE_NBP_MARK, SAFE_NBP_MARK };
++
++ program_urgency_watermark(
++ mi->ctx, bm_dce110->offsets.dmif, max_marks, MAX_WATERMARK);
++ dce110_program_stutter_watermark(mi, max_marks);
++ dce110_program_nbp_watermark(mi, nbp_marks);
++
++}
++
++void dce110_program_urgency_watermark(
++ struct mem_input *mi,
++ struct bw_watermarks marks,
++ uint32_t h_total,
++ uint32_t pixel_clk_in_khz,
++ uint32_t pstate_blackout_duration_ns)
++{
++ struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mi);
++ uint32_t total_dest_line_time_ns = 1000000ULL * h_total
++ / pixel_clk_in_khz + pstate_blackout_duration_ns;
++
++ program_urgency_watermark(
++ mi->ctx,
++ bm_dce110->offsets.dmif,
++ marks,
++ total_dest_line_time_ns);
++}
++
++static uint32_t get_dmif_switch_time_us(struct dc_crtc_timing *timing)
++{
++ uint32_t frame_time;
++ uint32_t pixels_per_second;
++ uint32_t pixels_per_frame;
++ uint32_t refresh_rate;
++ const uint32_t us_in_sec = 1000000;
++ const uint32_t min_single_frame_time_us = 30000;
++ /*return double of frame time*/
++ const uint32_t single_frame_time_multiplier = 2;
++
++ if (timing == NULL)
++ return single_frame_time_multiplier * min_single_frame_time_us;
++
++ /*TODO: should we use pixel format normalized pixel clock here?*/
++ pixels_per_second = timing->pix_clk_khz * 1000;
++ pixels_per_frame = timing->h_total * timing->v_total;
++
++ if (!pixels_per_second || !pixels_per_frame) {
++ /* avoid division by zero */
++ ASSERT(pixels_per_frame);
++ ASSERT(pixels_per_second);
++ return single_frame_time_multiplier * min_single_frame_time_us;
++ }
++
++ refresh_rate = pixels_per_second / pixels_per_frame;
++
++ if (!refresh_rate) {
++ /* avoid division by zero*/
++ ASSERT(refresh_rate);
++ return single_frame_time_multiplier * min_single_frame_time_us;
++ }
++
++ frame_time = us_in_sec / refresh_rate;
++
++ if (frame_time < min_single_frame_time_us)
++ frame_time = min_single_frame_time_us;
++
++ frame_time *= single_frame_time_multiplier;
++
++ return frame_time;
++}
++
++void dce110_allocate_dmif_buffer(
++ struct mem_input *mi,
++ struct dc_crtc_timing *timing,
++ uint32_t paths_num)
++{
++ const uint32_t retry_delay = 10;
++ uint32_t retry_count = get_dmif_switch_time_us(timing) / retry_delay;
++
++ struct dce110_mem_input *bm110 = TO_DCE110_MEM_INPUT(mi);
++ uint32_t addr = bm110->offsets.pipe + mmPIPE0_DMIF_BUFFER_CONTROL;
++ uint32_t value;
++ uint32_t field;
++
++ if (bm110->supported_stutter_mode
++ & STUTTER_MODE_NO_DMIF_BUFFER_ALLOCATION)
++ goto register_underflow_int;
++
++ /*Allocate DMIF buffer*/
++ value = dal_read_reg(mi->ctx, addr);
++ field = get_reg_field_value(
++ value, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED);
++ if (field == 2)
++ goto register_underflow_int;
++
++ set_reg_field_value(
++ value,
++ 2,
++ PIPE0_DMIF_BUFFER_CONTROL,
++ DMIF_BUFFERS_ALLOCATED);
++
++ dal_write_reg(mi->ctx, addr, value);
++
++ do {
++ value = dal_read_reg(mi->ctx, addr);
++ field = get_reg_field_value(
++ value,
++ PIPE0_DMIF_BUFFER_CONTROL,
++ DMIF_BUFFERS_ALLOCATION_COMPLETED);
++
++ if (field)
++ break;
++
++ dc_service_delay_in_microseconds(mi->ctx, retry_delay);
++ retry_count--;
++
++ } while (retry_count > 0);
++
++ if (field == 0)
++ dal_logger_write(mi->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: DMIF allocation failed",
++ __func__);
++
++ /*
++ * Stella Wong proposed the following change
++ *
++ * Value of mcHubRdReqDmifLimit.ENABLE:
++ * 00 - disable DMIF rdreq limit
++ * 01 - enable DMIF rdreq limit, disabled by DMIF stall = 1 || urg != 0
++ * 02 - enable DMIF rdreq limit, disable by DMIF stall = 1
++ * 03 - force enable DMIF rdreq limit, ignore DMIF stall / urgent
++ */
++ addr = mmMC_HUB_RDREQ_DMIF_LIMIT;
++ value = dal_read_reg(mi->ctx, addr);
++ if (paths_num > 1)
++ set_reg_field_value(value, 0, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE);
++ else
++ set_reg_field_value(value, 3, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE);
++ dal_write_reg(mi->ctx, addr, value);
++
++register_underflow_int:
++ /*todo*/;
++ /*register_interrupt(bm110, irq_source, ctrl_id);*/
++}
++
++static void deallocate_dmif_buffer_helper(
++ struct dc_context *ctx, uint32_t offset)
++{
++ uint32_t value;
++ uint32_t count = 0xBB8; /* max retry count */
++
++ value = dal_read_reg(ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset);
++
++ if (!get_reg_field_value(
++ value, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED))
++ return;
++
++ set_reg_field_value(
++ value, 0, PIPE0_DMIF_BUFFER_CONTROL, DMIF_BUFFERS_ALLOCATED);
++
++ dal_write_reg(
++ ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset, value);
++
++ do {
++ value = dal_read_reg(ctx, mmPIPE0_DMIF_BUFFER_CONTROL + offset);
++ dc_service_delay_in_microseconds(ctx, 10);
++ count--;
++ } while (count > 0 &&
++ !get_reg_field_value(
++ value,
++ PIPE0_DMIF_BUFFER_CONTROL,
++ DMIF_BUFFERS_ALLOCATION_COMPLETED));
++}
++
++void dce110_deallocate_dmif_buffer(struct mem_input *mi, uint32_t paths_num)
++{
++ struct dce110_mem_input *bm_dce110 = TO_DCE110_MEM_INPUT(mi);
++ uint32_t value;
++
++ if (!(bm_dce110->supported_stutter_mode &
++ STUTTER_MODE_NO_DMIF_BUFFER_ALLOCATION)) {
++
++ /* De-allocate DMIF buffer first */
++ if (mmPIPE0_DMIF_BUFFER_CONTROL + bm_dce110->offsets.pipe != 0)
++ deallocate_dmif_buffer_helper(
++ mi->ctx, bm_dce110->offsets.pipe);
++ }
++
++ /* TODO: unregister underflow interrupt
++ unregisterInterrupt();
++ */
++
++ /* Value of mcHubRdReqDmifLimit.ENABLE.
++ * 00 - disable dmif rdreq limit
++ * 01 - enable dmif rdreq limit, disable by dmif stall=1||urg!=0
++ * 02 - enable dmif rdreq limit, disable by dmif stall=1
++ * 03 - force enable dmif rdreq limit, ignore dmif stall/urgent
++ * Stella Wong proposed this change. */
++ value = dal_read_reg(mi->ctx, mmMC_HUB_RDREQ_DMIF_LIMIT);
++ if (paths_num > 1)
++ set_reg_field_value(value, 0, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE);
++ else
++ set_reg_field_value(value, 3, MC_HUB_RDREQ_DMIF_LIMIT, ENABLE);
++
++ dal_write_reg(mi->ctx, mmMC_HUB_RDREQ_DMIF_LIMIT, value);
++}
++
++void dce110_program_pix_dur(struct mem_input *mi, uint32_t pix_clk_khz)
++{
++ uint64_t pix_dur;
++ uint32_t addr = mmDMIF_PG0_DPG_PIPE_ARBITRATION_CONTROL1
++ + TO_DCE110_MEM_INPUT(mi)->offsets.dmif;
++ uint32_t value = dal_read_reg(mi->ctx, addr);
++
++ if (pix_clk_khz == 0)
++ return;
++
++ pix_dur = 1000000000 / pix_clk_khz;
++
++ set_reg_field_value(
++ value,
++ pix_dur,
++ DPG_PIPE_ARBITRATION_CONTROL1,
++ PIXEL_DURATION);
++
++ dal_write_reg(mi->ctx, addr, value);
++}
++
++/*****************************************/
++/* Constructor, Destructor */
++/*****************************************/
++
++bool dce110_mem_input_construct(
++ struct dce110_mem_input *mem_input110,
++ struct dc_context *ctx,
++ uint32_t inst)
++{
++ if ((inst < 1) || (inst > ARRAY_SIZE(reg_offsets)))
++ return false;
++
++ mem_input110->base.ctx = ctx;
++
++ mem_input110->base.inst = inst;
++
++ mem_input110->offsets = reg_offsets[inst - 1];
++
++ mem_input110->supported_stutter_mode = 0;
++ dal_adapter_service_get_feature_value(FEATURE_STUTTER_MODE,
++ &(mem_input110->supported_stutter_mode),
++ sizeof(mem_input110->supported_stutter_mode));
++
++ return true;
++}
++
++void dce110_mem_input_destroy(struct mem_input **mem_input)
++{
++ dc_service_free((*mem_input)->ctx, TO_DCE110_MEM_INPUT(*mem_input));
++ *mem_input = NULL;
++}
++
++struct mem_input *dce110_mem_input_create(
++ struct dc_context *ctx,
++ uint32_t inst)
++{
++ struct dce110_mem_input *mem_input110 =
++ dc_service_alloc(ctx, sizeof(struct dce110_mem_input));
++
++ if (!mem_input110)
++ return NULL;
++
++ if (dce110_mem_input_construct(mem_input110,
++ ctx, inst))
++ return &mem_input110->base;
++
++ BREAK_TO_DEBUGGER();
++ dc_service_free(ctx, mem_input110);
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h
+new file mode 100644
+index 0000000..9c6d278
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_mem_input.h
+@@ -0,0 +1,88 @@
++/* Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_MEM_INPUT_DCE110_H__
++#define __DC_MEM_INPUT_DCE110_H__
++
++#include "inc/mem_input.h"
++
++#define TO_DCE110_MEM_INPUT(mi)\
++ container_of(mi, struct dce110_mem_input, base)
++
++struct dce110_mem_input_reg_offsets {
++ uint32_t dcp;
++ uint32_t dmif;
++ uint32_t pipe;
++};
++
++struct dce110_mem_input {
++ struct mem_input base;
++ struct dce110_mem_input_reg_offsets offsets;
++ uint32_t supported_stutter_mode;
++};
++
++struct mem_input *dce110_mem_input_create(
++ struct dc_context *ctx,
++ uint32_t inst);
++
++void dce110_mem_input_destroy(struct mem_input **mem_input);
++
++bool dce110_mem_input_program_surface_flip_and_addr(
++ struct mem_input *mem_input,
++ const struct dc_plane_address *address,
++ bool flip_immediate);
++
++bool dce110_mem_input_program_surface_config(
++ struct mem_input *mem_input,
++ const struct dc_surface *surface);
++
++void dce110_program_nbp_watermark(
++ struct mem_input *mem_input,
++ struct bw_watermarks marks);
++
++void dce110_program_stutter_watermark(
++ struct mem_input *mem_input,
++ struct bw_watermarks marks);
++
++void dce110_program_urgency_watermark(
++ struct mem_input *mem_input,
++ struct bw_watermarks marks,
++ uint32_t h_total,
++ uint32_t pixel_clk_in_khz,
++ uint32_t pstate_blackout_duration_ns);
++
++void dce110_program_safe_display_marks(struct mem_input *mi);
++
++void dce110_allocate_dmif_buffer(
++ struct mem_input *mem_input,
++ struct dc_crtc_timing *timing,
++ uint32_t paths_num);
++
++void dce110_deallocate_dmif_buffer(
++ struct mem_input *mem_input, uint32_t paths_num);
++
++void dce110_program_pix_dur(
++ struct mem_input *mem_input, uint32_t pix_clk_khz);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c
+new file mode 100644
+index 0000000..0fdffac
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.c
+@@ -0,0 +1,296 @@
++/*
++ * 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 "dal_services.h"
++
++/* include DCE11 register header files */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_opp.h"
++
++#define FROM_OPP(opp)\
++ container_of(opp, struct dce110_opp, base)
++
++enum {
++ MAX_LUT_ENTRY = 256,
++ MAX_NUMBER_OF_ENTRIES = 256
++};
++
++static const struct dce110_opp_reg_offsets reg_offsets[] = {
++{
++ .fmt_offset = (mmFMT0_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE0_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++},
++{ .fmt_offset = (mmFMT1_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE1_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++},
++{ .fmt_offset = (mmFMT2_FMT_CONTROL - mmFMT0_FMT_CONTROL),
++ .dcfe_offset = (mmDCFE2_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++}
++};
++
++static void build_evenly_distributed_points(
++ struct gamma_pixel *points,
++ uint32_t numberof_points,
++ struct fixed31_32 max_value,
++ struct fixed31_32 divider1,
++ struct fixed31_32 divider2,
++ struct fixed31_32 divider3)
++{
++ struct gamma_pixel *p = points;
++ struct gamma_pixel *p_last = p + numberof_points - 1;
++
++ uint32_t i = 0;
++
++ do {
++ struct fixed31_32 value = dal_fixed31_32_div_int(
++ dal_fixed31_32_mul_int(max_value, i),
++ numberof_points - 1);
++
++ p->r = value;
++ p->g = value;
++ p->b = value;
++
++ ++p;
++ ++i;
++ } while (i != numberof_points);
++
++ p->r = dal_fixed31_32_div(p_last->r, divider1);
++ p->g = dal_fixed31_32_div(p_last->g, divider1);
++ p->b = dal_fixed31_32_div(p_last->b, divider1);
++
++ ++p;
++
++ p->r = dal_fixed31_32_div(p_last->r, divider2);
++ p->g = dal_fixed31_32_div(p_last->g, divider2);
++ p->b = dal_fixed31_32_div(p_last->b, divider2);
++
++ ++p;
++
++ p->r = dal_fixed31_32_div(p_last->r, divider3);
++ p->g = dal_fixed31_32_div(p_last->g, divider3);
++ p->b = dal_fixed31_32_div(p_last->b, divider3);
++}
++
++/*****************************************/
++/* Constructor, Destructor */
++/*****************************************/
++
++bool dce110_opp_construct(struct dce110_opp *opp110,
++ struct dc_context *ctx,
++ uint32_t inst)
++{
++ if ((inst < 1) || (inst > ARRAY_SIZE(reg_offsets)))
++ return false;
++
++ opp110->base.ctx = ctx;
++
++ opp110->base.inst = inst;
++
++ opp110->offsets = reg_offsets[inst - 1];
++
++ opp110->regamma.hw_points_num = 128;
++ opp110->regamma.coordinates_x = NULL;
++ opp110->regamma.rgb_resulted = NULL;
++ opp110->regamma.rgb_regamma = NULL;
++ opp110->regamma.coeff128 = NULL;
++ opp110->regamma.coeff128_oem = NULL;
++ opp110->regamma.coeff128_dx = NULL;
++ opp110->regamma.axis_x_256 = NULL;
++ opp110->regamma.axis_x_1025 = NULL;
++ opp110->regamma.rgb_oem = NULL;
++ opp110->regamma.rgb_user = NULL;
++ opp110->regamma.extra_points = 3;
++ opp110->regamma.use_half_points = false;
++ opp110->regamma.x_max1 = dal_fixed31_32_one;
++ opp110->regamma.x_max2 = dal_fixed31_32_from_int(2);
++ opp110->regamma.x_min = dal_fixed31_32_zero;
++ opp110->regamma.divider1 = dal_fixed31_32_from_fraction(3, 2);
++ opp110->regamma.divider2 = dal_fixed31_32_from_int(2);
++ opp110->regamma.divider3 = dal_fixed31_32_from_fraction(5, 2);
++
++ opp110->regamma.rgb_user = dc_service_alloc(
++ ctx,
++ sizeof(struct pwl_float_data) *
++ (DX_GAMMA_RAMP_MAX + opp110->regamma.extra_points));
++ if (!opp110->regamma.rgb_user)
++ goto failure_1;
++
++ opp110->regamma.rgb_oem = dc_service_alloc(
++ ctx,
++ sizeof(struct pwl_float_data) *
++ (DX_GAMMA_RAMP_MAX + opp110->regamma.extra_points));
++ if (!opp110->regamma.rgb_oem)
++ goto failure_2;
++
++ opp110->regamma.rgb_resulted = dc_service_alloc(
++ ctx,
++ sizeof(struct pwl_result_data) *
++ (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
++ if (!opp110->regamma.rgb_resulted)
++ goto failure_3;
++
++ opp110->regamma.rgb_regamma = dc_service_alloc(
++ ctx,
++ sizeof(struct pwl_float_data_ex) *
++ (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
++ if (!opp110->regamma.rgb_regamma)
++ goto failure_4;
++
++ opp110->regamma.coordinates_x = dc_service_alloc(
++ ctx,
++ sizeof(struct hw_x_point) *
++ (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
++ if (!opp110->regamma.coordinates_x)
++ goto failure_5;
++
++ opp110->regamma.axis_x_256 = dc_service_alloc(
++ ctx,
++ sizeof(struct gamma_pixel) *
++ (MAX_LUT_ENTRY + opp110->regamma.extra_points));
++ if (!opp110->regamma.axis_x_256)
++ goto failure_6;
++
++ opp110->regamma.axis_x_1025 = dc_service_alloc(
++ ctx,
++ sizeof(struct gamma_pixel) *
++ (DX_GAMMA_RAMP_MAX + opp110->regamma.extra_points));
++ if (!opp110->regamma.axis_x_1025)
++ goto failure_7;
++
++ opp110->regamma.coeff128 = dc_service_alloc(
++ ctx,
++ sizeof(struct pixel_gamma_point) *
++ (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
++ if (!opp110->regamma.coeff128)
++ goto failure_8;
++
++ opp110->regamma.coeff128_oem = dc_service_alloc(
++ ctx,
++ sizeof(struct pixel_gamma_point) *
++ (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
++ if (!opp110->regamma.coeff128_oem)
++ goto failure_9;
++
++ opp110->regamma.coeff128_dx = dc_service_alloc(
++ ctx,
++ sizeof(struct pixel_gamma_point) *
++ (MAX_NUMBER_OF_ENTRIES + opp110->regamma.extra_points));
++ if (!opp110->regamma.coeff128_dx)
++ goto failure_10;
++
++ /* init palette */
++ {
++ uint32_t i = 0;
++
++ do {
++ opp110->regamma.saved_palette[i].red = (uint8_t)i;
++ opp110->regamma.saved_palette[i].green = (uint8_t)i;
++ opp110->regamma.saved_palette[i].blue = (uint8_t)i;
++
++ ++i;
++ } while (i != MAX_LUT_ENTRY);
++ }
++
++ build_evenly_distributed_points(
++ opp110->regamma.axis_x_256,
++ MAX_LUT_ENTRY,
++ opp110->regamma.x_max1,
++ opp110->regamma.divider1,
++ opp110->regamma.divider2,
++ opp110->regamma.divider3);
++
++ build_evenly_distributed_points(
++ opp110->regamma.axis_x_1025,
++ DX_GAMMA_RAMP_MAX,
++ opp110->regamma.x_max1,
++ opp110->regamma.divider1,
++ opp110->regamma.divider2,
++ opp110->regamma.divider3);
++
++ return true;
++
++failure_10:
++ dc_service_free(ctx, opp110->regamma.coeff128_oem);
++failure_9:
++ dc_service_free(ctx, opp110->regamma.coeff128);
++failure_8:
++ dc_service_free(ctx, opp110->regamma.axis_x_1025);
++failure_7:
++ dc_service_free(ctx, opp110->regamma.axis_x_256);
++failure_6:
++ dc_service_free(ctx, opp110->regamma.coordinates_x);
++failure_5:
++ dc_service_free(ctx, opp110->regamma.rgb_regamma);
++failure_4:
++ dc_service_free(ctx, opp110->regamma.rgb_resulted);
++failure_3:
++ dc_service_free(ctx, opp110->regamma.rgb_oem);
++failure_2:
++ dc_service_free(ctx, opp110->regamma.rgb_user);
++failure_1:
++
++ return true;
++}
++
++void dce110_opp_destroy(struct output_pixel_processor **opp)
++{
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.coeff128_dx);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.coeff128_oem);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.coeff128);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.axis_x_1025);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.axis_x_256);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.coordinates_x);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.rgb_regamma);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.rgb_resulted);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.rgb_oem);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp)->regamma.rgb_user);
++ dc_service_free((*opp)->ctx, FROM_OPP(*opp));
++ *opp = NULL;
++}
++
++struct output_pixel_processor *dce110_opp_create(
++ struct dc_context *ctx,
++ uint32_t inst)
++{
++ struct dce110_opp *opp =
++ dc_service_alloc(ctx, sizeof(struct dce110_opp));
++
++ if (!opp)
++ return NULL;
++
++ if (dce110_opp_construct(opp,
++ ctx, inst))
++ return &opp->base;
++
++ BREAK_TO_DEBUGGER();
++ dc_service_free(ctx, opp);
++ return NULL;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h
+new file mode 100644
+index 0000000..71fe624
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp.h
+@@ -0,0 +1,140 @@
++/* Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_OPP_DCE110_H__
++#define __DC_OPP_DCE110_H__
++
++#include "dc_types.h"
++#include "inc/opp.h"
++
++enum dce110_opp_reg_type {
++ DCE110_OPP_REG_DCP = 0,
++ DCE110_OPP_REG_DCFE,
++ DCE110_OPP_REG_FMT,
++
++ DCE110_OPP_REG_MAX
++};
++
++struct dce110_regamma {
++ struct gamma_curve arr_curve_points[16];
++ struct curve_points arr_points[3];
++ uint32_t hw_points_num;
++ struct hw_x_point *coordinates_x;
++ struct pwl_result_data *rgb_resulted;
++
++ /* re-gamma curve */
++ struct pwl_float_data_ex *rgb_regamma;
++ /* coeff used to map user evenly distributed points
++ * to our hardware points (predefined) for gamma 256 */
++ struct pixel_gamma_point *coeff128;
++ struct pixel_gamma_point *coeff128_oem;
++ /* coeff used to map user evenly distributed points
++ * to our hardware points (predefined) for gamma 1025 */
++ struct pixel_gamma_point *coeff128_dx;
++ /* evenly distributed points, gamma 256 software points 0-255 */
++ struct gamma_pixel *axis_x_256;
++ /* evenly distributed points, gamma 1025 software points 0-1025 */
++ struct gamma_pixel *axis_x_1025;
++ /* OEM supplied gamma for regamma LUT */
++ struct pwl_float_data *rgb_oem;
++ /* user supplied gamma */
++ struct pwl_float_data *rgb_user;
++ struct dev_c_lut saved_palette[RGB_256X3X16];
++ uint32_t extra_points;
++ bool use_half_points;
++ struct fixed31_32 x_max1;
++ struct fixed31_32 x_max2;
++ struct fixed31_32 x_min;
++ struct fixed31_32 divider1;
++ struct fixed31_32 divider2;
++ struct fixed31_32 divider3;
++};
++
++/* OPP RELATED */
++#define TO_DCE110_OPP(opp)\
++ container_of(opp, struct dce110_opp, base)
++
++struct dce110_opp_reg_offsets {
++ uint32_t fmt_offset;
++ uint32_t dcp_offset;
++ uint32_t dcfe_offset;
++};
++
++struct dce110_opp {
++ struct output_pixel_processor base;
++ struct dce110_opp_reg_offsets offsets;
++ struct dce110_regamma regamma;
++};
++
++bool dce110_opp_construct(struct dce110_opp *opp110,
++ struct dc_context *ctx,
++ uint32_t inst);
++
++void dce110_opp_destroy(struct output_pixel_processor **opp);
++
++struct output_pixel_processor *dce110_opp_create(
++ struct dc_context *ctx,
++ uint32_t inst);
++
++/* REGAMMA RELATED */
++void dce110_opp_power_on_regamma_lut(
++ struct output_pixel_processor *opp,
++ bool power_on);
++
++bool dce110_opp_set_regamma(
++ struct output_pixel_processor *opp,
++ const struct gamma_ramp *ramp,
++ const struct gamma_parameters *params,
++ bool force_bypass);
++
++bool dce110_opp_map_legacy_and_regamma_hw_to_x_user(
++ struct output_pixel_processor *opp,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params);
++
++void dce110_opp_set_csc_adjustment(
++ struct output_pixel_processor *opp,
++ const struct grph_csc_adjustment *adjust);
++
++void dce110_opp_set_csc_default(
++ struct output_pixel_processor *opp,
++ const struct default_adjustment *default_adjust);
++
++/* FORMATTER RELATED */
++void dce110_opp_program_bit_depth_reduction(
++ struct output_pixel_processor *opp,
++ const struct bit_depth_reduction_params *params);
++
++void dce110_opp_program_clamping_and_pixel_encoding(
++ struct output_pixel_processor *opp,
++ const struct clamping_and_pixel_encoding_params *params);
++
++
++void dce110_opp_set_dyn_expansion(
++ struct output_pixel_processor *opp,
++ enum color_space color_sp,
++ enum dc_color_depth color_dpth,
++ enum signal_type signal);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c
+new file mode 100644
+index 0000000..91430c0
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_csc.c
+@@ -0,0 +1,904 @@
++/*
++ * 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 "dal_services.h"
++#include "dce110_opp.h"
++#include "basics/conversion.h"
++
++/* include DCE11 register header files */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#define DCP_REG(reg)\
++ (reg + opp110->offsets.dcp_offset)
++
++enum {
++ OUTPUT_CSC_MATRIX_SIZE = 12
++};
++
++struct out_csc_color_matrix {
++ enum color_space color_space;
++ uint16_t regval[OUTPUT_CSC_MATRIX_SIZE];
++};
++
++static const struct out_csc_color_matrix global_color_matrix[] = {
++{ COLOR_SPACE_SRGB_FULL_RANGE,
++ { 0x2000, 0, 0, 0, 0, 0x2000, 0, 0, 0, 0, 0x2000, 0} },
++{ COLOR_SPACE_SRGB_LIMITED_RANGE,
++ { 0x1B60, 0, 0, 0x200, 0, 0x1B60, 0, 0x200, 0, 0, 0x1B60, 0x200} },
++{ COLOR_SPACE_YCBCR601,
++ { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x82F, 0x1012, 0x31F, 0x200, 0xFB47,
++ 0xF6B9, 0xE00, 0x1000} },
++{ COLOR_SPACE_YCBCR709, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x5D2, 0x1394, 0x1FA,
++ 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} },
++/* YOnly same as YCbCr709 but Y in Full range -To do. */
++{ COLOR_SPACE_YCBCR601_YONLY, { 0xE00, 0xF447, 0xFDB9, 0x1000, 0x991,
++ 0x12C9, 0x3A6, 0x200, 0xFB47, 0xF6B9, 0xE00, 0x1000} },
++{ COLOR_SPACE_YCBCR709_YONLY, { 0xE00, 0xF349, 0xFEB7, 0x1000, 0x6CE, 0x16E3,
++ 0x24F, 0x200, 0xFCCB, 0xF535, 0xE00, 0x1000} }
++};
++
++enum csc_color_mode {
++ /* 00 - BITS2:0 Bypass */
++ CSC_COLOR_MODE_GRAPHICS_BYPASS,
++ /* 01 - hard coded coefficient TV RGB */
++ CSC_COLOR_MODE_GRAPHICS_PREDEFINED,
++ /* 04 - programmable OUTPUT CSC coefficient */
++ CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC,
++};
++
++static void program_color_matrix(
++ struct dce110_opp *opp110,
++ const struct out_csc_color_matrix *tbl_entry,
++ enum grph_color_adjust_option options)
++{
++ struct dc_context *ctx = opp110->base.ctx;
++ {
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C11_C12);
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[0],
++ OUTPUT_CSC_C11_C12,
++ OUTPUT_CSC_C11);
++
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[1],
++ OUTPUT_CSC_C11_C12,
++ OUTPUT_CSC_C12);
++
++ dal_write_reg(ctx, addr, value);
++ }
++ {
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C13_C14);
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[2],
++ OUTPUT_CSC_C13_C14,
++ OUTPUT_CSC_C13);
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[3],
++ OUTPUT_CSC_C13_C14,
++ OUTPUT_CSC_C14);
++
++ dal_write_reg(ctx, addr, value);
++ }
++ {
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C21_C22);
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[4],
++ OUTPUT_CSC_C21_C22,
++ OUTPUT_CSC_C21);
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[5],
++ OUTPUT_CSC_C21_C22,
++ OUTPUT_CSC_C22);
++
++ dal_write_reg(ctx, addr, value);
++ }
++ {
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C23_C24);
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[6],
++ OUTPUT_CSC_C23_C24,
++ OUTPUT_CSC_C23);
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[7],
++ OUTPUT_CSC_C23_C24,
++ OUTPUT_CSC_C24);
++
++ dal_write_reg(ctx, addr, value);
++ }
++ {
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C31_C32);
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[8],
++ OUTPUT_CSC_C31_C32,
++ OUTPUT_CSC_C31);
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[9],
++ OUTPUT_CSC_C31_C32,
++ OUTPUT_CSC_C32);
++
++ dal_write_reg(ctx, addr, value);
++ }
++ {
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmOUTPUT_CSC_C33_C34);
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[10],
++ OUTPUT_CSC_C33_C34,
++ OUTPUT_CSC_C33);
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ value,
++ tbl_entry->regval[11],
++ OUTPUT_CSC_C33_C34,
++ OUTPUT_CSC_C34);
++
++ dal_write_reg(ctx, addr, value);
++ }
++}
++
++/*
++ * initialize_color_float_adj_reference_values
++ * This initialize display color adjust input from API to HW range for later
++ * calculation use. This is shared by all the display color adjustment.
++ * @param :
++ * @return None
++ */
++static void initialize_color_float_adj_reference_values(
++ const struct grph_csc_adjustment *adjust,
++ struct fixed31_32 *grph_cont,
++ struct fixed31_32 *grph_sat,
++ struct fixed31_32 *grph_bright,
++ struct fixed31_32 *sin_grph_hue,
++ struct fixed31_32 *cos_grph_hue)
++{
++ /* Hue adjustment could be negative. -45 ~ +45 */
++ struct fixed31_32 hue =
++ dal_fixed31_32_mul(
++ dal_fixed31_32_from_fraction(adjust->grph_hue, 180),
++ dal_fixed31_32_pi);
++
++ *sin_grph_hue = dal_fixed31_32_sin(hue);
++ *cos_grph_hue = dal_fixed31_32_cos(hue);
++
++ if (adjust->adjust_divider) {
++ *grph_cont =
++ dal_fixed31_32_from_fraction(
++ adjust->grph_cont,
++ adjust->adjust_divider);
++ *grph_sat =
++ dal_fixed31_32_from_fraction(
++ adjust->grph_sat,
++ adjust->adjust_divider);
++ *grph_bright =
++ dal_fixed31_32_from_fraction(
++ adjust->grph_bright,
++ adjust->adjust_divider);
++ } else {
++ *grph_cont = dal_fixed31_32_from_int(adjust->grph_cont);
++ *grph_sat = dal_fixed31_32_from_int(adjust->grph_sat);
++ *grph_bright = dal_fixed31_32_from_int(adjust->grph_bright);
++ }
++}
++
++static inline struct fixed31_32 fixed31_32_clamp(
++ struct fixed31_32 value,
++ int32_t min_numerator,
++ int32_t max_numerator,
++ int32_t denominator)
++{
++ return dal_fixed31_32_clamp(
++ value,
++ dal_fixed31_32_from_fraction(
++ min_numerator,
++ denominator),
++ dal_fixed31_32_from_fraction(
++ max_numerator,
++ denominator));
++}
++
++static void setup_reg_format(
++ struct fixed31_32 *coefficients,
++ uint16_t *reg_values)
++{
++ enum {
++ LENGTH = 12,
++ DENOMINATOR = 10000
++ };
++
++ static const int32_t min_numerator[] = {
++ -3 * DENOMINATOR,
++ -DENOMINATOR
++ };
++
++ static const int32_t max_numerator[] = {
++ DENOMINATOR,
++ DENOMINATOR
++ };
++
++ static const uint8_t integer_bits[] = { 2, 0 };
++
++ uint32_t i = 0;
++
++ do {
++ const uint32_t index = (i % 4) == 3;
++
++ reg_values[i] = fixed_point_to_int_frac(
++ fixed31_32_clamp(coefficients[(i + 8) % LENGTH],
++ min_numerator[index],
++ max_numerator[index],
++ DENOMINATOR),
++ integer_bits[index], 13);
++
++ ++i;
++ } while (i != LENGTH);
++}
++
++/**
++ *****************************************************************************
++ * Function: setup_adjustments
++ * @note prepare to setup the values
++ *
++ * @see
++ *
++ *****************************************************************************
++ */
++static void setup_adjustments(const struct grph_csc_adjustment *adjust,
++ struct dc_csc_adjustments *adjustments)
++{
++ if (adjust->adjust_divider != 0) {
++ adjustments->brightness =
++ dal_fixed31_32_from_fraction(adjust->grph_bright,
++ adjust->adjust_divider);
++ adjustments->contrast =
++ dal_fixed31_32_from_fraction(adjust->grph_cont,
++ adjust->adjust_divider);
++ adjustments->saturation =
++ dal_fixed31_32_from_fraction(adjust->grph_sat,
++ adjust->adjust_divider);
++ } else {
++ adjustments->brightness =
++ dal_fixed31_32_from_fraction(adjust->grph_bright, 1);
++ adjustments->contrast =
++ dal_fixed31_32_from_fraction(adjust->grph_cont, 1);
++ adjustments->saturation =
++ dal_fixed31_32_from_fraction(adjust->grph_sat, 1);
++ }
++
++ /* convert degrees into radians */
++ adjustments->hue =
++ dal_fixed31_32_mul(
++ dal_fixed31_32_from_fraction(adjust->grph_hue, 180),
++ dal_fixed31_32_pi);
++}
++
++static void prepare_tv_rgb_ideal(
++ struct fixed31_32 *matrix)
++{
++ static const int32_t matrix_[] = {
++ 85546875, 0, 0, 6250000,
++ 0, 85546875, 0, 6250000,
++ 0, 0, 85546875, 6250000
++ };
++
++ uint32_t i = 0;
++
++ do {
++ matrix[i] = dal_fixed31_32_from_fraction(
++ matrix_[i],
++ 100000000);
++ ++i;
++ } while (i != ARRAY_SIZE(matrix_));
++}
++
++/**
++ *****************************************************************************
++ * Function: dal_transform_wide_gamut_set_rgb_adjustment_legacy
++ *
++ * @param [in] const struct grph_csc_adjustment *adjust
++ *
++ * @return
++ * void
++ *
++ * @note calculate and program color adjustments for sRGB color space
++ *
++ * @see
++ *
++ *****************************************************************************
++ */
++static void set_rgb_adjustment_legacy(
++ struct dce110_opp *opp110,
++ const struct grph_csc_adjustment *adjust)
++{
++ const struct fixed31_32 k1 =
++ dal_fixed31_32_from_fraction(701000, 1000000);
++ const struct fixed31_32 k2 =
++ dal_fixed31_32_from_fraction(236568, 1000000);
++ const struct fixed31_32 k3 =
++ dal_fixed31_32_from_fraction(-587000, 1000000);
++ const struct fixed31_32 k4 =
++ dal_fixed31_32_from_fraction(464432, 1000000);
++ const struct fixed31_32 k5 =
++ dal_fixed31_32_from_fraction(-114000, 1000000);
++ const struct fixed31_32 k6 =
++ dal_fixed31_32_from_fraction(-701000, 1000000);
++ const struct fixed31_32 k7 =
++ dal_fixed31_32_from_fraction(-299000, 1000000);
++ const struct fixed31_32 k8 =
++ dal_fixed31_32_from_fraction(-292569, 1000000);
++ const struct fixed31_32 k9 =
++ dal_fixed31_32_from_fraction(413000, 1000000);
++ const struct fixed31_32 k10 =
++ dal_fixed31_32_from_fraction(-92482, 1000000);
++ const struct fixed31_32 k11 =
++ dal_fixed31_32_from_fraction(-114000, 1000000);
++ const struct fixed31_32 k12 =
++ dal_fixed31_32_from_fraction(385051, 1000000);
++ const struct fixed31_32 k13 =
++ dal_fixed31_32_from_fraction(-299000, 1000000);
++ const struct fixed31_32 k14 =
++ dal_fixed31_32_from_fraction(886000, 1000000);
++ const struct fixed31_32 k15 =
++ dal_fixed31_32_from_fraction(-587000, 1000000);
++ const struct fixed31_32 k16 =
++ dal_fixed31_32_from_fraction(-741914, 1000000);
++ const struct fixed31_32 k17 =
++ dal_fixed31_32_from_fraction(886000, 1000000);
++ const struct fixed31_32 k18 =
++ dal_fixed31_32_from_fraction(-144086, 1000000);
++
++ const struct fixed31_32 luma_r =
++ dal_fixed31_32_from_fraction(299, 1000);
++ const struct fixed31_32 luma_g =
++ dal_fixed31_32_from_fraction(587, 1000);
++ const struct fixed31_32 luma_b =
++ dal_fixed31_32_from_fraction(114, 1000);
++
++ struct out_csc_color_matrix tbl_entry;
++ struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE];
++
++ struct fixed31_32 grph_cont;
++ struct fixed31_32 grph_sat;
++ struct fixed31_32 grph_bright;
++ struct fixed31_32 sin_grph_hue;
++ struct fixed31_32 cos_grph_hue;
++
++ initialize_color_float_adj_reference_values(
++ adjust, &grph_cont, &grph_sat,
++ &grph_bright, &sin_grph_hue, &cos_grph_hue);
++
++ /* COEF_1_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K1 +
++ * Sin(GrphHue) * K2)) */
++ /* (Cos(GrphHue) * K1 + Sin(GrphHue) * K2) */
++ matrix[0] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k1),
++ dal_fixed31_32_mul(sin_grph_hue, k2));
++ /* GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * K2 */
++ matrix[0] = dal_fixed31_32_mul(grph_sat, matrix[0]);
++ /* (LumaR + GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) * K2)) */
++ matrix[0] = dal_fixed31_32_add(luma_r, matrix[0]);
++ /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K1 + Sin(GrphHue) *
++ * K2)) */
++ matrix[0] = dal_fixed31_32_mul(grph_cont, matrix[0]);
++
++ /* COEF_1_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K3 +
++ * Sin(GrphHue) * K4)) */
++ /* (Cos(GrphHue) * K3 + Sin(GrphHue) * K4) */
++ matrix[1] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k3),
++ dal_fixed31_32_mul(sin_grph_hue, k4));
++ /* GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * K4) */
++ matrix[1] = dal_fixed31_32_mul(grph_sat, matrix[1]);
++ /* (LumaG + GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) * K4)) */
++ matrix[1] = dal_fixed31_32_add(luma_g, matrix[1]);
++ /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K3 + Sin(GrphHue) *
++ * K4)) */
++ matrix[1] = dal_fixed31_32_mul(grph_cont, matrix[1]);
++
++ /* COEF_1_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K5 +
++ * Sin(GrphHue) * K6)) */
++ /* (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */
++ matrix[2] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k5),
++ dal_fixed31_32_mul(sin_grph_hue, k6));
++ /* GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */
++ matrix[2] = dal_fixed31_32_mul(grph_sat, matrix[2]);
++ /* LumaB + GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) * K6) */
++ matrix[2] = dal_fixed31_32_add(luma_b, matrix[2]);
++ /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K5 + Sin(GrphHue) *
++ * K6)) */
++ matrix[2] = dal_fixed31_32_mul(grph_cont, matrix[2]);
++
++ /* COEF_1_4 = GrphBright */
++ matrix[3] = grph_bright;
++
++ /* COEF_2_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K7 +
++ * Sin(GrphHue) * K8)) */
++ /* (Cos(GrphHue) * K7 + Sin(GrphHue) * K8) */
++ matrix[4] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k7),
++ dal_fixed31_32_mul(sin_grph_hue, k8));
++ /* GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * K8) */
++ matrix[4] = dal_fixed31_32_mul(grph_sat, matrix[4]);
++ /* (LumaR + GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) * K8)) */
++ matrix[4] = dal_fixed31_32_add(luma_r, matrix[4]);
++ /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K7 + Sin(GrphHue) *
++ * K8)) */
++ matrix[4] = dal_fixed31_32_mul(grph_cont, matrix[4]);
++
++ /* COEF_2_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K9 +
++ * Sin(GrphHue) * K10)) */
++ /* (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */
++ matrix[5] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k9),
++ dal_fixed31_32_mul(sin_grph_hue, k10));
++ /* GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */
++ matrix[5] = dal_fixed31_32_mul(grph_sat, matrix[5]);
++ /* (LumaG + GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) * K10)) */
++ matrix[5] = dal_fixed31_32_add(luma_g, matrix[5]);
++ /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K9 + Sin(GrphHue) *
++ * K10)) */
++ matrix[5] = dal_fixed31_32_mul(grph_cont, matrix[5]);
++
++ /* COEF_2_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K11 +
++ * Sin(GrphHue) * K12)) */
++ /* (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */
++ matrix[6] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k11),
++ dal_fixed31_32_mul(sin_grph_hue, k12));
++ /* GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */
++ matrix[6] = dal_fixed31_32_mul(grph_sat, matrix[6]);
++ /* (LumaB + GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) * K12)) */
++ matrix[6] = dal_fixed31_32_add(luma_b, matrix[6]);
++ /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K11 + Sin(GrphHue) *
++ * K12)) */
++ matrix[6] = dal_fixed31_32_mul(grph_cont, matrix[6]);
++
++ /* COEF_2_4 = GrphBright */
++ matrix[7] = grph_bright;
++
++ /* COEF_3_1 = GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K13 +
++ * Sin(GrphHue) * K14)) */
++ /* (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
++ matrix[8] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k13),
++ dal_fixed31_32_mul(sin_grph_hue, k14));
++ /* GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
++ matrix[8] = dal_fixed31_32_mul(grph_sat, matrix[8]);
++ /* (LumaR + GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) * K14)) */
++ matrix[8] = dal_fixed31_32_add(luma_r, matrix[8]);
++ /* GrphCont * (LumaR + GrphSat * (Cos(GrphHue) * K13 + Sin(GrphHue) *
++ * K14)) */
++ matrix[8] = dal_fixed31_32_mul(grph_cont, matrix[8]);
++
++ /* COEF_3_2 = GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K15 +
++ * Sin(GrphHue) * K16)) */
++ /* GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16) */
++ matrix[9] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k15),
++ dal_fixed31_32_mul(sin_grph_hue, k16));
++ /* (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16)) */
++ matrix[9] = dal_fixed31_32_mul(grph_sat, matrix[9]);
++ /* (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) * K16)) */
++ matrix[9] = dal_fixed31_32_add(luma_g, matrix[9]);
++ /* GrphCont * (LumaG + GrphSat * (Cos(GrphHue) * K15 + Sin(GrphHue) *
++ * K16)) */
++ matrix[9] = dal_fixed31_32_mul(grph_cont, matrix[9]);
++
++ /* COEF_3_3 = GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K17 +
++ * Sin(GrphHue) * K18)) */
++ /* (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
++ matrix[10] =
++ dal_fixed31_32_add(
++ dal_fixed31_32_mul(cos_grph_hue, k17),
++ dal_fixed31_32_mul(sin_grph_hue, k18));
++ /* GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
++ matrix[10] = dal_fixed31_32_mul(grph_sat, matrix[10]);
++ /* (LumaB + GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) * K18)) */
++ matrix[10] = dal_fixed31_32_add(luma_b, matrix[10]);
++ /* GrphCont * (LumaB + GrphSat * (Cos(GrphHue) * K17 + Sin(GrphHue) *
++ * K18)) */
++ matrix[10] = dal_fixed31_32_mul(grph_cont, matrix[10]);
++
++ /* COEF_3_4 = GrphBright */
++ matrix[11] = grph_bright;
++
++ tbl_entry.color_space = adjust->c_space;
++
++ convert_float_matrix(tbl_entry.regval, matrix, OUTPUT_CSC_MATRIX_SIZE);
++
++ program_color_matrix(
++ opp110, &tbl_entry, adjust->color_adjust_option);
++}
++
++/**
++ *****************************************************************************
++ * Function: dal_transform_wide_gamut_set_rgb_limited_range_adjustment
++ *
++ * @param [in] const struct grph_csc_adjustment *adjust
++ *
++ * @return
++ * void
++ *
++ * @note calculate and program color adjustments for sRGB limited color space
++ *
++ * @see
++ *
++ *****************************************************************************
++ */
++static void set_rgb_limited_range_adjustment(
++ struct dce110_opp *opp110,
++ const struct grph_csc_adjustment *adjust)
++{
++ struct out_csc_color_matrix reg_matrix;
++ struct fixed31_32 change_matrix[OUTPUT_CSC_MATRIX_SIZE];
++ struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE];
++ struct dc_csc_adjustments adjustments;
++ struct fixed31_32 ideals[OUTPUT_CSC_MATRIX_SIZE];
++
++ prepare_tv_rgb_ideal(ideals);
++
++ setup_adjustments(adjust, &adjustments);
++
++ calculate_adjustments(ideals, &adjustments, matrix);
++
++ dc_service_memmove(change_matrix, matrix, sizeof(matrix));
++
++ /* from 1 -> 3 */
++ matrix[8] = change_matrix[0];
++ matrix[9] = change_matrix[1];
++ matrix[10] = change_matrix[2];
++ matrix[11] = change_matrix[3];
++
++ /* from 2 -> 1 */
++ matrix[0] = change_matrix[4];
++ matrix[1] = change_matrix[5];
++ matrix[2] = change_matrix[6];
++ matrix[3] = change_matrix[7];
++
++ /* from 3 -> 2 */
++ matrix[4] = change_matrix[8];
++ matrix[5] = change_matrix[9];
++ matrix[6] = change_matrix[10];
++ matrix[7] = change_matrix[11];
++
++ dc_service_memset(&reg_matrix, 0, sizeof(struct out_csc_color_matrix));
++
++ setup_reg_format(matrix, reg_matrix.regval);
++
++ program_color_matrix(opp110, &reg_matrix, GRPH_COLOR_MATRIX_SW);
++}
++
++static void prepare_yuv_ideal(
++ bool b601,
++ struct fixed31_32 *matrix)
++{
++ static const int32_t matrix_1[] = {
++ 25578516, 50216016, 9752344, 6250000,
++ -14764391, -28985609, 43750000, 50000000,
++ 43750000, -36635164, -7114836, 50000000
++ };
++
++ static const int32_t matrix_2[] = {
++ 18187266, 61183125, 6176484, 6250000,
++ -10025059, -33724941, 43750000, 50000000,
++ 43750000, -39738379, -4011621, 50000000
++ };
++
++ const int32_t *matrix_x = b601 ? matrix_1 : matrix_2;
++
++ uint32_t i = 0;
++
++ do {
++ matrix[i] = dal_fixed31_32_from_fraction(
++ matrix_x[i],
++ 100000000);
++ ++i;
++ } while (i != ARRAY_SIZE(matrix_1));
++}
++
++/**
++ *****************************************************************************
++ * Function: dal_transform_wide_gamut_set_yuv_adjustment
++ *
++ * @param [in] const struct grph_csc_adjustment *adjust
++ *
++ * @return
++ * void
++ *
++ * @note calculate and program color adjustments for YUV color spaces
++ *
++ * @see
++ *
++ *****************************************************************************
++ */
++static void set_yuv_adjustment(
++ struct dce110_opp *opp110,
++ const struct grph_csc_adjustment *adjust)
++{
++ bool b601 = (adjust->c_space == COLOR_SPACE_YPBPR601) ||
++ (adjust->c_space == COLOR_SPACE_YCBCR601) ||
++ (adjust->c_space == COLOR_SPACE_YCBCR601_YONLY);
++ struct out_csc_color_matrix reg_matrix;
++ struct fixed31_32 matrix[OUTPUT_CSC_MATRIX_SIZE];
++ struct dc_csc_adjustments adjustments;
++ struct fixed31_32 ideals[OUTPUT_CSC_MATRIX_SIZE];
++
++ prepare_yuv_ideal(b601, ideals);
++
++ setup_adjustments(adjust, &adjustments);
++
++ if ((adjust->c_space == COLOR_SPACE_YCBCR601_YONLY) ||
++ (adjust->c_space == COLOR_SPACE_YCBCR709_YONLY))
++ calculate_adjustments_y_only(
++ ideals, &adjustments, matrix);
++ else
++ calculate_adjustments(
++ ideals, &adjustments, matrix);
++
++ dc_service_memset(&reg_matrix, 0, sizeof(struct out_csc_color_matrix));
++
++ setup_reg_format(matrix, reg_matrix.regval);
++
++ program_color_matrix(opp110, &reg_matrix, GRPH_COLOR_MATRIX_SW);
++}
++
++static bool configure_graphics_mode(
++ struct dce110_opp *opp110,
++ enum csc_color_mode config,
++ enum graphics_csc_adjust_type csc_adjust_type,
++ enum color_space color_space)
++{
++ struct dc_context *ctx = opp110->base.ctx;
++ uint32_t addr = DCP_REG(mmOUTPUT_CSC_CONTROL);
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++
++ if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_SW) {
++ if (config == CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC) {
++ set_reg_field_value(
++ value,
++ 4,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ } else {
++
++ switch (color_space) {
++ case COLOR_SPACE_SRGB_FULL_RANGE:
++ /* by pass */
++ set_reg_field_value(
++ value,
++ 0,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ break;
++ case COLOR_SPACE_SRGB_LIMITED_RANGE:
++ /* TV RGB */
++ set_reg_field_value(
++ value,
++ 1,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ break;
++ case COLOR_SPACE_YCBCR601:
++ case COLOR_SPACE_YPBPR601:
++ case COLOR_SPACE_YCBCR601_YONLY:
++ /* YCbCr601 */
++ set_reg_field_value(
++ value,
++ 2,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ break;
++ case COLOR_SPACE_YCBCR709:
++ case COLOR_SPACE_YPBPR709:
++ case COLOR_SPACE_YCBCR709_YONLY:
++ /* YCbCr709 */
++ set_reg_field_value(
++ value,
++ 3,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ break;
++ default:
++ return false;
++ }
++ }
++ } else if (csc_adjust_type == GRAPHICS_CSC_ADJUST_TYPE_HW) {
++ switch (color_space) {
++ case COLOR_SPACE_SRGB_FULL_RANGE:
++ /* by pass */
++ set_reg_field_value(
++ value,
++ 0,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ break;
++ case COLOR_SPACE_SRGB_LIMITED_RANGE:
++ /* TV RGB */
++ set_reg_field_value(
++ value,
++ 1,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ break;
++ case COLOR_SPACE_YCBCR601:
++ case COLOR_SPACE_YPBPR601:
++ case COLOR_SPACE_YCBCR601_YONLY:
++ /* YCbCr601 */
++ set_reg_field_value(
++ value,
++ 2,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ break;
++ case COLOR_SPACE_YCBCR709:
++ case COLOR_SPACE_YPBPR709:
++ case COLOR_SPACE_YCBCR709_YONLY:
++ /* YCbCr709 */
++ set_reg_field_value(
++ value,
++ 3,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++ break;
++ default:
++ return false;
++ }
++
++ } else
++ /* by pass */
++ set_reg_field_value(
++ value,
++ 0,
++ OUTPUT_CSC_CONTROL,
++ OUTPUT_CSC_GRPH_MODE);
++
++ addr = DCP_REG(mmOUTPUT_CSC_CONTROL);
++ dal_write_reg(ctx, addr, value);
++
++ return true;
++}
++
++void dce110_opp_set_csc_adjustment(
++ struct output_pixel_processor *opp,
++ const struct grph_csc_adjustment *adjust)
++{
++ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
++ enum csc_color_mode config =
++ CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
++
++ /* Apply color adjustments: brightness, saturation, hue, contrast and
++ * CSC. No need for different color space routine, color space defines
++ * the ideal values only, but keep original design to allow quick switch
++ * to the old legacy routines */
++ switch (adjust->c_space) {
++ case COLOR_SPACE_SRGB_FULL_RANGE:
++ set_rgb_adjustment_legacy(opp110, adjust);
++ break;
++ case COLOR_SPACE_SRGB_LIMITED_RANGE:
++ set_rgb_limited_range_adjustment(
++ opp110, adjust);
++ break;
++ case COLOR_SPACE_YCBCR601:
++ case COLOR_SPACE_YCBCR709:
++ case COLOR_SPACE_YCBCR601_YONLY:
++ case COLOR_SPACE_YCBCR709_YONLY:
++ case COLOR_SPACE_YPBPR601:
++ case COLOR_SPACE_YPBPR709:
++ set_yuv_adjustment(opp110, adjust);
++ break;
++ default:
++ set_rgb_adjustment_legacy(opp110, adjust);
++ break;
++ }
++
++ /* We did everything ,now program DxOUTPUT_CSC_CONTROL */
++ configure_graphics_mode(opp110, config, adjust->csc_adjust_type,
++ adjust->c_space);
++}
++
++void dce110_opp_set_csc_default(
++ struct output_pixel_processor *opp,
++ const struct default_adjustment *default_adjust)
++{
++ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
++ enum csc_color_mode config =
++ CSC_COLOR_MODE_GRAPHICS_PREDEFINED;
++
++ if (default_adjust->force_hw_default == false) {
++ const struct out_csc_color_matrix *elm;
++ /* currently parameter not in use */
++ enum grph_color_adjust_option option =
++ GRPH_COLOR_MATRIX_HW_DEFAULT;
++ uint32_t i;
++ /*
++ * HW default false we program locally defined matrix
++ * HW default true we use predefined hw matrix and we
++ * do not need to program matrix
++ * OEM wants the HW default via runtime parameter.
++ */
++ option = GRPH_COLOR_MATRIX_SW;
++
++ for (i = 0; i < ARRAY_SIZE(global_color_matrix); ++i) {
++ elm = &global_color_matrix[i];
++ if (elm->color_space != default_adjust->color_space)
++ continue;
++ /* program the matrix with default values from this
++ * file */
++ program_color_matrix(opp110, elm, option);
++ config = CSC_COLOR_MODE_GRAPHICS_OUTPUT_CSC;
++ break;
++ }
++ }
++
++ /* configure the what we programmed :
++ * 1. Default values from this file
++ * 2. Use hardware default from ROM_A and we do not need to program
++ * matrix */
++
++ configure_graphics_mode(opp110, config,
++ default_adjust->csc_adjust_type,
++ default_adjust->color_space);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_formatter.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_formatter.c
+new file mode 100644
+index 0000000..fdf87bd
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_formatter.c
+@@ -0,0 +1,610 @@
++/*
++ * 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 "dal_services.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_opp.h"
++
++#define FMT_REG(reg)\
++ (reg + opp110->offsets.fmt_offset)
++
++/**
++ * set_truncation
++ * 1) set truncation depth: 0 for 18 bpp or 1 for 24 bpp
++ * 2) enable truncation
++ * 3) HW remove 12bit FMT support for DCE11 power saving reason.
++ */
++static void set_truncation(
++ struct dce110_opp *opp110,
++ const struct bit_depth_reduction_params *params)
++{
++ uint32_t value = 0;
++ uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
++
++ /*Disable truncation*/
++ value = dal_read_reg(opp110->base.ctx, addr);
++ set_reg_field_value(value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN);
++ set_reg_field_value(value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH);
++ set_reg_field_value(value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_MODE);
++
++ dal_write_reg(opp110->base.ctx, addr, value);
++
++ /* no 10bpc trunc on DCE11*/
++ if (params->flags.TRUNCATE_ENABLED == 0 ||
++ params->flags.TRUNCATE_DEPTH == 2)
++ return;
++
++ /*Set truncation depth and Enable truncation*/
++ set_reg_field_value(value, 1,
++ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_EN);
++ set_reg_field_value(value, params->flags.TRUNCATE_MODE,
++ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_MODE);
++ set_reg_field_value(value, params->flags.TRUNCATE_DEPTH,
++ FMT_BIT_DEPTH_CONTROL, FMT_TRUNCATE_DEPTH);
++
++ dal_write_reg(opp110->base.ctx, addr, value);
++
++}
++
++/**
++ * set_spatial_dither
++ * 1) set spatial dithering mode: pattern of seed
++ * 2) set spatical dithering depth: 0 for 18bpp or 1 for 24bpp
++ * 3) set random seed
++ * 4) set random mode
++ * lfsr is reset every frame or not reset
++ * RGB dithering method
++ * 0: RGB data are all dithered with x^28+x^3+1
++ * 1: R data is dithered with x^28+x^3+1
++ * G data is dithered with x^28+X^9+1
++ * B data is dithered with x^28+x^13+1
++ * enable high pass filter or not
++ * 5) enable spatical dithering
++ */
++static void set_spatial_dither(
++ struct dce110_opp *opp110,
++ const struct bit_depth_reduction_params *params)
++{
++ uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
++ uint32_t depth_cntl_value = 0;
++ uint32_t fmt_cntl_value = 0;
++ uint32_t dither_r_value = 0;
++ uint32_t dither_g_value = 0;
++ uint32_t dither_b_value = 0;
++
++ /*Disable spatial (random) dithering*/
++ depth_cntl_value = dal_read_reg(opp110->base.ctx, addr);
++ set_reg_field_value(depth_cntl_value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_EN);
++ set_reg_field_value(depth_cntl_value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_MODE);
++ set_reg_field_value(depth_cntl_value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_SPATIAL_DITHER_DEPTH);
++ set_reg_field_value(depth_cntl_value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_TEMPORAL_DITHER_EN);
++ set_reg_field_value(depth_cntl_value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_HIGHPASS_RANDOM_ENABLE);
++ set_reg_field_value(depth_cntl_value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_FRAME_RANDOM_ENABLE);
++ set_reg_field_value(depth_cntl_value, 0,
++ FMT_BIT_DEPTH_CONTROL, FMT_RGB_RANDOM_ENABLE);
++
++ dal_write_reg(opp110->base.ctx, addr, depth_cntl_value);
++
++ /* no 10bpc on DCE11*/
++ if (params->flags.SPATIAL_DITHER_ENABLED == 0 ||
++ params->flags.SPATIAL_DITHER_DEPTH == 2)
++ return;
++
++ addr = FMT_REG(mmFMT_CONTROL);
++ fmt_cntl_value = dal_read_reg(opp110->base.ctx, addr);
++ /* only use FRAME_COUNTER_MAX if frameRandom == 1*/
++ if (params->flags.FRAME_RANDOM == 1) {
++ if (params->flags.SPATIAL_DITHER_DEPTH == 0 ||
++ params->flags.SPATIAL_DITHER_DEPTH == 1) {
++ set_reg_field_value(fmt_cntl_value, 15,
++ FMT_CONTROL,
++ FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX);
++ set_reg_field_value(fmt_cntl_value, 2,
++ FMT_CONTROL,
++ FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP);
++ } else if (params->flags.SPATIAL_DITHER_DEPTH == 2) {
++ set_reg_field_value(fmt_cntl_value, 3,
++ FMT_CONTROL,
++ FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX);
++ set_reg_field_value(fmt_cntl_value, 1,
++ FMT_CONTROL,
++ FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP);
++ } else
++ return;
++ } else {
++ set_reg_field_value(fmt_cntl_value, 0,
++ FMT_CONTROL,
++ FMT_SPATIAL_DITHER_FRAME_COUNTER_MAX);
++ set_reg_field_value(fmt_cntl_value, 0,
++ FMT_CONTROL,
++ FMT_SPATIAL_DITHER_FRAME_COUNTER_BIT_SWAP);
++ }
++
++ dal_write_reg(opp110->base.ctx, addr, fmt_cntl_value);
++
++ /*Set seed for random values for
++ * spatial dithering for R,G,B channels*/
++ addr = FMT_REG(mmFMT_DITHER_RAND_R_SEED);
++ set_reg_field_value(dither_r_value, params->r_seed_value,
++ FMT_DITHER_RAND_R_SEED,
++ FMT_RAND_R_SEED);
++ dal_write_reg(opp110->base.ctx, addr, dither_r_value);
++
++ addr = FMT_REG(mmFMT_DITHER_RAND_G_SEED);
++ set_reg_field_value(dither_g_value,
++ params->g_seed_value,
++ FMT_DITHER_RAND_G_SEED,
++ FMT_RAND_G_SEED);
++ dal_write_reg(opp110->base.ctx, addr, dither_g_value);
++
++ addr = FMT_REG(mmFMT_DITHER_RAND_B_SEED);
++ set_reg_field_value(dither_b_value, params->b_seed_value,
++ FMT_DITHER_RAND_B_SEED,
++ FMT_RAND_B_SEED);
++ dal_write_reg(opp110->base.ctx, addr, dither_b_value);
++
++ /* FMT_OFFSET_R_Cr 31:16 0x0 Setting the zero
++ * offset for the R/Cr channel, lower 4LSB
++ * is forced to zeros. Typically set to 0
++ * RGB and 0x80000 YCbCr.
++ */
++ /* FMT_OFFSET_G_Y 31:16 0x0 Setting the zero
++ * offset for the G/Y channel, lower 4LSB is
++ * forced to zeros. Typically set to 0 RGB
++ * and 0x80000 YCbCr.
++ */
++ /* FMT_OFFSET_B_Cb 31:16 0x0 Setting the zero
++ * offset for the B/Cb channel, lower 4LSB is
++ * forced to zeros. Typically set to 0 RGB and
++ * 0x80000 YCbCr.
++ */
++
++ /*Set spatial dithering bit depth*/
++ set_reg_field_value(depth_cntl_value,
++ params->flags.SPATIAL_DITHER_DEPTH,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_SPATIAL_DITHER_DEPTH);
++
++ /* Set spatial dithering mode
++ * (default is Seed patterrn AAAA...)
++ */
++ set_reg_field_value(depth_cntl_value,
++ params->flags.SPATIAL_DITHER_MODE,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_SPATIAL_DITHER_MODE);
++
++ /*Reset only at startup*/
++ set_reg_field_value(depth_cntl_value,
++ params->flags.FRAME_RANDOM,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_RGB_RANDOM_ENABLE);
++
++ /*Set RGB data dithered with x^28+x^3+1*/
++ set_reg_field_value(depth_cntl_value,
++ params->flags.RGB_RANDOM,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_RGB_RANDOM_ENABLE);
++
++ /*Disable High pass filter*/
++ set_reg_field_value(depth_cntl_value,
++ params->flags.HIGHPASS_RANDOM,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_HIGHPASS_RANDOM_ENABLE);
++
++ /*Enable spatial dithering*/
++ set_reg_field_value(depth_cntl_value,
++ 1,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_SPATIAL_DITHER_EN);
++
++ addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
++ dal_write_reg(opp110->base.ctx, addr, depth_cntl_value);
++
++}
++
++/**
++ * SetTemporalDither (Frame Modulation)
++ * 1) set temporal dither depth
++ * 2) select pattern: from hard-coded pattern or programmable pattern
++ * 3) select optimized strips for BGR or RGB LCD sub-pixel
++ * 4) set s matrix
++ * 5) set t matrix
++ * 6) set grey level for 0.25, 0.5, 0.75
++ * 7) enable temporal dithering
++ */
++static void set_temporal_dither(
++ struct dce110_opp *opp110,
++ const struct bit_depth_reduction_params *params)
++{
++ uint32_t addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
++ uint32_t value;
++
++ /*Disable temporal (frame modulation) dithering first*/
++ value = dal_read_reg(opp110->base.ctx, addr);
++
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_DITHER_EN);
++
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_DITHER_RESET);
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_DITHER_OFFSET);
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_DITHER_DEPTH);
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_LEVEL);
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_25FRC_SEL);
++
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_50FRC_SEL);
++
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_75FRC_SEL);
++
++ dal_write_reg(opp110->base.ctx, addr, value);
++
++ /* no 10bpc dither on DCE11*/
++ if (params->flags.FRAME_MODULATION_ENABLED == 0 ||
++ params->flags.FRAME_MODULATION_DEPTH == 2)
++ return;
++
++ /* Set temporal dithering depth*/
++ set_reg_field_value(value,
++ params->flags.FRAME_MODULATION_DEPTH,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_DITHER_DEPTH);
++
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_DITHER_RESET);
++
++ set_reg_field_value(value,
++ 0,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_DITHER_OFFSET);
++
++ /*Select legacy pattern based on FRC and Temporal level*/
++ addr = FMT_REG(mmFMT_TEMPORAL_DITHER_PATTERN_CONTROL);
++ dal_write_reg(opp110->base.ctx, addr, 0);
++ /*Set s matrix*/
++ addr = FMT_REG(
++ mmFMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_S_MATRIX);
++ dal_write_reg(opp110->base.ctx, addr, 0);
++ /*Set t matrix*/
++ addr = FMT_REG(
++ mmFMT_TEMPORAL_DITHER_PROGRAMMABLE_PATTERN_T_MATRIX);
++ dal_write_reg(opp110->base.ctx, addr, 0);
++
++ /*Select patterns for 0.25, 0.5 and 0.75 grey level*/
++ set_reg_field_value(value,
++ params->flags.TEMPORAL_LEVEL,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_LEVEL);
++
++ set_reg_field_value(value,
++ params->flags.FRC25,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_25FRC_SEL);
++
++ set_reg_field_value(value,
++ params->flags.FRC50,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_50FRC_SEL);
++
++ set_reg_field_value(value,
++ params->flags.FRC75,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_75FRC_SEL);
++
++ /*Enable bit reduction by temporal (frame modulation) dithering*/
++ set_reg_field_value(value,
++ 1,
++ FMT_BIT_DEPTH_CONTROL,
++ FMT_TEMPORAL_DITHER_EN);
++
++ addr = FMT_REG(mmFMT_BIT_DEPTH_CONTROL);
++ dal_write_reg(opp110->base.ctx, addr, value);
++
++}
++
++/**
++ * Set Clamping
++ * 1) Set clamping format based on bpc - 0 for 6bpc (No clamping)
++ * 1 for 8 bpc
++ * 2 for 10 bpc
++ * 3 for 12 bpc
++ * 7 for programable
++ * 2) Enable clamp if Limited range requested
++ */
++static void set_clamping(
++ struct dce110_opp *opp110,
++ const struct clamping_and_pixel_encoding_params *params)
++{
++ uint32_t clamp_cntl_value = 0;
++ uint32_t red_clamp_value = 0;
++ uint32_t green_clamp_value = 0;
++ uint32_t blue_clamp_value = 0;
++ uint32_t addr = FMT_REG(mmFMT_CLAMP_CNTL);
++
++ clamp_cntl_value = dal_read_reg(opp110->base.ctx, addr);
++
++ set_reg_field_value(clamp_cntl_value,
++ 0,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_DATA_EN);
++
++ set_reg_field_value(clamp_cntl_value,
++ 0,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_COLOR_FORMAT);
++
++ switch (params->clamping_level) {
++ case CLAMPING_FULL_RANGE:
++ break;
++
++ case CLAMPING_LIMITED_RANGE_8BPC:
++ set_reg_field_value(clamp_cntl_value,
++ 1,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_DATA_EN);
++
++ set_reg_field_value(clamp_cntl_value,
++ 1,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_COLOR_FORMAT);
++
++ break;
++
++ case CLAMPING_LIMITED_RANGE_10BPC:
++ set_reg_field_value(clamp_cntl_value,
++ 1,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_DATA_EN);
++
++ set_reg_field_value(clamp_cntl_value,
++ 2,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_COLOR_FORMAT);
++
++ break;
++ case CLAMPING_LIMITED_RANGE_12BPC:
++ set_reg_field_value(clamp_cntl_value,
++ 1,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_DATA_EN);
++
++ set_reg_field_value(clamp_cntl_value,
++ 3,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_COLOR_FORMAT);
++
++ break;
++ case CLAMPING_LIMITED_RANGE_PROGRAMMABLE:
++ set_reg_field_value(clamp_cntl_value,
++ 1,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_DATA_EN);
++
++ set_reg_field_value(clamp_cntl_value,
++ 7,
++ FMT_CLAMP_CNTL,
++ FMT_CLAMP_COLOR_FORMAT);
++
++ /*set the defaults*/
++ set_reg_field_value(red_clamp_value,
++ 0x10,
++ FMT_CLAMP_COMPONENT_R,
++ FMT_CLAMP_LOWER_R);
++
++ set_reg_field_value(red_clamp_value,
++ 0xFEF,
++ FMT_CLAMP_COMPONENT_R,
++ FMT_CLAMP_UPPER_R);
++
++ addr = FMT_REG(mmFMT_CLAMP_COMPONENT_R);
++ dal_write_reg(opp110->base.ctx, addr, red_clamp_value);
++
++ set_reg_field_value(green_clamp_value,
++ 0x10,
++ FMT_CLAMP_COMPONENT_G,
++ FMT_CLAMP_LOWER_G);
++
++ set_reg_field_value(green_clamp_value,
++ 0xFEF,
++ FMT_CLAMP_COMPONENT_G,
++ FMT_CLAMP_UPPER_G);
++
++ addr = FMT_REG(mmFMT_CLAMP_COMPONENT_G);
++ dal_write_reg(opp110->base.ctx, addr, green_clamp_value);
++
++ set_reg_field_value(blue_clamp_value,
++ 0x10,
++ FMT_CLAMP_COMPONENT_B,
++ FMT_CLAMP_LOWER_B);
++
++ set_reg_field_value(blue_clamp_value,
++ 0xFEF,
++ FMT_CLAMP_COMPONENT_B,
++ FMT_CLAMP_UPPER_B);
++
++ addr = FMT_REG(mmFMT_CLAMP_COMPONENT_B);
++ dal_write_reg(opp110->base.ctx, addr, blue_clamp_value);
++
++ break;
++
++ default:
++ break;
++ }
++
++ addr = FMT_REG(mmFMT_CLAMP_CNTL);
++ /*Set clamp control*/
++ dal_write_reg(opp110->base.ctx, addr, clamp_cntl_value);
++
++}
++
++/**
++ * set_pixel_encoding
++ *
++ * Set Pixel Encoding
++ * 0: RGB 4:4:4 or YCbCr 4:4:4 or YOnly
++ * 1: YCbCr 4:2:2
++ */
++static void set_pixel_encoding(
++ struct dce110_opp *opp110,
++ const struct clamping_and_pixel_encoding_params *params)
++{
++ uint32_t fmt_cntl_value;
++ uint32_t addr = FMT_REG(mmFMT_CONTROL);
++
++ /*RGB 4:4:4 or YCbCr 4:4:4 - 0; YCbCr 4:2:2 -1.*/
++ fmt_cntl_value = dal_read_reg(opp110->base.ctx, addr);
++
++ set_reg_field_value(fmt_cntl_value,
++ 0,
++ FMT_CONTROL,
++ FMT_PIXEL_ENCODING);
++
++ if (params->pixel_encoding == PIXEL_ENCODING_YCBCR422) {
++ set_reg_field_value(fmt_cntl_value,
++ 1,
++ FMT_CONTROL,
++ FMT_PIXEL_ENCODING);
++
++ /*00 - Pixels drop mode ,01 - Pixels average mode*/
++ set_reg_field_value(fmt_cntl_value,
++ 0,
++ FMT_CONTROL,
++ FMT_SUBSAMPLING_MODE);
++
++ /*00 - Cb before Cr ,01 - Cr before Cb*/
++ set_reg_field_value(fmt_cntl_value,
++ 0,
++ FMT_CONTROL,
++ FMT_SUBSAMPLING_ORDER);
++ }
++ dal_write_reg(opp110->base.ctx, addr, fmt_cntl_value);
++
++}
++
++void dce110_opp_program_bit_depth_reduction(
++ struct output_pixel_processor *opp,
++ const struct bit_depth_reduction_params *params)
++{
++ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
++
++ set_truncation(opp110, params);
++ set_spatial_dither(opp110, params);
++ set_temporal_dither(opp110, params);
++}
++
++void dce110_opp_program_clamping_and_pixel_encoding(
++ struct output_pixel_processor *opp,
++ const struct clamping_and_pixel_encoding_params *params)
++{
++ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
++
++ set_clamping(opp110, params);
++ set_pixel_encoding(opp110, params);
++}
++
++void dce110_opp_set_dyn_expansion(
++ struct output_pixel_processor *opp,
++ enum color_space color_sp,
++ enum dc_color_depth color_dpth,
++ enum signal_type signal)
++{
++ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
++ uint32_t value;
++ bool enable_dyn_exp = false;
++ uint32_t addr = FMT_REG(mmFMT_DYNAMIC_EXP_CNTL);
++
++ value = dal_read_reg(opp->ctx, addr);
++
++ set_reg_field_value(value, 0,
++ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN);
++ set_reg_field_value(value, 0,
++ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE);
++
++ /* From HW programming guide:
++ FMT_DYNAMIC_EXP_EN = 0 for limited RGB or YCbCr output
++ FMT_DYNAMIC_EXP_EN = 1 for RGB full range only*/
++ if (color_sp == COLOR_SPACE_SRGB_FULL_RANGE)
++ enable_dyn_exp = true;
++
++ /*00 - 10-bit -> 12-bit dynamic expansion*/
++ /*01 - 8-bit -> 12-bit dynamic expansion*/
++ if (signal == SIGNAL_TYPE_HDMI_TYPE_A) {
++ switch (color_dpth) {
++ case COLOR_DEPTH_888:
++ set_reg_field_value(value, enable_dyn_exp ? 1:0,
++ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN);
++ set_reg_field_value(value, 1,
++ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE);
++ break;
++ case COLOR_DEPTH_101010:
++ set_reg_field_value(value, enable_dyn_exp ? 1:0,
++ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_EN);
++ set_reg_field_value(value, 0,
++ FMT_DYNAMIC_EXP_CNTL, FMT_DYNAMIC_EXP_MODE);
++ break;
++ case COLOR_DEPTH_121212:
++ break;
++ default:
++ break;
++ }
++ }
++
++ dal_write_reg(opp->ctx, addr, value);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c
+new file mode 100644
+index 0000000..4cba172
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_opp_regamma.c
+@@ -0,0 +1,2473 @@
++/*
++ * 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 "dal_services.h"
++
++/* include DCE11 register header files */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_opp.h"
++
++#define DCP_REG(reg)\
++ (reg + opp110->offsets.dcp_offset)
++
++#define DCFE_REG(reg)\
++ (reg + opp110->offsets.dcfe_offset)
++
++enum {
++ MAX_PWL_ENTRY = 128,
++ MAX_REGIONS_NUMBER = 16
++
++};
++
++struct curve_config {
++ uint32_t offset;
++ int8_t segments[MAX_REGIONS_NUMBER];
++ int8_t begin;
++};
++
++/* BASE */
++static bool find_software_points(
++ struct dce110_opp *opp110,
++ struct fixed31_32 hw_point,
++ enum channel_name channel,
++ uint32_t *index_to_start,
++ uint32_t *index_left,
++ uint32_t *index_right,
++ enum hw_point_position *pos)
++{
++ const uint32_t max_number =
++ RGB_256X3X16 + opp110->regamma.extra_points;
++
++ struct fixed31_32 left, right;
++
++ uint32_t i = *index_to_start;
++
++ while (i < max_number) {
++ if (channel == CHANNEL_NAME_RED) {
++ left = opp110->
++ regamma.axis_x_256[i].r;
++
++ if (i < max_number - 1)
++ right = opp110->
++ regamma.axis_x_256[i + 1].r;
++ else
++ right = opp110->
++ regamma.axis_x_256[max_number - 1].r;
++ } else if (channel == CHANNEL_NAME_GREEN) {
++ left = opp110->regamma.axis_x_256[i].g;
++
++ if (i < max_number - 1)
++ right = opp110->
++ regamma.axis_x_256[i + 1].g;
++ else
++ right = opp110->
++ regamma.axis_x_256[max_number - 1].g;
++ } else {
++ left = opp110->regamma.axis_x_256[i].b;
++
++ if (i < max_number - 1)
++ right = opp110->
++ regamma.axis_x_256[i + 1].b;
++ else
++ right = opp110->
++ regamma.axis_x_256[max_number - 1].b;
++ }
++
++ if (dal_fixed31_32_le(left, hw_point) &&
++ dal_fixed31_32_le(hw_point, right)) {
++ *index_to_start = i;
++ *index_left = i;
++
++ if (i < max_number - 1)
++ *index_right = i + 1;
++ else
++ *index_right = max_number - 1;
++
++ *pos = HW_POINT_POSITION_MIDDLE;
++
++ return true;
++ } else if ((i == *index_to_start) &&
++ dal_fixed31_32_le(hw_point, left)) {
++ *index_to_start = i;
++ *index_left = i;
++ *index_right = i;
++
++ *pos = HW_POINT_POSITION_LEFT;
++
++ return true;
++ } else if ((i == max_number - 1) &&
++ dal_fixed31_32_le(right, hw_point)) {
++ *index_to_start = i;
++ *index_left = i;
++ *index_right = i;
++
++ *pos = HW_POINT_POSITION_RIGHT;
++
++ return true;
++ }
++
++ ++i;
++ }
++
++ return false;
++}
++
++static bool find_software_points_dx(
++ struct dce110_opp *opp110,
++ struct fixed31_32 hw_point,
++ enum channel_name channel,
++ uint32_t *index_to_start,
++ uint32_t *index_left,
++ uint32_t *index_right,
++ enum hw_point_position *pos)
++{
++ const uint32_t max_number = DX_GAMMA_RAMP_MAX +
++ opp110->regamma.extra_points;
++
++ struct fixed31_32 left, right;
++
++ uint32_t i = *index_to_start;
++
++ while (i < max_number) {
++ if (channel == CHANNEL_NAME_RED) {
++ left = opp110->regamma.axis_x_1025[i].r;
++
++ if (i < DX_GAMMA_RAMP_MAX - 1)
++ right = opp110->
++ regamma.axis_x_1025[i + 1].r;
++ else
++ right = opp110->
++ regamma.axis_x_1025[DX_GAMMA_RAMP_MAX-1].r;
++ } else if (channel == CHANNEL_NAME_GREEN) {
++ left = opp110->regamma.axis_x_1025[i].g;
++
++ if (i < DX_GAMMA_RAMP_MAX - 1)
++ right = opp110->
++ regamma.axis_x_1025[i + 1].g;
++ else
++ right = opp110->
++ regamma.axis_x_1025[DX_GAMMA_RAMP_MAX-1].g;
++ } else {
++ left = opp110->regamma.axis_x_1025[i].b;
++
++ if (i < DX_GAMMA_RAMP_MAX - 1)
++ right = opp110->
++ regamma.axis_x_1025[i + 1].b;
++ else
++ right = opp110->
++ regamma.axis_x_1025[DX_GAMMA_RAMP_MAX-1].b;
++ }
++
++ if (dal_fixed31_32_le(left, hw_point) &&
++ dal_fixed31_32_le(hw_point, right)) {
++ *index_to_start = i;
++ *index_left = i;
++
++ if (i < DX_GAMMA_RAMP_MAX - 1)
++ *index_right = i + 1;
++ else
++ *index_right = DX_GAMMA_RAMP_MAX - 1;
++
++ *pos = HW_POINT_POSITION_MIDDLE;
++
++ return true;
++ } else if ((i == *index_to_start) &&
++ dal_fixed31_32_le(hw_point, left)) {
++ *index_to_start = i;
++ *index_left = i;
++ *index_right = i;
++
++ *pos = HW_POINT_POSITION_LEFT;
++
++ return true;
++ } else if ((i == max_number - 1) &&
++ dal_fixed31_32_le(right, hw_point)) {
++ *index_to_start = i;
++ *index_left = i;
++ *index_right = i;
++
++ *pos = HW_POINT_POSITION_RIGHT;
++
++ return true;
++ }
++
++ ++i;
++ }
++
++ return false;
++}
++
++static bool build_custom_gamma_mapping_coefficients_worker(
++ struct dce110_opp *opp110,
++ struct pixel_gamma_point *coeff,
++ enum channel_name channel,
++ uint32_t number_of_points,
++ enum pixel_format pixel_format)
++{
++ uint32_t i = 0;
++
++ while (i <= number_of_points) {
++ struct fixed31_32 coord_x;
++
++ uint32_t index_to_start = 0;
++ uint32_t index_left = 0;
++ uint32_t index_right = 0;
++
++ enum hw_point_position hw_pos;
++
++ struct gamma_point *point;
++
++ struct fixed31_32 left_pos;
++ struct fixed31_32 right_pos;
++
++ if (pixel_format == PIXEL_FORMAT_FP16)
++ coord_x = opp110->
++ regamma.coordinates_x[i].adjusted_x;
++ else if (channel == CHANNEL_NAME_RED)
++ coord_x = opp110->
++ regamma.coordinates_x[i].regamma_y_red;
++ else if (channel == CHANNEL_NAME_GREEN)
++ coord_x = opp110->
++ regamma.coordinates_x[i].regamma_y_green;
++ else
++ coord_x = opp110->
++ regamma.coordinates_x[i].regamma_y_blue;
++
++ if (!find_software_points(
++ opp110, coord_x, channel,
++ &index_to_start, &index_left, &index_right, &hw_pos)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (index_left >= RGB_256X3X16 +
++ opp110->regamma.extra_points) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (index_right >= RGB_256X3X16 +
++ opp110->regamma.extra_points) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (channel == CHANNEL_NAME_RED) {
++ point = &coeff[i].r;
++
++ left_pos = opp110->
++ regamma.axis_x_256[index_left].r;
++ right_pos = opp110->
++ regamma.axis_x_256[index_right].r;
++ } else if (channel == CHANNEL_NAME_GREEN) {
++ point = &coeff[i].g;
++
++ left_pos = opp110->
++ regamma.axis_x_256[index_left].g;
++ right_pos = opp110->
++ regamma.axis_x_256[index_right].g;
++ } else {
++ point = &coeff[i].b;
++
++ left_pos = opp110->
++ regamma.axis_x_256[index_left].b;
++ right_pos = opp110->
++ regamma.axis_x_256[index_right].b;
++ }
++
++ if (hw_pos == HW_POINT_POSITION_MIDDLE)
++ point->coeff = dal_fixed31_32_div(
++ dal_fixed31_32_sub(
++ coord_x,
++ left_pos),
++ dal_fixed31_32_sub(
++ right_pos,
++ left_pos));
++ else if (hw_pos == HW_POINT_POSITION_LEFT)
++ point->coeff = opp110->regamma.x_min;
++ else if (hw_pos == HW_POINT_POSITION_RIGHT)
++ point->coeff = opp110->regamma.x_max2;
++ else {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ point->left_index = index_left;
++ point->right_index = index_right;
++ point->pos = hw_pos;
++
++ ++i;
++ }
++
++ return true;
++}
++
++static inline bool build_custom_gamma_mapping_coefficients(
++ struct dce110_opp *opp110,
++ enum channel_name channel,
++ uint32_t number_of_points,
++ enum pixel_format pixel_format)
++{
++ return build_custom_gamma_mapping_coefficients_worker(
++ opp110, opp110->regamma.coeff128, channel,
++ number_of_points, pixel_format);
++}
++
++static inline bool build_oem_custom_gamma_mapping_coefficients(
++ struct dce110_opp *opp110,
++ enum channel_name channel,
++ uint32_t number_of_points,
++ enum pixel_format pixel_format)
++{
++ return build_custom_gamma_mapping_coefficients_worker(
++ opp110, opp110->regamma.coeff128_oem, channel,
++ number_of_points, pixel_format);
++}
++
++static bool build_custom_dx_gamma_mapping_coefficients(
++ struct dce110_opp *opp110,
++ enum channel_name channel,
++ uint32_t number_of_points,
++ enum pixel_format pixel_format)
++{
++ uint32_t i = 0;
++
++ while (i <= number_of_points) {
++ struct fixed31_32 coord_x;
++
++ uint32_t index_to_start = 0;
++ uint32_t index_left = 0;
++ uint32_t index_right = 0;
++
++ enum hw_point_position hw_pos;
++
++ struct gamma_point *point;
++
++ struct fixed31_32 left_pos;
++ struct fixed31_32 right_pos;
++
++ if (pixel_format == PIXEL_FORMAT_FP16)
++ coord_x = opp110->
++ regamma.coordinates_x[i].adjusted_x;
++ else if (channel == CHANNEL_NAME_RED)
++ coord_x = opp110->
++ regamma.coordinates_x[i].regamma_y_red;
++ else if (channel == CHANNEL_NAME_GREEN)
++ coord_x = opp110->
++ regamma.coordinates_x[i].regamma_y_green;
++ else
++ coord_x = opp110->
++ regamma.coordinates_x[i].regamma_y_blue;
++
++ if (!find_software_points_dx(
++ opp110, coord_x, channel,
++ &index_to_start, &index_left, &index_right, &hw_pos)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (index_left >= DX_GAMMA_RAMP_MAX +
++ opp110->regamma.extra_points) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (index_right >= DX_GAMMA_RAMP_MAX +
++ opp110->regamma.extra_points) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (channel == CHANNEL_NAME_RED) {
++ point = &opp110->regamma.coeff128_dx[i].r;
++
++ left_pos = opp110->
++ regamma.axis_x_1025[index_left].r;
++ right_pos = opp110->
++ regamma.axis_x_1025[index_right].r;
++ } else if (channel == CHANNEL_NAME_GREEN) {
++ point = &opp110->regamma.coeff128_dx[i].g;
++
++ left_pos = opp110->
++ regamma.axis_x_1025[index_left].g;
++ right_pos = opp110->
++ regamma.axis_x_1025[index_right].g;
++ } else {
++ point = &opp110->regamma.coeff128_dx[i].b;
++
++ left_pos = opp110->
++ regamma.axis_x_1025[index_left].b;
++ right_pos = opp110->
++ regamma.axis_x_1025[index_right].b;
++ }
++
++ if (hw_pos == HW_POINT_POSITION_MIDDLE)
++ point->coeff = dal_fixed31_32_div(
++ dal_fixed31_32_sub(
++ coord_x,
++ left_pos),
++ dal_fixed31_32_sub(
++ right_pos,
++ left_pos));
++ else if (hw_pos == HW_POINT_POSITION_LEFT)
++ point->coeff = opp110->regamma.x_min;
++ else if (hw_pos == HW_POINT_POSITION_RIGHT)
++ point->coeff = opp110->regamma.x_max2;
++ else {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ point->left_index = index_left;
++ point->right_index = index_right;
++ point->pos = hw_pos;
++
++ ++i;
++ }
++
++ return true;
++}
++
++static struct fixed31_32 calculate_mapped_value(
++ struct dce110_opp *opp110,
++ struct pwl_float_data *rgb,
++ const struct pixel_gamma_point *coeff,
++ enum channel_name channel,
++ uint32_t max_index)
++{
++ const struct gamma_point *point;
++
++ struct fixed31_32 result;
++
++ if (channel == CHANNEL_NAME_RED)
++ point = &coeff->r;
++ else if (channel == CHANNEL_NAME_GREEN)
++ point = &coeff->g;
++ else
++ point = &coeff->b;
++
++ if ((point->left_index < 0) || (point->left_index > max_index)) {
++ BREAK_TO_DEBUGGER();
++ return dal_fixed31_32_zero;
++ }
++
++ if ((point->right_index < 0) || (point->right_index > max_index)) {
++ BREAK_TO_DEBUGGER();
++ return dal_fixed31_32_zero;
++ }
++
++ if (point->pos == HW_POINT_POSITION_MIDDLE)
++ if (channel == CHANNEL_NAME_RED)
++ result = dal_fixed31_32_add(
++ dal_fixed31_32_mul(
++ point->coeff,
++ dal_fixed31_32_sub(
++ rgb[point->right_index].r,
++ rgb[point->left_index].r)),
++ rgb[point->left_index].r);
++ else if (channel == CHANNEL_NAME_GREEN)
++ result = dal_fixed31_32_add(
++ dal_fixed31_32_mul(
++ point->coeff,
++ dal_fixed31_32_sub(
++ rgb[point->right_index].g,
++ rgb[point->left_index].g)),
++ rgb[point->left_index].g);
++ else
++ result = dal_fixed31_32_add(
++ dal_fixed31_32_mul(
++ point->coeff,
++ dal_fixed31_32_sub(
++ rgb[point->right_index].b,
++ rgb[point->left_index].b)),
++ rgb[point->left_index].b);
++ else if (point->pos == HW_POINT_POSITION_LEFT) {
++ BREAK_TO_DEBUGGER();
++ result = opp110->regamma.x_min;
++ } else {
++ BREAK_TO_DEBUGGER();
++ result = opp110->regamma.x_max1;
++ }
++
++ return result;
++}
++
++static inline struct fixed31_32 calculate_regamma_user_mapped_value(
++ struct dce110_opp *opp110,
++ const struct pixel_gamma_point *coeff,
++ enum channel_name channel,
++ uint32_t max_index)
++{
++ return calculate_mapped_value(
++ opp110, opp110->regamma.rgb_oem,
++ coeff, channel, max_index);
++}
++
++static inline struct fixed31_32 calculate_user_mapped_value(
++ struct dce110_opp *opp110,
++ const struct pixel_gamma_point *coeff,
++ enum channel_name channel,
++ uint32_t max_index)
++{
++ return calculate_mapped_value(
++ opp110, opp110->regamma.rgb_user,
++ coeff, channel, max_index);
++}
++
++static inline struct fixed31_32 calculate_oem_mapped_value(
++ struct dce110_opp *opp110,
++ uint32_t index,
++ enum channel_name channel,
++ uint32_t max_index)
++{
++ return calculate_regamma_user_mapped_value(
++ opp110, opp110->regamma.coeff128_oem +
++ index, channel, max_index);
++}
++
++static void scale_oem_gamma(
++ struct dce110_opp *opp110,
++ const struct regamma_ramp *regamma_ramp)
++{
++ const uint16_t max_driver = 0xFFFF;
++ const uint16_t max_os = 0xFF00;
++
++ uint16_t scale = max_os;
++
++ uint32_t i;
++
++ struct pwl_float_data *rgb = opp110->regamma.rgb_oem;
++ struct pwl_float_data *rgb_last = rgb + RGB_256X3X16 - 1;
++
++ /* find OEM maximum */
++
++ i = 0;
++
++ do {
++ if ((regamma_ramp->gamma[i] > max_os) ||
++ (regamma_ramp->gamma[i + RGB_256X3X16] > max_os) ||
++ (regamma_ramp->gamma[i + 2 * RGB_256X3X16] > max_os)) {
++ scale = max_driver;
++ break;
++ }
++
++ ++i;
++ } while (i != RGB_256X3X16);
++
++ /* scale */
++
++ i = 0;
++
++ do {
++ rgb->r = dal_fixed31_32_div_int(
++ dal_fixed31_32_from_int(
++ regamma_ramp->gamma[i]),
++ scale);
++ rgb->g = dal_fixed31_32_div_int(
++ dal_fixed31_32_from_int(
++ regamma_ramp->gamma[i + RGB_256X3X16]),
++ scale);
++ rgb->b = dal_fixed31_32_div_int(
++ dal_fixed31_32_from_int(
++ regamma_ramp->gamma[i + 2 * RGB_256X3X16]),
++ scale);
++
++ ++rgb;
++ ++i;
++ } while (i != RGB_256X3X16);
++
++ /* add 3 extra points, 2 physical plus 1 virtual */
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ opp110->regamma.divider1);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ opp110->regamma.divider1);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ opp110->regamma.divider1);
++
++ ++rgb;
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ opp110->regamma.divider2);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ opp110->regamma.divider2);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ opp110->regamma.divider2);
++
++ ++rgb;
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ opp110->regamma.divider3);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ opp110->regamma.divider3);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ opp110->regamma.divider3);
++}
++
++static inline void copy_rgb_regamma_to_coordinates_x(
++ struct dce110_opp *opp110)
++{
++ struct hw_x_point *coords = opp110->regamma.coordinates_x;
++ const struct pwl_float_data_ex *rgb_regamma =
++ opp110->regamma.rgb_regamma;
++
++ uint32_t i = 0;
++
++ while (i <= opp110->regamma.hw_points_num) {
++ coords->regamma_y_red = rgb_regamma->r;
++ coords->regamma_y_green = rgb_regamma->g;
++ coords->regamma_y_blue = rgb_regamma->b;
++
++ ++coords;
++ ++rgb_regamma;
++ ++i;
++ }
++}
++
++static bool calculate_interpolated_hardware_curve(
++ struct dce110_opp *opp110,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params)
++{
++ struct pwl_result_data *rgb_resulted =
++ opp110->regamma.rgb_resulted;
++
++ const struct pixel_gamma_point *coeff;
++ uint32_t max_entries = opp110->regamma.extra_points - 1;
++
++ uint32_t i = 0;
++
++ if (gamma_ramp->type == GAMMA_RAMP_RBG256X3X16) {
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_RED,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_GREEN,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_BLUE,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ coeff = opp110->regamma.coeff128;
++ max_entries += RGB_256X3X16;
++ } else if (gamma_ramp->type == GAMMA_RAMP_DXGI_1) {
++ if (!build_custom_dx_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_RED,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_custom_dx_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_GREEN,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_custom_dx_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_BLUE,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ coeff = opp110->regamma.coeff128_dx;
++ max_entries += DX_GAMMA_RAMP_MAX;
++ } else {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ while (i <= opp110->regamma.hw_points_num) {
++ rgb_resulted->red = calculate_user_mapped_value(
++ opp110, coeff, CHANNEL_NAME_RED, max_entries);
++ rgb_resulted->green = calculate_user_mapped_value(
++ opp110, coeff, CHANNEL_NAME_GREEN, max_entries);
++ rgb_resulted->blue = calculate_user_mapped_value(
++ opp110, coeff, CHANNEL_NAME_BLUE, max_entries);
++
++ ++coeff;
++ ++rgb_resulted;
++ ++i;
++ }
++
++ return true;
++}
++
++static void map_standard_regamma_hw_to_x_user(
++ struct dce110_opp *opp110,
++ enum gamma_ramp_type type,
++ const struct gamma_parameters *params)
++{
++ struct pwl_result_data *rgb_resulted =
++ opp110->regamma.rgb_resulted;
++ const struct pwl_float_data_ex *rgb_regamma =
++ opp110->regamma.rgb_regamma;
++
++ uint32_t i = 0;
++
++ while (i <= opp110->regamma.hw_points_num) {
++ rgb_resulted->red = rgb_regamma->r;
++ rgb_resulted->green = rgb_regamma->g;
++ rgb_resulted->blue = rgb_regamma->b;
++
++ ++rgb_resulted;
++ ++rgb_regamma;
++ ++i;
++ }
++}
++
++bool dce110_opp_map_legacy_and_regamma_hw_to_x_user(
++ struct output_pixel_processor *opp,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params)
++{
++ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
++
++ if (params->regamma.features.bits.GAMMA_RAMP_ARRAY ||
++ params->regamma.features.bits.APPLY_DEGAMMA) {
++
++ const uint32_t max_entries =
++ RGB_256X3X16 + opp110->regamma.extra_points - 1;
++
++ const struct pixel_gamma_point *coeff =
++ opp110->regamma.coeff128;
++ struct pwl_result_data *rgb_resulted =
++ opp110->regamma.rgb_resulted;
++
++ uint32_t i = 0;
++
++ scale_oem_gamma(opp110, &params->regamma.regamma_ramp);
++
++ copy_rgb_regamma_to_coordinates_x(opp110);
++
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_RED,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_GREEN,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_BLUE,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ while (i <= opp110->regamma.hw_points_num) {
++ rgb_resulted->red =
++ calculate_regamma_user_mapped_value(opp110,
++ coeff,
++ CHANNEL_NAME_RED, max_entries);
++ rgb_resulted->green =
++ calculate_regamma_user_mapped_value(opp110,
++ coeff,
++ CHANNEL_NAME_GREEN, max_entries);
++ rgb_resulted->blue =
++ calculate_regamma_user_mapped_value(opp110,
++ coeff,
++ CHANNEL_NAME_BLUE, max_entries);
++
++ ++coeff;
++ ++rgb_resulted;
++ ++i;
++ }
++ } else
++ map_standard_regamma_hw_to_x_user(opp110,
++ gamma_ramp->type,
++ params);
++
++ return true;
++}
++
++static bool map_regamma_hw_to_x_user(
++ struct dce110_opp *opp110,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params)
++{
++ /* setup to spare calculated ideal regamma values */
++ if (params->regamma.features.bits.GAMMA_RAMP_ARRAY ||
++ params->regamma.features.bits.APPLY_DEGAMMA) {
++
++ const uint32_t max_entries =
++ RGB_256X3X16 + opp110->regamma.extra_points - 1;
++
++ const struct pixel_gamma_point *coeff =
++ opp110->regamma.coeff128;
++ struct hw_x_point *coords =
++ opp110->regamma.coordinates_x;
++
++ uint32_t i = 0;
++
++ scale_oem_gamma(opp110, &params->regamma.regamma_ramp);
++
++ copy_rgb_regamma_to_coordinates_x(opp110);
++
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_RED,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_GREEN,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_BLUE,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ while (i <= opp110->regamma.hw_points_num) {
++ coords->regamma_y_red =
++ calculate_regamma_user_mapped_value(opp110,
++ coeff,
++ CHANNEL_NAME_RED, max_entries);
++ coords->regamma_y_green =
++ calculate_regamma_user_mapped_value(opp110,
++ coeff,
++ CHANNEL_NAME_GREEN, max_entries);
++ coords->regamma_y_blue =
++ calculate_regamma_user_mapped_value(opp110,
++ coeff,
++ CHANNEL_NAME_BLUE, max_entries);
++
++ ++coeff;
++ ++coords;
++ ++i;
++ }
++ } else {
++ copy_rgb_regamma_to_coordinates_x(opp110);
++ }
++
++ return calculate_interpolated_hardware_curve(opp110, gamma_ramp,
++ params);
++}
++
++static void build_regamma_coefficients(
++ const struct regamma_lut *regamma,
++ bool is_degamma_srgb,
++ struct gamma_coefficients *coefficients)
++{
++ /* sRGB should apply 2.4 */
++ static const int32_t numerator01[3] = { 31308, 31308, 31308 };
++ static const int32_t numerator02[3] = { 12920, 12920, 12920 };
++ static const int32_t numerator03[3] = { 55, 55, 55 };
++ static const int32_t numerator04[3] = { 55, 55, 55 };
++ static const int32_t numerator05[3] = { 2400, 2400, 2400 };
++
++ /* Non-sRGB should apply 2.2 */
++ static const int32_t numerator11[3] = { 180000, 180000, 180000 };
++ static const int32_t numerator12[3] = { 4500, 4500, 4500 };
++ static const int32_t numerator13[3] = { 99, 99, 99 };
++ static const int32_t numerator14[3] = { 99, 99, 99 };
++ static const int32_t numerator15[3] = { 2200, 2200, 2200 };
++
++ const int32_t *numerator1;
++ const int32_t *numerator2;
++ const int32_t *numerator3;
++ const int32_t *numerator4;
++ const int32_t *numerator5;
++
++ uint32_t i = 0;
++
++ if (!regamma->features.bits.GAMMA_RAMP_ARRAY) {
++ numerator1 = regamma->gamma_coeff.a0;
++ numerator2 = regamma->gamma_coeff.a1;
++ numerator3 = regamma->gamma_coeff.a2;
++ numerator4 = regamma->gamma_coeff.a3;
++ numerator5 = regamma->gamma_coeff.gamma;
++ } else if (is_degamma_srgb) {
++ numerator1 = numerator01;
++ numerator2 = numerator02;
++ numerator3 = numerator03;
++ numerator4 = numerator04;
++ numerator5 = numerator05;
++ } else {
++ numerator1 = numerator11;
++ numerator2 = numerator12;
++ numerator3 = numerator13;
++ numerator4 = numerator14;
++ numerator5 = numerator15;
++ }
++
++ do {
++ coefficients->a0[i] = dal_fixed31_32_from_fraction(
++ numerator1[i], 10000000);
++ coefficients->a1[i] = dal_fixed31_32_from_fraction(
++ numerator2[i], 1000);
++ coefficients->a2[i] = dal_fixed31_32_from_fraction(
++ numerator3[i], 1000);
++ coefficients->a3[i] = dal_fixed31_32_from_fraction(
++ numerator4[i], 1000);
++ coefficients->user_gamma[i] = dal_fixed31_32_from_fraction(
++ numerator5[i], 1000);
++
++ ++i;
++ } while (i != ARRAY_SIZE(regamma->gamma_coeff.a0));
++}
++
++static struct fixed31_32 translate_from_linear_space(
++ struct fixed31_32 arg,
++ struct fixed31_32 a0,
++ struct fixed31_32 a1,
++ struct fixed31_32 a2,
++ struct fixed31_32 a3,
++ struct fixed31_32 gamma)
++{
++ const struct fixed31_32 one = dal_fixed31_32_from_int(1);
++
++ if (dal_fixed31_32_le(arg, dal_fixed31_32_neg(a0)))
++ return dal_fixed31_32_sub(
++ a2,
++ dal_fixed31_32_mul(
++ dal_fixed31_32_add(
++ one,
++ a3),
++ dal_fixed31_32_pow(
++ dal_fixed31_32_neg(arg),
++ dal_fixed31_32_recip(gamma))));
++ else if (dal_fixed31_32_le(a0, arg))
++ return dal_fixed31_32_sub(
++ dal_fixed31_32_mul(
++ dal_fixed31_32_add(
++ one,
++ a3),
++ dal_fixed31_32_pow(
++ arg,
++ dal_fixed31_32_recip(gamma))),
++ a2);
++ else
++ return dal_fixed31_32_mul(
++ arg,
++ a1);
++}
++
++static inline struct fixed31_32 translate_from_linear_space_ex(
++ struct fixed31_32 arg,
++ struct gamma_coefficients *coeff,
++ uint32_t color_index)
++{
++ return translate_from_linear_space(
++ arg,
++ coeff->a0[color_index],
++ coeff->a1[color_index],
++ coeff->a2[color_index],
++ coeff->a3[color_index],
++ coeff->user_gamma[color_index]);
++}
++
++static bool build_regamma_curve(
++ struct dce110_opp *opp110,
++ const struct gamma_parameters *params)
++{
++ struct pwl_float_data_ex *rgb = opp110->regamma.rgb_regamma;
++
++ uint32_t i;
++
++ if (!params->regamma.features.bits.GAMMA_RAMP_ARRAY &&
++ params->regamma.features.bits.APPLY_DEGAMMA) {
++ struct gamma_coefficients coeff;
++
++ struct hw_x_point *coord_x =
++ opp110->regamma.coordinates_x;
++
++ build_regamma_coefficients(
++ &params->regamma,
++ params->regamma.features.bits.GRAPHICS_DEGAMMA_SRGB,
++ &coeff);
++
++ /* Use opp110->regamma.coordinates_x to retrieve
++ * coordinates chosen base on given user curve (future task).
++ * The x values are exponentially distributed and currently
++ * it is hard-coded, the user curve shape is ignored.
++ * The future task is to recalculate opp110-
++ * regamma.coordinates_x based on input/user curve,
++ * translation from 256/1025 to 128 pwl points.
++ */
++
++ i = 0;
++
++ while (i != opp110->regamma.hw_points_num + 1) {
++ rgb->r = translate_from_linear_space_ex(
++ coord_x->adjusted_x, &coeff, 0);
++ rgb->g = translate_from_linear_space_ex(
++ coord_x->adjusted_x, &coeff, 1);
++ rgb->b = translate_from_linear_space_ex(
++ coord_x->adjusted_x, &coeff, 2);
++
++ ++coord_x;
++ ++rgb;
++ ++i;
++ }
++ } else {
++ const uint32_t max_entries =
++ RGB_256X3X16 + opp110->regamma.extra_points - 1;
++
++ /* interpolate between 256 input points and output 185 points */
++
++ scale_oem_gamma(opp110, &params->regamma.regamma_ramp);
++
++ if (!build_oem_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_RED,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_oem_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_GREEN,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!build_oem_custom_gamma_mapping_coefficients(
++ opp110, CHANNEL_NAME_BLUE,
++ opp110->regamma.hw_points_num,
++ params->surface_pixel_format)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ i = 0;
++
++ while (i != opp110->regamma.hw_points_num + 1) {
++ rgb->r = calculate_oem_mapped_value(
++ opp110, i, CHANNEL_NAME_RED, max_entries);
++ rgb->g = calculate_oem_mapped_value(
++ opp110, i, CHANNEL_NAME_GREEN, max_entries);
++ rgb->b = calculate_oem_mapped_value(
++ opp110, i, CHANNEL_NAME_BLUE, max_entries);
++ ++rgb;
++ ++i;
++ }
++ }
++
++ return true;
++}
++
++static void build_new_custom_resulted_curve(
++ struct dce110_opp *opp110,
++ const struct gamma_parameters *params)
++{
++ struct pwl_result_data *rgb = opp110->regamma.rgb_resulted;
++ struct pwl_result_data *rgb_plus_1 = rgb + 1;
++
++ uint32_t i;
++
++ i = 0;
++
++ while (i != opp110->regamma.hw_points_num + 1) {
++ rgb->red = dal_fixed31_32_clamp(
++ rgb->red, opp110->regamma.x_min,
++ opp110->regamma.x_max1);
++ rgb->green = dal_fixed31_32_clamp(
++ rgb->green, opp110->regamma.x_min,
++ opp110->regamma.x_max1);
++ rgb->blue = dal_fixed31_32_clamp(
++ rgb->blue, opp110->regamma.x_min,
++ opp110->regamma.x_max1);
++
++ ++rgb;
++ ++i;
++ }
++
++ rgb = opp110->regamma.rgb_resulted;
++
++ i = 1;
++
++ while (i != opp110->regamma.hw_points_num + 1) {
++ if (dal_fixed31_32_lt(rgb_plus_1->red, rgb->red))
++ rgb_plus_1->red = rgb->red;
++ if (dal_fixed31_32_lt(rgb_plus_1->green, rgb->green))
++ rgb_plus_1->green = rgb->green;
++ if (dal_fixed31_32_lt(rgb_plus_1->blue, rgb->blue))
++ rgb_plus_1->blue = rgb->blue;
++
++ rgb->delta_red = dal_fixed31_32_sub(
++ rgb_plus_1->red,
++ rgb->red);
++ rgb->delta_green = dal_fixed31_32_sub(
++ rgb_plus_1->green,
++ rgb->green);
++ rgb->delta_blue = dal_fixed31_32_sub(
++ rgb_plus_1->blue,
++ rgb->blue);
++
++ ++rgb_plus_1;
++ ++rgb;
++ ++i;
++ }
++}
++
++static bool rebuild_curve_configuration_magic(
++ struct dce110_opp *opp110)
++{
++ const struct fixed31_32 magic_number =
++ dal_fixed31_32_from_fraction(249, 1000);
++
++ struct fixed31_32 y_r;
++ struct fixed31_32 y_g;
++ struct fixed31_32 y_b;
++
++ struct fixed31_32 y1_min;
++ struct fixed31_32 y2_max;
++ struct fixed31_32 y3_max;
++
++ y_r = opp110->regamma.rgb_resulted[0].red;
++ y_g = opp110->regamma.rgb_resulted[0].green;
++ y_b = opp110->regamma.rgb_resulted[0].blue;
++
++ y1_min = dal_fixed31_32_min(y_r, dal_fixed31_32_min(y_g, y_b));
++
++ opp110->regamma.arr_points[0].x =
++ opp110->regamma.coordinates_x[0].adjusted_x;
++ opp110->regamma.arr_points[0].y = y1_min;
++ opp110->regamma.arr_points[0].slope = dal_fixed31_32_div(
++ opp110->regamma.arr_points[0].y,
++ opp110->regamma.arr_points[0].x);
++
++ opp110->regamma.arr_points[1].x = dal_fixed31_32_add(
++ opp110->regamma.coordinates_x
++ [opp110->regamma.hw_points_num - 1].adjusted_x,
++ magic_number);
++
++ opp110->regamma.arr_points[2].x =
++ opp110->regamma.arr_points[1].x;
++
++ y_r = opp110->regamma.rgb_resulted
++ [opp110->regamma.hw_points_num - 1].red;
++ y_g = opp110->regamma.rgb_resulted
++ [opp110->regamma.hw_points_num - 1].green;
++ y_b = opp110->regamma.rgb_resulted
++ [opp110->regamma.hw_points_num - 1].blue;
++
++ y2_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
++
++ opp110->regamma.arr_points[1].y = y2_max;
++
++ y_r = opp110->regamma.rgb_resulted
++ [opp110->regamma.hw_points_num].red;
++ y_g = opp110->regamma.rgb_resulted
++ [opp110->regamma.hw_points_num].green;
++ y_b = opp110->regamma.rgb_resulted
++ [opp110->regamma.hw_points_num].blue;
++
++ y3_max = dal_fixed31_32_max(y_r, dal_fixed31_32_max(y_g, y_b));
++
++ opp110->regamma.arr_points[2].y = y3_max;
++
++ opp110->regamma.arr_points[2].slope = dal_fixed31_32_one;
++
++ return true;
++}
++
++static bool build_custom_float(
++ struct fixed31_32 value,
++ const struct custom_float_format *format,
++ bool *negative,
++ uint32_t *mantissa,
++ uint32_t *exponenta)
++{
++ uint32_t exp_offset = (1 << (format->exponenta_bits - 1)) - 1;
++
++ const struct fixed31_32 mantissa_constant_plus_max_fraction =
++ dal_fixed31_32_from_fraction(
++ (1LL << (format->mantissa_bits + 1)) - 1,
++ 1LL << format->mantissa_bits);
++
++ struct fixed31_32 mantiss;
++
++ if (dal_fixed31_32_eq(
++ value,
++ dal_fixed31_32_zero)) {
++ *negative = false;
++ *mantissa = 0;
++ *exponenta = 0;
++ return true;
++ }
++
++ if (dal_fixed31_32_lt(
++ value,
++ dal_fixed31_32_zero)) {
++ *negative = format->sign;
++ value = dal_fixed31_32_neg(value);
++ } else {
++ *negative = false;
++ }
++
++ if (dal_fixed31_32_lt(
++ value,
++ dal_fixed31_32_one)) {
++ uint32_t i = 1;
++
++ do {
++ value = dal_fixed31_32_shl(value, 1);
++ ++i;
++ } while (dal_fixed31_32_lt(
++ value,
++ dal_fixed31_32_one));
++
++ --i;
++
++ if (exp_offset <= i) {
++ *mantissa = 0;
++ *exponenta = 0;
++ return true;
++ }
++
++ *exponenta = exp_offset - i;
++ } else if (dal_fixed31_32_le(
++ mantissa_constant_plus_max_fraction,
++ value)) {
++ uint32_t i = 1;
++
++ do {
++ value = dal_fixed31_32_shr(value, 1);
++ ++i;
++ } while (dal_fixed31_32_lt(
++ mantissa_constant_plus_max_fraction,
++ value));
++
++ *exponenta = exp_offset + i - 1;
++ } else {
++ *exponenta = exp_offset;
++ }
++
++ mantiss = dal_fixed31_32_sub(
++ value,
++ dal_fixed31_32_one);
++
++ if (dal_fixed31_32_lt(
++ mantiss,
++ dal_fixed31_32_zero) ||
++ dal_fixed31_32_lt(
++ dal_fixed31_32_one,
++ mantiss))
++ mantiss = dal_fixed31_32_zero;
++ else
++ mantiss = dal_fixed31_32_shl(
++ mantiss,
++ format->mantissa_bits);
++
++ *mantissa = dal_fixed31_32_floor(mantiss);
++
++ return true;
++}
++
++static bool setup_custom_float(
++ const struct custom_float_format *format,
++ bool negative,
++ uint32_t mantissa,
++ uint32_t exponenta,
++ uint32_t *result)
++{
++ uint32_t i = 0;
++ uint32_t j = 0;
++
++ uint32_t value = 0;
++
++ /* verification code:
++ * once calculation is ok we can remove it */
++
++ const uint32_t mantissa_mask =
++ (1 << (format->mantissa_bits + 1)) - 1;
++
++ const uint32_t exponenta_mask =
++ (1 << (format->exponenta_bits + 1)) - 1;
++
++ if (mantissa & ~mantissa_mask) {
++ BREAK_TO_DEBUGGER();
++ mantissa = mantissa_mask;
++ }
++
++ if (exponenta & ~exponenta_mask) {
++ BREAK_TO_DEBUGGER();
++ exponenta = exponenta_mask;
++ }
++
++ /* end of verification code */
++
++ while (i < format->mantissa_bits) {
++ uint32_t mask = 1 << i;
++
++ if (mantissa & mask)
++ value |= mask;
++
++ ++i;
++ }
++
++ while (j < format->exponenta_bits) {
++ uint32_t mask = 1 << j;
++
++ if (exponenta & mask)
++ value |= mask << i;
++
++ ++j;
++ }
++
++ if (negative && format->sign)
++ value |= 1 << (i + j);
++
++ *result = value;
++
++ return true;
++}
++
++static bool convert_to_custom_float_format(
++ struct fixed31_32 value,
++ const struct custom_float_format *format,
++ uint32_t *result)
++{
++ uint32_t mantissa;
++ uint32_t exponenta;
++ bool negative;
++
++ return build_custom_float(
++ value, format, &negative, &mantissa, &exponenta) &&
++ setup_custom_float(
++ format, negative, mantissa, exponenta, result);
++}
++
++static bool convert_to_custom_float_format_ex(
++ struct fixed31_32 value,
++ const struct custom_float_format *format,
++ struct custom_float_value *result)
++{
++ return build_custom_float(
++ value, format,
++ &result->negative, &result->mantissa, &result->exponenta) &&
++ setup_custom_float(
++ format, result->negative, result->mantissa, result->exponenta,
++ &result->value);
++}
++
++static bool convert_to_custom_float(
++ struct dce110_opp *opp110)
++{
++ struct custom_float_format fmt;
++
++ struct pwl_result_data *rgb = opp110->regamma.rgb_resulted;
++
++ uint32_t i = 0;
++
++ fmt.exponenta_bits = 6;
++ fmt.mantissa_bits = 12;
++ fmt.sign = true;
++
++ if (!convert_to_custom_float_format(
++ opp110->regamma.arr_points[0].x,
++ &fmt,
++ &opp110->regamma.arr_points[0].custom_float_x)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ opp110->regamma.arr_points[0].offset,
++ &fmt,
++ &opp110->regamma.arr_points[0].custom_float_offset)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ opp110->regamma.arr_points[0].slope,
++ &fmt,
++ &opp110->regamma.arr_points[0].custom_float_slope)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ fmt.mantissa_bits = 10;
++ fmt.sign = false;
++
++ if (!convert_to_custom_float_format(
++ opp110->regamma.arr_points[1].x,
++ &fmt,
++ &opp110->regamma.arr_points[1].custom_float_x)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ opp110->regamma.arr_points[1].y,
++ &fmt,
++ &opp110->regamma.arr_points[1].custom_float_y)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ opp110->regamma.arr_points[2].slope,
++ &fmt,
++ &opp110->regamma.arr_points[2].custom_float_slope)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ fmt.mantissa_bits = 12;
++ fmt.sign = true;
++
++ while (i != opp110->regamma.hw_points_num) {
++ if (!convert_to_custom_float_format(
++ rgb->red,
++ &fmt,
++ &rgb->red_reg)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ rgb->green,
++ &fmt,
++ &rgb->green_reg)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ rgb->blue,
++ &fmt,
++ &rgb->blue_reg)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ rgb->delta_red,
++ &fmt,
++ &rgb->delta_red_reg)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ rgb->delta_green,
++ &fmt,
++ &rgb->delta_green_reg)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!convert_to_custom_float_format(
++ rgb->delta_blue,
++ &fmt,
++ &rgb->delta_blue_reg)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ ++rgb;
++ ++i;
++ }
++
++ return true;
++}
++
++static bool round_custom_float_6_12(
++ struct hw_x_point *x)
++{
++ struct custom_float_format fmt;
++
++ struct custom_float_value value;
++
++ fmt.exponenta_bits = 6;
++ fmt.mantissa_bits = 12;
++ fmt.sign = true;
++
++ if (!convert_to_custom_float_format_ex(
++ x->x, &fmt, &value))
++ return false;
++
++ x->adjusted_x = x->x;
++
++ if (value.mantissa) {
++ BREAK_TO_DEBUGGER();
++
++ return false;
++ }
++
++ return true;
++}
++
++static bool build_hw_curve_configuration(
++ const struct curve_config *curve_config,
++ struct gamma_curve *gamma_curve,
++ struct curve_points *curve_points,
++ struct hw_x_point *points,
++ uint32_t *number_of_points)
++{
++ const int8_t max_regions_number = ARRAY_SIZE(curve_config->segments);
++
++ int8_t i;
++
++ uint8_t segments_calculation[8] = { 0 };
++
++ struct fixed31_32 region1 = dal_fixed31_32_zero;
++ struct fixed31_32 region2;
++ struct fixed31_32 increment;
++
++ uint32_t index = 0;
++ uint32_t segments = 0;
++ uint32_t max_number;
++
++ bool result = false;
++
++ if (!number_of_points) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ max_number = *number_of_points;
++
++ i = 0;
++
++ while (i != max_regions_number) {
++ gamma_curve[i].offset = 0;
++ gamma_curve[i].segments_num = 0;
++
++ ++i;
++ }
++
++ i = 0;
++
++ while (i != max_regions_number) {
++ /* number should go in uninterruptible sequence */
++ if (curve_config->segments[i] == -1)
++ break;
++
++ ASSERT(curve_config->segments[i] >= 0);
++
++ segments += (1 << curve_config->segments[i]);
++
++ ++i;
++ }
++
++ if (segments > max_number) {
++ BREAK_TO_DEBUGGER();
++ } else {
++ int32_t divisor;
++ uint32_t offset = 0;
++ int8_t begin = curve_config->begin;
++ int32_t region_number = 0;
++
++ i = begin;
++
++ while ((index < max_number) &&
++ (region_number < max_regions_number) &&
++ (i <= 1)) {
++ int32_t j = 0;
++
++ segments = curve_config->segments[region_number];
++ divisor = 1 << segments;
++
++ if (segments == -1) {
++ if (i > 0) {
++ region1 = dal_fixed31_32_shl(
++ dal_fixed31_32_one,
++ i - 1);
++ region2 = dal_fixed31_32_shl(
++ dal_fixed31_32_one,
++ i);
++ } else {
++ region1 = dal_fixed31_32_shr(
++ dal_fixed31_32_one,
++ -(i - 1));
++ region2 = dal_fixed31_32_shr(
++ dal_fixed31_32_one,
++ -i);
++ }
++
++ break;
++ }
++
++ if (i > -1) {
++ region1 = dal_fixed31_32_shl(
++ dal_fixed31_32_one,
++ i);
++ region2 = dal_fixed31_32_shl(
++ dal_fixed31_32_one,
++ i + 1);
++ } else {
++ region1 = dal_fixed31_32_shr(
++ dal_fixed31_32_one,
++ -i);
++ region2 = dal_fixed31_32_shr(
++ dal_fixed31_32_one,
++ -(i + 1));
++ }
++
++ gamma_curve[region_number].offset = offset;
++ gamma_curve[region_number].segments_num = segments;
++
++ offset += divisor;
++
++ ++segments_calculation[segments];
++
++ increment = dal_fixed31_32_div_int(
++ dal_fixed31_32_sub(
++ region2,
++ region1),
++ divisor);
++
++ points[index].x = region1;
++
++ round_custom_float_6_12(points + index);
++
++ ++index;
++ ++region_number;
++
++ while ((index < max_number) && (j < divisor - 1)) {
++ region1 = dal_fixed31_32_add(
++ region1,
++ increment);
++
++ points[index].x = region1;
++ points[index].adjusted_x = region1;
++
++ ++index;
++ ++j;
++ }
++
++ ++i;
++ }
++
++ points[index].x = region1;
++
++ round_custom_float_6_12(points + index);
++
++ *number_of_points = index;
++
++ result = true;
++ }
++
++ curve_points[0].x = points[0].adjusted_x;
++ curve_points[0].offset = dal_fixed31_32_zero;
++
++ curve_points[1].x = points[index - 1].adjusted_x;
++ curve_points[1].offset = dal_fixed31_32_zero;
++
++ curve_points[2].x = points[index].adjusted_x;
++ curve_points[2].offset = dal_fixed31_32_zero;
++
++ return result;
++}
++
++static bool setup_distribution_points(
++ struct dce110_opp *opp110)
++{
++ uint32_t hw_points_num = MAX_PWL_ENTRY * 2;
++
++ struct curve_config cfg;
++
++ cfg.offset = 0;
++
++ cfg.segments[0] = 3;
++ cfg.segments[1] = 4;
++ cfg.segments[2] = 4;
++ cfg.segments[3] = 4;
++ cfg.segments[4] = 4;
++ cfg.segments[5] = 4;
++ cfg.segments[6] = 4;
++ cfg.segments[7] = 4;
++ cfg.segments[8] = 5;
++ cfg.segments[9] = 5;
++ cfg.segments[10] = 0;
++ cfg.segments[11] = -1;
++ cfg.segments[12] = -1;
++ cfg.segments[13] = -1;
++ cfg.segments[14] = -1;
++ cfg.segments[15] = -1;
++
++ cfg.begin = -10;
++
++ if (!build_hw_curve_configuration(
++ &cfg, opp110->regamma.arr_curve_points,
++ opp110->regamma.arr_points,
++ opp110->regamma.coordinates_x, &hw_points_num)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ opp110->regamma.hw_points_num = hw_points_num;
++
++ return true;
++}
++
++
++/*
++ *****************************************************************************
++ * Function: regamma_config_regions_and_segments
++ *
++ * build regamma curve by using predefined hw points
++ * uses interface parameters ,like EDID coeff.
++ *
++ * @param : parameters interface parameters
++ * @return void
++ *
++ * @note
++ *
++ * @see
++ *
++ *****************************************************************************
++ */
++static void regamma_config_regions_and_segments(
++ struct dce110_opp *opp110)
++{
++ struct gamma_curve *curve;
++ uint32_t value = 0;
++
++ {
++ set_reg_field_value(
++ value,
++ opp110->regamma.arr_points[0].custom_float_x,
++ REGAMMA_CNTLA_START_CNTL,
++ REGAMMA_CNTLA_EXP_REGION_START);
++
++ set_reg_field_value(
++ value,
++ 0,
++ REGAMMA_CNTLA_START_CNTL,
++ REGAMMA_CNTLA_EXP_REGION_START_SEGMENT);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_START_CNTL),
++ value);
++ }
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ opp110->regamma.arr_points[0].custom_float_slope,
++ REGAMMA_CNTLA_SLOPE_CNTL,
++ REGAMMA_CNTLA_EXP_REGION_LINEAR_SLOPE);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_SLOPE_CNTL), value);
++ }
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ opp110->regamma.arr_points[1].custom_float_x,
++ REGAMMA_CNTLA_END_CNTL1,
++ REGAMMA_CNTLA_EXP_REGION_END);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_END_CNTL1), value);
++ }
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ opp110->regamma.arr_points[2].custom_float_slope,
++ REGAMMA_CNTLA_END_CNTL2,
++ REGAMMA_CNTLA_EXP_REGION_END_BASE);
++
++ set_reg_field_value(
++ value,
++ opp110->regamma.arr_points[1].custom_float_y,
++ REGAMMA_CNTLA_END_CNTL2,
++ REGAMMA_CNTLA_EXP_REGION_END_SLOPE);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_END_CNTL2), value);
++ }
++
++ curve = opp110->regamma.arr_curve_points;
++
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ curve[0].offset,
++ REGAMMA_CNTLA_REGION_0_1,
++ REGAMMA_CNTLA_EXP_REGION0_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[0].segments_num,
++ REGAMMA_CNTLA_REGION_0_1,
++ REGAMMA_CNTLA_EXP_REGION0_NUM_SEGMENTS);
++
++ set_reg_field_value(
++ value,
++ curve[1].offset,
++ REGAMMA_CNTLA_REGION_0_1,
++ REGAMMA_CNTLA_EXP_REGION1_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[1].segments_num,
++ REGAMMA_CNTLA_REGION_0_1,
++ REGAMMA_CNTLA_EXP_REGION1_NUM_SEGMENTS);
++
++ dal_write_reg(
++ opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_REGION_0_1),
++ value);
++ }
++
++ curve += 2;
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ curve[0].offset,
++ REGAMMA_CNTLA_REGION_2_3,
++ REGAMMA_CNTLA_EXP_REGION2_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[0].segments_num,
++ REGAMMA_CNTLA_REGION_2_3,
++ REGAMMA_CNTLA_EXP_REGION2_NUM_SEGMENTS);
++
++ set_reg_field_value(
++ value,
++ curve[1].offset,
++ REGAMMA_CNTLA_REGION_2_3,
++ REGAMMA_CNTLA_EXP_REGION3_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[1].segments_num,
++ REGAMMA_CNTLA_REGION_2_3,
++ REGAMMA_CNTLA_EXP_REGION3_NUM_SEGMENTS);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_REGION_2_3),
++ value);
++ }
++
++ curve += 2;
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ curve[0].offset,
++ REGAMMA_CNTLA_REGION_4_5,
++ REGAMMA_CNTLA_EXP_REGION4_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[0].segments_num,
++ REGAMMA_CNTLA_REGION_4_5,
++ REGAMMA_CNTLA_EXP_REGION4_NUM_SEGMENTS);
++
++ set_reg_field_value(
++ value,
++ curve[1].offset,
++ REGAMMA_CNTLA_REGION_4_5,
++ REGAMMA_CNTLA_EXP_REGION5_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[1].segments_num,
++ REGAMMA_CNTLA_REGION_4_5,
++ REGAMMA_CNTLA_EXP_REGION5_NUM_SEGMENTS);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_REGION_4_5),
++ value);
++ }
++
++ curve += 2;
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ curve[0].offset,
++ REGAMMA_CNTLA_REGION_6_7,
++ REGAMMA_CNTLA_EXP_REGION6_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[0].segments_num,
++ REGAMMA_CNTLA_REGION_6_7,
++ REGAMMA_CNTLA_EXP_REGION6_NUM_SEGMENTS);
++
++ set_reg_field_value(
++ value,
++ curve[1].offset,
++ REGAMMA_CNTLA_REGION_6_7,
++ REGAMMA_CNTLA_EXP_REGION7_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[1].segments_num,
++ REGAMMA_CNTLA_REGION_6_7,
++ REGAMMA_CNTLA_EXP_REGION7_NUM_SEGMENTS);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_REGION_6_7),
++ value);
++ }
++
++ curve += 2;
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ curve[0].offset,
++ REGAMMA_CNTLA_REGION_8_9,
++ REGAMMA_CNTLA_EXP_REGION8_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[0].segments_num,
++ REGAMMA_CNTLA_REGION_8_9,
++ REGAMMA_CNTLA_EXP_REGION8_NUM_SEGMENTS);
++
++ set_reg_field_value(
++ value,
++ curve[1].offset,
++ REGAMMA_CNTLA_REGION_8_9,
++ REGAMMA_CNTLA_EXP_REGION9_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[1].segments_num,
++ REGAMMA_CNTLA_REGION_8_9,
++ REGAMMA_CNTLA_EXP_REGION9_NUM_SEGMENTS);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_REGION_8_9),
++ value);
++ }
++
++ curve += 2;
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ curve[0].offset,
++ REGAMMA_CNTLA_REGION_10_11,
++ REGAMMA_CNTLA_EXP_REGION10_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[0].segments_num,
++ REGAMMA_CNTLA_REGION_10_11,
++ REGAMMA_CNTLA_EXP_REGION10_NUM_SEGMENTS);
++
++ set_reg_field_value(
++ value,
++ curve[1].offset,
++ REGAMMA_CNTLA_REGION_10_11,
++ REGAMMA_CNTLA_EXP_REGION11_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[1].segments_num,
++ REGAMMA_CNTLA_REGION_10_11,
++ REGAMMA_CNTLA_EXP_REGION11_NUM_SEGMENTS);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_REGION_10_11),
++ value);
++ }
++
++ curve += 2;
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ curve[0].offset,
++ REGAMMA_CNTLA_REGION_12_13,
++ REGAMMA_CNTLA_EXP_REGION12_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[0].segments_num,
++ REGAMMA_CNTLA_REGION_12_13,
++ REGAMMA_CNTLA_EXP_REGION12_NUM_SEGMENTS);
++
++ set_reg_field_value(
++ value,
++ curve[1].offset,
++ REGAMMA_CNTLA_REGION_12_13,
++ REGAMMA_CNTLA_EXP_REGION13_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[1].segments_num,
++ REGAMMA_CNTLA_REGION_12_13,
++ REGAMMA_CNTLA_EXP_REGION13_NUM_SEGMENTS);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_REGION_12_13),
++ value);
++ }
++
++ curve += 2;
++ {
++ value = 0;
++ set_reg_field_value(
++ value,
++ curve[0].offset,
++ REGAMMA_CNTLA_REGION_14_15,
++ REGAMMA_CNTLA_EXP_REGION14_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[0].segments_num,
++ REGAMMA_CNTLA_REGION_14_15,
++ REGAMMA_CNTLA_EXP_REGION14_NUM_SEGMENTS);
++
++ set_reg_field_value(
++ value,
++ curve[1].offset,
++ REGAMMA_CNTLA_REGION_14_15,
++ REGAMMA_CNTLA_EXP_REGION15_LUT_OFFSET);
++
++ set_reg_field_value(
++ value,
++ curve[1].segments_num,
++ REGAMMA_CNTLA_REGION_14_15,
++ REGAMMA_CNTLA_EXP_REGION15_NUM_SEGMENTS);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_CNTLA_REGION_14_15),
++ value);
++ }
++}
++
++static void program_pwl(
++ struct dce110_opp *opp110,
++ const struct gamma_parameters *params)
++{
++ uint32_t value;
++
++ {
++ uint8_t max_tries = 10;
++ uint8_t counter = 0;
++
++ /* Power on LUT memory */
++ value = dal_read_reg(opp110->base.ctx,
++ DCFE_REG(mmDCFE_MEM_PWR_CTRL));
++
++ set_reg_field_value(
++ value,
++ 1,
++ DCFE_MEM_PWR_CTRL,
++ DCP_REGAMMA_MEM_PWR_DIS);
++
++ dal_write_reg(opp110->base.ctx,
++ DCFE_REG(mmDCFE_MEM_PWR_CTRL), value);
++
++ while (counter < max_tries) {
++ value =
++ dal_read_reg(
++ opp110->base.ctx,
++ DCFE_REG(mmDCFE_MEM_PWR_STATUS));
++
++ if (get_reg_field_value(
++ value,
++ DCFE_MEM_PWR_STATUS,
++ DCP_REGAMMA_MEM_PWR_STATE) == 0)
++ break;
++
++ ++counter;
++ }
++
++ if (counter == max_tries) {
++ dal_logger_write(opp110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "%s: regamma lut was not powered on "
++ "in a timely manner,"
++ " programming still proceeds\n",
++ __func__);
++ }
++ }
++
++ value = 0;
++
++ set_reg_field_value(
++ value,
++ 7,
++ REGAMMA_LUT_WRITE_EN_MASK,
++ REGAMMA_LUT_WRITE_EN_MASK);
++
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_LUT_WRITE_EN_MASK), value);
++ dal_write_reg(opp110->base.ctx,
++ DCP_REG(mmREGAMMA_LUT_INDEX), 0);
++
++ /* Program REGAMMA_LUT_DATA */
++ {
++ const uint32_t addr = DCP_REG(mmREGAMMA_LUT_DATA);
++
++ uint32_t i = 0;
++
++ struct pwl_result_data *rgb =
++ opp110->regamma.rgb_resulted;
++
++ while (i != opp110->regamma.hw_points_num) {
++ dal_write_reg(opp110->base.ctx, addr, rgb->red_reg);
++ dal_write_reg(opp110->base.ctx, addr, rgb->green_reg);
++ dal_write_reg(opp110->base.ctx, addr, rgb->blue_reg);
++
++ dal_write_reg(opp110->base.ctx, addr,
++ rgb->delta_red_reg);
++ dal_write_reg(opp110->base.ctx, addr,
++ rgb->delta_green_reg);
++ dal_write_reg(opp110->base.ctx, addr,
++ rgb->delta_blue_reg);
++
++ ++rgb;
++ ++i;
++ }
++ }
++
++ /* we are done with DCP LUT memory; re-enable low power mode */
++ value = dal_read_reg(opp110->base.ctx, DCFE_REG(mmDCFE_MEM_PWR_CTRL));
++
++ set_reg_field_value(
++ value,
++ 0,
++ DCFE_MEM_PWR_CTRL,
++ DCP_REGAMMA_MEM_PWR_DIS);
++
++ dal_write_reg(opp110->base.ctx, DCFE_REG(mmDCFE_MEM_PWR_CTRL), value);
++}
++
++void dce110_opp_power_on_regamma_lut(
++ struct output_pixel_processor *opp,
++ bool power_on)
++{
++ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
++
++ uint32_t value =
++ dal_read_reg(opp->ctx, DCFE_REG(mmDCFE_MEM_PWR_CTRL));
++
++ set_reg_field_value(
++ value,
++ power_on,
++ DCFE_MEM_PWR_CTRL,
++ DCP_REGAMMA_MEM_PWR_DIS);
++
++ set_reg_field_value(
++ value,
++ power_on,
++ DCFE_MEM_PWR_CTRL,
++ DCP_LUT_MEM_PWR_DIS);
++
++ dal_write_reg(opp->ctx, DCFE_REG(mmDCFE_MEM_PWR_CTRL), value);
++}
++
++static bool scale_gamma(
++ struct dce110_opp *opp110,
++ const struct gamma_ramp *gamma_ramp,
++ const struct gamma_parameters *params)
++{
++ const struct gamma_ramp_rgb256x3x16 *gamma;
++ bool use_palette = params->surface_pixel_format == PIXEL_FORMAT_INDEX8;
++
++ const uint16_t max_driver = 0xFFFF;
++ const uint16_t max_os = 0xFF00;
++
++ uint16_t scaler = max_os;
++
++ uint32_t i;
++
++ struct dev_c_lut *palette = opp110->regamma.saved_palette;
++
++ struct pwl_float_data *rgb = opp110->regamma.rgb_user;
++ struct pwl_float_data *rgb_last = rgb + RGB_256X3X16 - 1;
++
++ if (gamma_ramp->type == GAMMA_RAMP_RBG256X3X16)
++ gamma = &gamma_ramp->gamma_ramp_rgb256x3x16;
++ else
++ return false; /* invalid option */
++
++ i = 0;
++
++ do {
++ if ((gamma->red[i] > max_os) ||
++ (gamma->green[i] > max_os) ||
++ (gamma->blue[i] > max_os)) {
++ scaler = max_driver;
++ break;
++ }
++ ++i;
++ } while (i != RGB_256X3X16);
++
++ i = 0;
++
++ if (use_palette)
++ do {
++ rgb->r = dal_fixed31_32_from_fraction(
++ gamma->red[palette->red], scaler);
++ rgb->g = dal_fixed31_32_from_fraction(
++ gamma->green[palette->green], scaler);
++ rgb->b = dal_fixed31_32_from_fraction(
++ gamma->blue[palette->blue], scaler);
++
++ ++palette;
++ ++rgb;
++ ++i;
++ } while (i != RGB_256X3X16);
++ else
++ do {
++ rgb->r = dal_fixed31_32_from_fraction(
++ gamma->red[i], scaler);
++ rgb->g = dal_fixed31_32_from_fraction(
++ gamma->green[i], scaler);
++ rgb->b = dal_fixed31_32_from_fraction(
++ gamma->blue[i], scaler);
++
++ ++rgb;
++ ++i;
++ } while (i != RGB_256X3X16);
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ opp110->regamma.divider1);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ opp110->regamma.divider1);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ opp110->regamma.divider1);
++
++ ++rgb;
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ opp110->regamma.divider2);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ opp110->regamma.divider2);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ opp110->regamma.divider2);
++
++ ++rgb;
++
++ rgb->r = dal_fixed31_32_mul(rgb_last->r,
++ opp110->regamma.divider3);
++ rgb->g = dal_fixed31_32_mul(rgb_last->g,
++ opp110->regamma.divider3);
++ rgb->b = dal_fixed31_32_mul(rgb_last->b,
++ opp110->regamma.divider3);
++
++ return true;
++}
++
++
++static void configure_regamma_mode(
++ struct dce110_opp *opp110,
++ const struct gamma_parameters *params,
++ bool force_bypass)
++{
++ const uint32_t addr = DCP_REG(mmREGAMMA_CONTROL);
++
++ enum wide_gamut_regamma_mode mode =
++ WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_MATRIX_A;
++
++ uint32_t value = dal_read_reg(opp110->base.ctx, addr);
++
++ if (force_bypass) {
++
++ set_reg_field_value(
++ value,
++ 0,
++ REGAMMA_CONTROL,
++ GRPH_REGAMMA_MODE);
++
++ dal_write_reg(opp110->base.ctx, addr, value);
++
++ return;
++ }
++
++ if (params->regamma_adjust_type == GRAPHICS_REGAMMA_ADJUST_BYPASS)
++ mode = WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_BYPASS;
++ else if (params->regamma_adjust_type == GRAPHICS_REGAMMA_ADJUST_HW) {
++ if (params->surface_pixel_format == PIXEL_FORMAT_FP16)
++ mode = WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_BYPASS;
++ else
++ mode = WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_SRGB24;
++ }
++
++ switch (mode) {
++ case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_BYPASS:
++ set_reg_field_value(
++ value,
++ 0,
++ REGAMMA_CONTROL,
++ GRPH_REGAMMA_MODE);
++ break;
++ case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_SRGB24:
++ set_reg_field_value(
++ value,
++ 1,
++ REGAMMA_CONTROL,
++ GRPH_REGAMMA_MODE);
++ break;
++ case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_XYYCC22:
++ set_reg_field_value(
++ value,
++ 2,
++ REGAMMA_CONTROL,
++ GRPH_REGAMMA_MODE);
++ break;
++ case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_MATRIX_A:
++ set_reg_field_value(
++ value,
++ 3,
++ REGAMMA_CONTROL,
++ GRPH_REGAMMA_MODE);
++ break;
++ case WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_MATRIX_B:
++ set_reg_field_value(
++ value,
++ 4,
++ REGAMMA_CONTROL,
++ GRPH_REGAMMA_MODE);
++ break;
++ default:
++ break;
++ }
++
++ dal_write_reg(opp110->base.ctx, addr, value);
++}
++
++bool dce110_opp_set_regamma(
++ struct output_pixel_processor *opp,
++ const struct gamma_ramp *ramp,
++ const struct gamma_parameters *params,
++ bool force_bypass)
++{
++ struct dce110_opp *opp110 = TO_DCE110_OPP(opp);
++
++ if (force_bypass) {
++ configure_regamma_mode(opp110, params, true);
++ } else {
++ /* 1. Scale gamma to 0 - 1 to m_pRgbUser */
++ if (!scale_gamma(opp110, ramp, params)) {
++ ASSERT_CRITICAL(false);
++ /* invalid option */
++ return false;
++ }
++
++ /* 2. Configure regamma curve without analysis (future task) */
++ /* and program the PWL regions and segments */
++ if (params->regamma_adjust_type == GRAPHICS_REGAMMA_ADJUST_SW ||
++ params->surface_pixel_format == PIXEL_FORMAT_FP16) {
++
++ /* 3. Setup x exponentially distributed points */
++ if (!setup_distribution_points(opp110)) {
++ ASSERT_CRITICAL(false);
++ /* invalid option */
++ return false;
++ }
++
++ /* 4. Build ideal regamma curve */
++ if (!build_regamma_curve(opp110, params)) {
++ ASSERT_CRITICAL(false);
++ /* invalid parameters or bug */
++ return false;
++ }
++
++ /* 5. Map user gamma (evenly distributed x points) to
++ * new curve when x is y from ideal regamma , step 5 */
++ if (!map_regamma_hw_to_x_user(
++ opp110, ramp, params)) {
++ ASSERT_CRITICAL(false);
++ /* invalid parameters or bug */
++ return false;
++ }
++
++ /* 6.Build and verify resulted curve */
++ build_new_custom_resulted_curve(opp110, params);
++
++ /* 7. Build and translate x to hw format */
++ if (!rebuild_curve_configuration_magic(opp110)) {
++ ASSERT_CRITICAL(false);
++ /* invalid parameters or bug */
++ return false;
++ }
++
++ /* 8. convert all params to the custom float format */
++ if (!convert_to_custom_float(opp110)) {
++ ASSERT_CRITICAL(false);
++ /* invalid parameters or bug */
++ return false;
++ }
++
++ /* 9. program regamma curve configuration */
++ regamma_config_regions_and_segments(opp110);
++
++ /* 10. Program PWL */
++ program_pwl(opp110, params);
++ }
++
++ /*
++ * 11. program regamma config
++ */
++ configure_regamma_mode(opp110, params, false);
++ }
++ return true;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
+new file mode 100644
+index 0000000..d2594a9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.c
+@@ -0,0 +1,1276 @@
++/*
++* 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 "dc_services.h"
++
++#include "resource.h"
++#include "include/irq_service_interface.h"
++#include "dce110/dce110_timing_generator.h"
++#include "dce110/dce110_link_encoder.h"
++#include "dce110/dce110_mem_input.h"
++#include "dce110/dce110_ipp.h"
++#include "dce110/dce110_transform.h"
++#include "dce110/dce110_stream_encoder.h"
++#include "dce110/dce110_opp.h"
++#include "link_encoder_types.h"
++#include "stream_encoder_types.h"
++
++enum dce110_clk_src_array_id {
++ DCE110_CLK_SRC_PLL0 = 0,
++ DCE110_CLK_SRC_PLL1,
++ DCE110_CLK_SRC_EXT,
++
++ DCE110_CLK_SRC_TOTAL
++};
++
++static void set_vendor_info_packet(struct core_stream *stream,
++ struct hw_info_packet *info_packet)
++{
++ uint32_t length = 0;
++ bool hdmi_vic_mode = false;
++ uint8_t checksum = 0;
++ uint32_t i = 0;
++ enum dc_timing_3d_format format;
++
++ ASSERT_CRITICAL(stream != NULL);
++ ASSERT_CRITICAL(info_packet != NULL);
++
++ format = stream->public.timing.timing_3d_format;
++
++ /* Can be different depending on packet content */
++ length = 5;
++
++ if (stream->public.timing.hdmi_vic != 0
++ && stream->public.timing.h_total >= 3840
++ && stream->public.timing.v_total >= 2160)
++ hdmi_vic_mode = true;
++
++ /* According to HDMI 1.4a CTS, VSIF should be sent
++ * for both 3D stereo and HDMI VIC modes.
++ * For all other modes, there is no VSIF sent. */
++
++ if (format == TIMING_3D_FORMAT_NONE && !hdmi_vic_mode)
++ return;
++
++ /* 24bit IEEE Registration identifier (0x000c03). LSB first. */
++ info_packet->sb[1] = 0x03;
++ info_packet->sb[2] = 0x0C;
++ info_packet->sb[3] = 0x00;
++
++ /*PB4: 5 lower bytes = 0 (reserved). 3 higher bits = HDMI_Video_Format.
++ * The value for HDMI_Video_Format are:
++ * 0x0 (0b000) - No additional HDMI video format is presented in this
++ * packet
++ * 0x1 (0b001) - Extended resolution format present. 1 byte of HDMI_VIC
++ * parameter follows
++ * 0x2 (0b010) - 3D format indication present. 3D_Structure and
++ * potentially 3D_Ext_Data follows
++ * 0x3..0x7 (0b011..0b111) - reserved for future use */
++ if (format != TIMING_3D_FORMAT_NONE)
++ info_packet->sb[4] = (2 << 5);
++ else if (hdmi_vic_mode)
++ info_packet->sb[4] = (1 << 5);
++
++ /* PB5: If PB4 claims 3D timing (HDMI_Video_Format = 0x2):
++ * 4 lower bites = 0 (reserved). 4 higher bits = 3D_Structure.
++ * The value for 3D_Structure are:
++ * 0x0 - Frame Packing
++ * 0x1 - Field Alternative
++ * 0x2 - Line Alternative
++ * 0x3 - Side-by-Side (full)
++ * 0x4 - L + depth
++ * 0x5 - L + depth + graphics + graphics-depth
++ * 0x6 - Top-and-Bottom
++ * 0x7 - Reserved for future use
++ * 0x8 - Side-by-Side (Half)
++ * 0x9..0xE - Reserved for future use
++ * 0xF - Not used */
++ switch (format) {
++ case TIMING_3D_FORMAT_HW_FRAME_PACKING:
++ case TIMING_3D_FORMAT_SW_FRAME_PACKING:
++ info_packet->sb[5] = (0x0 << 4);
++ break;
++
++ case TIMING_3D_FORMAT_SIDE_BY_SIDE:
++ case TIMING_3D_FORMAT_SBS_SW_PACKED:
++ info_packet->sb[5] = (0x8 << 4);
++ length = 6;
++ break;
++
++ case TIMING_3D_FORMAT_TOP_AND_BOTTOM:
++ case TIMING_3D_FORMAT_TB_SW_PACKED:
++ info_packet->sb[5] = (0x6 << 4);
++ break;
++
++ default:
++ break;
++ }
++
++ /*PB5: If PB4 is set to 0x1 (extended resolution format)
++ * fill PB5 with the correct HDMI VIC code */
++ if (hdmi_vic_mode)
++ info_packet->sb[5] = stream->public.timing.hdmi_vic;
++
++ /* Header */
++ info_packet->hb0 = 0x81; /* VSIF packet type. */
++ info_packet->hb1 = 0x01; /* Version */
++
++ /* 4 lower bits = Length, 4 higher bits = 0 (reserved) */
++ info_packet->hb2 = (uint8_t) (length);
++
++ /* Calculate checksum */
++ checksum = 0;
++ checksum += info_packet->hb0;
++ checksum += info_packet->hb1;
++ checksum += info_packet->hb2;
++
++ for (i = 1; i <= length; i++)
++ checksum += info_packet->sb[i];
++
++ info_packet->sb[0] = (uint8_t) (0x100 - checksum);
++
++ info_packet->valid = true;
++}
++
++static enum ds_color_space build_default_color_space(
++ struct core_stream *stream)
++{
++ enum ds_color_space color_space =
++ DS_COLOR_SPACE_SRGB_FULLRANGE;
++ struct dc_crtc_timing *timing = &stream->public.timing;
++
++ switch (stream->signal) {
++ /* TODO: implement other signal color space setting */
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ break;
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ {
++ uint32_t pix_clk_khz;
++
++ if (timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 &&
++ timing->pixel_encoding == PIXEL_ENCODING_YCBCR444) {
++ if (timing->timing_standard ==
++ TIMING_STANDARD_CEA770 &&
++ timing->timing_standard ==
++ TIMING_STANDARD_CEA861)
++ color_space = DS_COLOR_SPACE_SRGB_FULLRANGE;
++
++ pix_clk_khz = timing->pix_clk_khz / 10;
++ if (timing->h_addressable == 640 &&
++ timing->v_addressable == 480 &&
++ (pix_clk_khz == 2520 || pix_clk_khz == 2517))
++ color_space = DS_COLOR_SPACE_SRGB_FULLRANGE;
++ } else {
++ if (timing->timing_standard ==
++ TIMING_STANDARD_CEA770 ||
++ timing->timing_standard ==
++ TIMING_STANDARD_CEA861) {
++
++ color_space =
++ (timing->pix_clk_khz > PIXEL_CLOCK) ?
++ DS_COLOR_SPACE_YCBCR709 :
++ DS_COLOR_SPACE_YCBCR601;
++ }
++ }
++ break;
++ }
++ default:
++ switch (timing->pixel_encoding) {
++ case PIXEL_ENCODING_YCBCR422:
++ case PIXEL_ENCODING_YCBCR444:
++ if (timing->pix_clk_khz > PIXEL_CLOCK)
++ color_space = DS_COLOR_SPACE_YCBCR709;
++ else
++ color_space = DS_COLOR_SPACE_YCBCR601;
++ break;
++ default:
++ break;
++ }
++ break;
++ }
++ return color_space;
++}
++
++static void set_avi_info_frame(struct hw_info_packet *info_packet,
++ struct core_stream *stream)
++{
++ enum ds_color_space color_space = DS_COLOR_SPACE_UNKNOWN;
++ struct info_frame info_frame = { {0} };
++ uint32_t pixel_encoding = 0;
++ enum scanning_type scan_type = SCANNING_TYPE_NODATA;
++ enum dc_aspect_ratio aspect = ASPECT_RATIO_NO_DATA;
++ bool itc = false;
++ uint8_t cn0_cn1 = 0;
++ uint8_t *check_sum = NULL;
++ uint8_t byte_index = 0;
++
++ if (info_packet == NULL)
++ return;
++
++ color_space = build_default_color_space(stream);
++
++ /* Initialize header */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.header.
++ info_frame_type = INFO_FRAME_AVI;
++ /* InfoFrameVersion_3 is defined by CEA861F (Section 6.4), but shall
++ * not be used in HDMI 2.0 (Section 10.1) */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.header.version =
++ INFO_FRAME_VERSION_2;
++ info_frame.avi_info_packet.info_packet_hdmi.bits.header.length =
++ INFO_FRAME_SIZE_AVI;
++
++ /* IDO-defined (Y2,Y1,Y0 = 1,1,1) shall not be used by devices built
++ * according to HDMI 2.0 spec (Section 10.1)
++ * Add "case PixelEncoding_YCbCr420: pixelEncoding = 3; break;"
++ * when YCbCr 4:2:0 is supported by DAL hardware. */
++
++ switch (stream->public.timing.pixel_encoding) {
++ case PIXEL_ENCODING_YCBCR422:
++ pixel_encoding = 1;
++ break;
++
++ case PIXEL_ENCODING_YCBCR444:
++ pixel_encoding = 2;
++ break;
++
++ case PIXEL_ENCODING_RGB:
++ default:
++ pixel_encoding = 0;
++ }
++
++ /* Y0_Y1_Y2 : The pixel encoding */
++ /* H14b AVI InfoFrame has extension on Y-field from 2 bits to 3 bits */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.Y0_Y1_Y2 =
++ pixel_encoding;
++
++
++ /* A0 = 1 Active Format Information valid */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.A0 =
++ ACTIVE_FORMAT_VALID;
++
++ /* B0, B1 = 3; Bar info data is valid */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.B0_B1 =
++ BAR_INFO_BOTH_VALID;
++
++ info_frame.avi_info_packet.info_packet_hdmi.bits.SC0_SC1 =
++ PICTURE_SCALING_UNIFORM;
++
++ /* S0, S1 : Underscan / Overscan */
++ /* TODO: un-hardcode scan type */
++ scan_type = SCANNING_TYPE_UNDERSCAN;
++ info_frame.avi_info_packet.info_packet_hdmi.bits.S0_S1 = scan_type;
++
++ /* C0, C1 : Colorimetry */
++ if (color_space == DS_COLOR_SPACE_YCBCR709)
++ info_frame.avi_info_packet.info_packet_hdmi.bits.C0_C1 =
++ COLORIMETRY_ITU709;
++ else if (color_space == DS_COLOR_SPACE_YCBCR601)
++ info_frame.avi_info_packet.info_packet_hdmi.bits.C0_C1 =
++ COLORIMETRY_ITU601;
++ else
++ info_frame.avi_info_packet.info_packet_hdmi.bits.C0_C1 =
++ COLORIMETRY_NO_DATA;
++
++
++ /* TODO: un-hardcode aspect ratio */
++ aspect = stream->public.timing.aspect_ratio;
++
++ switch (aspect) {
++ case ASPECT_RATIO_4_3:
++ case ASPECT_RATIO_16_9:
++ info_frame.avi_info_packet.info_packet_hdmi.bits.M0_M1 = aspect;
++ break;
++
++ case ASPECT_RATIO_NO_DATA:
++ case ASPECT_RATIO_64_27:
++ case ASPECT_RATIO_256_135:
++ default:
++ info_frame.avi_info_packet.info_packet_hdmi.bits.M0_M1 = 0;
++ }
++
++ /* Active Format Aspect ratio - same as Picture Aspect Ratio. */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.R0_R3 =
++ ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE;
++
++ /* TODO: un-hardcode cn0_cn1 and itc */
++ cn0_cn1 = 0;
++ itc = false;
++
++ if (itc) {
++ info_frame.avi_info_packet.info_packet_hdmi.bits.ITC = 1;
++ info_frame.avi_info_packet.info_packet_hdmi.bits.CN0_CN1 =
++ cn0_cn1;
++ }
++
++ /* TODO: un-hardcode q0_q1 */
++ if (color_space == DS_COLOR_SPACE_SRGB_FULLRANGE)
++ info_frame.avi_info_packet.info_packet_hdmi.bits.Q0_Q1 =
++ RGB_QUANTIZATION_FULL_RANGE;
++ else if (color_space == DS_COLOR_SPACE_SRGB_LIMITEDRANGE)
++ info_frame.avi_info_packet.info_packet_hdmi.bits.Q0_Q1 =
++ RGB_QUANTIZATION_LIMITED_RANGE;
++ else
++ info_frame.avi_info_packet.info_packet_hdmi.bits.Q0_Q1 =
++ RGB_QUANTIZATION_DEFAULT_RANGE;
++
++ /* TODO : We should handle YCC quantization,
++ * but we do not have matrix calculation */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.YQ0_YQ1 =
++ YYC_QUANTIZATION_LIMITED_RANGE;
++
++ info_frame.avi_info_packet.info_packet_hdmi.bits.VIC0_VIC7 =
++ stream->public.timing.vic;
++
++ /* pixel repetition
++ * PR0 - PR3 start from 0 whereas pHwPathMode->mode.timing.flags.pixel
++ * repetition start from 1 */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.PR0_PR3 = 0;
++
++ /* Bar Info
++ * barTop: Line Number of End of Top Bar.
++ * barBottom: Line Number of Start of Bottom Bar.
++ * barLeft: Pixel Number of End of Left Bar.
++ * barRight: Pixel Number of Start of Right Bar. */
++ info_frame.avi_info_packet.info_packet_hdmi.bits.bar_top =
++ stream->public.timing.v_border_top;
++ info_frame.avi_info_packet.info_packet_hdmi.bits.bar_bottom =
++ (stream->public.timing.v_border_top
++ - stream->public.timing.v_border_bottom + 1);
++ info_frame.avi_info_packet.info_packet_hdmi.bits.bar_left =
++ stream->public.timing.h_border_left;
++ info_frame.avi_info_packet.info_packet_hdmi.bits.bar_right =
++ (stream->public.timing.h_total
++ - stream->public.timing.h_border_right + 1);
++
++ /* check_sum - Calculate AFMT_AVI_INFO0 ~ AFMT_AVI_INFO3 */
++ check_sum =
++ &info_frame.
++ avi_info_packet.info_packet_hdmi.packet_raw_data.sb[0];
++ *check_sum = INFO_FRAME_AVI + INFO_FRAME_SIZE_AVI
++ + INFO_FRAME_VERSION_2;
++
++ for (byte_index = 1; byte_index <= INFO_FRAME_SIZE_AVI; byte_index++)
++ *check_sum += info_frame.avi_info_packet.info_packet_hdmi.
++ packet_raw_data.sb[byte_index];
++
++ /* one byte complement */
++ *check_sum = (uint8_t) (0x100 - *check_sum);
++
++ /* Store in hw_path_mode */
++ info_packet->hb0 =
++ info_frame.avi_info_packet.info_packet_hdmi.packet_raw_data.hb0;
++ info_packet->hb1 =
++ info_frame.avi_info_packet.info_packet_hdmi.packet_raw_data.hb1;
++ info_packet->hb2 =
++ info_frame.avi_info_packet.info_packet_hdmi.packet_raw_data.hb2;
++
++ for (byte_index = 0; byte_index < sizeof(info_packet->sb); byte_index++)
++ info_packet->sb[byte_index] = info_frame.avi_info_packet.
++ info_packet_hdmi.packet_raw_data.sb[byte_index];
++
++ info_packet->valid = true;
++}
++
++static void translate_info_frame(const struct hw_info_frame *hw_info_frame,
++ struct encoder_info_frame *encoder_info_frame)
++{
++ dc_service_memset(
++ encoder_info_frame, 0, sizeof(struct encoder_info_frame));
++
++ /* For gamut we recalc checksum */
++ if (hw_info_frame->gamut_packet.valid) {
++ uint8_t chk_sum = 0;
++ uint8_t *ptr;
++ uint8_t i;
++
++ dc_service_memmove(
++ &encoder_info_frame->gamut,
++ &hw_info_frame->gamut_packet,
++ sizeof(struct hw_info_packet));
++
++ /*start of the Gamut data. */
++ ptr = &encoder_info_frame->gamut.sb[3];
++
++ for (i = 0; i <= encoder_info_frame->gamut.sb[1]; i++)
++ chk_sum += ptr[i];
++
++ encoder_info_frame->gamut.sb[2] = (uint8_t) (0x100 - chk_sum);
++ }
++
++ if (hw_info_frame->avi_info_packet.valid) {
++ dc_service_memmove(
++ &encoder_info_frame->avi,
++ &hw_info_frame->avi_info_packet,
++ sizeof(struct hw_info_packet));
++ }
++
++ if (hw_info_frame->vendor_info_packet.valid) {
++ dc_service_memmove(
++ &encoder_info_frame->vendor,
++ &hw_info_frame->vendor_info_packet,
++ sizeof(struct hw_info_packet));
++ }
++
++ if (hw_info_frame->spd_packet.valid) {
++ dc_service_memmove(
++ &encoder_info_frame->spd,
++ &hw_info_frame->spd_packet,
++ sizeof(struct hw_info_packet));
++ }
++
++ if (hw_info_frame->vsc_packet.valid) {
++ dc_service_memmove(
++ &encoder_info_frame->vsc,
++ &hw_info_frame->vsc_packet,
++ sizeof(struct hw_info_packet));
++ }
++}
++
++static void build_info_frame(struct core_stream *stream)
++{
++ enum signal_type signal = SIGNAL_TYPE_NONE;
++ struct hw_info_frame info_frame = { { 0 } };
++
++ /* default all packets to invalid */
++ info_frame.avi_info_packet.valid = false;
++ info_frame.gamut_packet.valid = false;
++ info_frame.vendor_info_packet.valid = false;
++ info_frame.spd_packet.valid = false;
++ info_frame.vsc_packet.valid = false;
++
++ signal = stream->sink->public.sink_signal;
++
++ /* HDMi and DP have different info packets*/
++ if (signal == SIGNAL_TYPE_HDMI_TYPE_A) {
++ set_avi_info_frame(&info_frame.avi_info_packet,
++ stream);
++ set_vendor_info_packet(stream, &info_frame.vendor_info_packet);
++ }
++
++ translate_info_frame(&info_frame,
++ &stream->encoder_info_frame);
++}
++
++
++bool dce110_construct_resource_pool(
++ struct adapter_service *adapter_serv,
++ struct dc *dc,
++ struct resource_pool *pool)
++{
++ unsigned int i;
++ struct clock_source_init_data clk_src_init_data = { 0 };
++ struct audio_init_data audio_init_data = { 0 };
++ struct dc_context *ctx = dc->ctx;
++ pool->adapter_srv = adapter_serv;
++
++ pool->stream_engines.engine.ENGINE_ID_DIGA = 1;
++ pool->stream_engines.engine.ENGINE_ID_DIGB = 1;
++ pool->stream_engines.engine.ENGINE_ID_DIGC = 1;
++
++ clk_src_init_data.as = adapter_serv;
++ clk_src_init_data.ctx = ctx;
++ clk_src_init_data.clk_src_id.enum_id = ENUM_ID_1;
++ clk_src_init_data.clk_src_id.type = OBJECT_TYPE_CLOCK_SOURCE;
++ pool->clk_src_count = DCE110_CLK_SRC_TOTAL;
++
++ clk_src_init_data.clk_src_id.id = CLOCK_SOURCE_ID_PLL0;
++ pool->clock_sources[DCE110_CLK_SRC_PLL0] = dal_clock_source_create(
++ &clk_src_init_data);
++ clk_src_init_data.clk_src_id.id = CLOCK_SOURCE_ID_PLL1;
++ pool->clock_sources[DCE110_CLK_SRC_PLL1] = dal_clock_source_create(
++ &clk_src_init_data);
++ clk_src_init_data.clk_src_id.id = CLOCK_SOURCE_ID_EXTERNAL;
++ pool->clock_sources[DCE110_CLK_SRC_EXT] = dal_clock_source_create(
++ &clk_src_init_data);
++
++ for (i = 0; i < pool->clk_src_count; i++) {
++ if (pool->clock_sources[i] == NULL) {
++ dal_error("DC: failed to create clock sources!\n");
++ BREAK_TO_DEBUGGER();
++ goto clk_src_create_fail;
++ }
++ }
++
++ pool->display_clock = dal_display_clock_dce110_create(ctx, adapter_serv);
++ if (pool->display_clock == NULL) {
++ dal_error("DC: failed to create display clock!\n");
++ BREAK_TO_DEBUGGER();
++ goto disp_clk_create_fail;
++ }
++
++ {
++ struct irq_service_init_data init_data;
++ init_data.ctx = dc->ctx;
++ pool->irqs = dal_irq_service_create(
++ dal_adapter_service_get_dce_version(
++ dc->res_pool.adapter_srv),
++ &init_data);
++ if (!pool->irqs)
++ goto irqs_create_fail;
++
++ }
++
++ pool->controller_count =
++ dal_adapter_service_get_func_controllers_num(adapter_serv);
++ pool->stream_enc_count = 3;
++ pool->scaler_filter = dal_scaler_filter_create(ctx);
++ if (pool->scaler_filter == NULL) {
++ BREAK_TO_DEBUGGER();
++ dal_error("DC: failed to create filter!\n");
++ goto filter_create_fail;
++ }
++
++ for (i = 0; i < pool->controller_count; i++) {
++ pool->timing_generators[i] = dce110_timing_generator_create(
++ adapter_serv,
++ ctx,
++ i + 1);
++ if (pool->timing_generators[i] == NULL) {
++ BREAK_TO_DEBUGGER();
++ dal_error("DC: failed to create tg!\n");
++ goto controller_create_fail;
++ }
++
++ pool->mis[i] = dce110_mem_input_create(
++ ctx,
++ i + 1);
++ if (pool->mis[i] == NULL) {
++ BREAK_TO_DEBUGGER();
++ dal_error(
++ "DC: failed to create memory input!\n");
++ goto controller_create_fail;
++ }
++
++ pool->ipps[i] = dce110_ipp_create(
++ ctx,
++ i + 1);
++ if (pool->ipps[i] == NULL) {
++ BREAK_TO_DEBUGGER();
++ dal_error(
++ "DC: failed to create input pixel processor!\n");
++ goto controller_create_fail;
++ }
++
++ pool->transforms[i] = dce110_transform_create(
++ ctx,
++ i + 1);
++ if (pool->transforms[i] == NULL) {
++ BREAK_TO_DEBUGGER();
++ dal_error(
++ "DC: failed to create transform!\n");
++ goto controller_create_fail;
++ }
++ dce110_transform_set_scaler_filter(
++ pool->transforms[i],
++ pool->scaler_filter);
++
++ pool->opps[i] = dce110_opp_create(
++ ctx,
++ i + 1);
++ if (pool->opps[i] == NULL) {
++ BREAK_TO_DEBUGGER();
++ dal_error(
++ "DC: failed to create output pixel processor!\n");
++ goto controller_create_fail;
++ }
++ }
++
++ audio_init_data.as = adapter_serv;
++ audio_init_data.ctx = ctx;
++ pool->audio_count = 0;
++ for (i = 0; i < pool->controller_count; i++) {
++ struct graphics_object_id obj_id;
++
++ obj_id = dal_adapter_service_enum_audio_object(adapter_serv, i);
++ if (false == dal_graphics_object_id_is_valid(obj_id)) {
++ /* no more valid audio objects */
++ break;
++ }
++
++ audio_init_data.audio_stream_id = obj_id;
++ pool->audios[i] = dal_audio_create(&audio_init_data);
++ if (pool->audios[i] == NULL) {
++ BREAK_TO_DEBUGGER();
++ dal_error("DC: failed to create DPPs!\n");
++ goto audio_create_fail;
++ }
++ pool->audio_count++;
++ }
++
++ for (i = 0; i < pool->stream_enc_count; i++) {
++ struct stream_enc_init_data enc_init_data = { 0 };
++ /* TODO: rework fragile code*/
++ enc_init_data.stream_engine_id = i;
++ enc_init_data.adapter_service = adapter_serv;
++ enc_init_data.ctx = dc->ctx;
++ if (pool->stream_engines.u_all & 1 << i) {
++ pool->stream_enc[i] = dce110_stream_encoder_create(
++ &enc_init_data);
++
++ if (pool->stream_enc[i] == NULL) {
++ BREAK_TO_DEBUGGER();
++ dal_error("DC: failed to create stream_encoder!\n");
++ goto stream_enc_create_fail;
++ }
++ }
++ }
++
++ return true;
++
++stream_enc_create_fail:
++ for (i = 0; i < pool->stream_enc_count; i++) {
++ if (pool->stream_enc[i] != NULL)
++ dce110_stream_encoder_destroy(&pool->stream_enc[i]);
++ }
++
++audio_create_fail:
++ for (i = 0; i < pool->controller_count; i++) {
++ if (pool->audios[i] != NULL)
++ dal_audio_destroy(&pool->audios[i]);
++ }
++
++controller_create_fail:
++ for (i = 0; i < pool->controller_count; i++) {
++ if (pool->opps[i] != NULL)
++ dce110_opp_destroy(&pool->opps[i]);
++
++ if (pool->transforms[i] != NULL)
++ dce110_transform_destroy(&pool->transforms[i]);
++
++ if (pool->ipps[i] != NULL)
++ dce110_ipp_destroy(&pool->ipps[i]);
++
++ if (pool->mis[i] != NULL)
++ dce110_mem_input_destroy(&pool->mis[i]);
++
++ if (pool->timing_generators[i] != NULL)
++ dce110_timing_generator_destroy(
++ &pool->timing_generators[i]);
++ }
++
++filter_create_fail:
++ dal_irq_service_destroy(&pool->irqs);
++
++irqs_create_fail:
++ dal_display_clock_destroy(&pool->display_clock);
++
++disp_clk_create_fail:
++clk_src_create_fail:
++ for (i = 0; i < pool->clk_src_count; i++) {
++ if (pool->clock_sources[i] != NULL)
++ dal_clock_source_destroy(&pool->clock_sources[i]);
++ }
++ return false;
++}
++
++void dce110_destruct_resource_pool(struct resource_pool *pool)
++{
++ unsigned int i;
++
++ for (i = 0; i < pool->controller_count; i++) {
++ if (pool->opps[i] != NULL)
++ dce110_opp_destroy(&pool->opps[i]);
++
++ if (pool->transforms[i] != NULL)
++ dce110_transform_destroy(&pool->transforms[i]);
++
++ if (pool->ipps[i] != NULL)
++ dce110_ipp_destroy(&pool->ipps[i]);
++
++ if (pool->mis[i] != NULL)
++ dce110_mem_input_destroy(&pool->mis[i]);
++
++ if (pool->timing_generators[i] != NULL)
++ dce110_timing_generator_destroy(
++ &pool->timing_generators[i]);
++ }
++
++ for (i = 0; i < pool->stream_enc_count; i++) {
++ if (pool->stream_enc[i] != NULL)
++ dce110_stream_encoder_destroy(&pool->stream_enc[i]);
++ }
++
++ for (i = 0; i < pool->clk_src_count; i++) {
++ if (pool->clock_sources[i] != NULL) {
++ dal_clock_source_destroy(&pool->clock_sources[i]);
++ }
++ }
++
++ for (i = 0; i < pool->audio_count; i++) {
++ if (pool->audios[i] != NULL) {
++ dal_audio_destroy(&pool->audios[i]);
++ }
++ }
++ if (pool->display_clock != NULL) {
++ dal_display_clock_destroy(&pool->display_clock);
++ }
++
++ if (pool->scaler_filter != NULL) {
++ dal_scaler_filter_destroy(&pool->scaler_filter);
++ }
++ if (pool->irqs != NULL) {
++ dal_irq_service_destroy(&pool->irqs);
++ }
++
++ if (pool->adapter_srv != NULL) {
++ dal_adapter_service_destroy(&pool->adapter_srv);
++ }
++}
++
++static void attach_stream_to_controller(
++ struct resource_context *res_ctx,
++ struct core_stream *stream)
++{
++ res_ctx->controller_ctx[stream->controller_idx].stream = stream;
++}
++
++static bool assign_first_free_controller(
++ struct resource_context *res_ctx,
++ struct core_stream *stream)
++{
++ uint8_t i;
++ for (i = 0; i < res_ctx->pool.controller_count; i++) {
++ if (!res_ctx->controller_ctx[i].stream) {
++ stream->tg = res_ctx->pool.timing_generators[i];
++ stream->mi = res_ctx->pool.mis[i];
++ stream->ipp = res_ctx->pool.ipps[i];
++ stream->xfm = res_ctx->pool.transforms[i];
++ stream->opp = res_ctx->pool.opps[i];
++ stream->controller_idx = i;
++ stream->dis_clk = res_ctx->pool.display_clock;
++ return true;
++ }
++ }
++ return false;
++}
++
++static void set_stream_engine_in_use(
++ struct resource_context *res_ctx,
++ struct stream_encoder *stream_enc)
++{
++ int i;
++
++ for (i = 0; i < res_ctx->pool.stream_enc_count; i++) {
++ if (res_ctx->pool.stream_enc[i] == stream_enc)
++ res_ctx->is_stream_enc_acquired[i] = true;
++ }
++}
++
++static struct stream_encoder *find_first_free_match_stream_enc_for_link(
++ struct resource_context *res_ctx,
++ struct core_link *link)
++{
++ uint8_t i;
++
++ for (i = 0; i < res_ctx->pool.stream_enc_count; i++) {
++ if (!res_ctx->is_stream_enc_acquired[i] &&
++ res_ctx->pool.stream_enc[i]) {
++ if (res_ctx->pool.stream_enc[i]->id ==
++ link->link_enc->preferred_engine)
++ return res_ctx->pool.stream_enc[i];
++ }
++ }
++
++ /* TODO: Handle MST*/
++
++ return NULL;
++}
++
++/* TODO: release audio object */
++static void set_audio_in_use(
++ struct resource_context *res_ctx,
++ struct audio *audio)
++{
++ int i;
++ for (i = 0; i < res_ctx->pool.audio_count; i++) {
++ if (res_ctx->pool.audios[i] == audio) {
++ res_ctx->is_audio_acquired[i] = true;
++ }
++ }
++}
++
++static struct audio *find_first_free_audio(struct resource_context *res_ctx)
++{
++ int i;
++ for (i = 0; i < res_ctx->pool.audio_count; i++) {
++ if (res_ctx->is_audio_acquired[i] == false) {
++ return res_ctx->pool.audios[i];
++ }
++ }
++
++ return 0;
++}
++
++
++static struct clock_source *find_first_free_pll(
++ struct resource_context *res_ctx)
++{
++ if (res_ctx->clock_source_ref_count[DCE110_CLK_SRC_PLL0] == 0) {
++ return res_ctx->pool.clock_sources[DCE110_CLK_SRC_PLL0];
++ }
++ if (res_ctx->clock_source_ref_count[DCE110_CLK_SRC_PLL1] == 0) {
++ return res_ctx->pool.clock_sources[DCE110_CLK_SRC_PLL1];
++ }
++
++ return 0;
++}
++
++static bool check_timing_change(struct core_stream *cur_stream,
++ struct core_stream *new_stream)
++{
++ if (cur_stream == NULL)
++ return true;
++
++ /* If sink pointer changed, it means this is a hotplug, we should do
++ * full hw setting.
++ */
++ if (cur_stream->sink != new_stream->sink)
++ return true;
++
++ return !is_same_timing(
++ &cur_stream->public.timing,
++ &new_stream->public.timing);
++}
++
++static enum dc_status map_resources(
++ const struct dc *dc,
++ struct validate_context *context)
++{
++ uint8_t i, j;
++
++ /* mark resources used for targets that are already active */
++ for (i = 0; i < context->target_count; i++) {
++ struct core_target *target = context->targets[i];
++ if (context->target_flags[i].unchanged)
++ for (j = 0; j < target->stream_count; j++) {
++ struct core_stream *stream = target->streams[j];
++ attach_stream_to_controller(
++ &context->res_ctx,
++ stream);
++
++ set_stream_engine_in_use(
++ &context->res_ctx,
++ stream->stream_enc);
++
++ reference_clock_source(
++ &context->res_ctx,
++ stream->clock_source);
++
++ if (stream->audio) {
++ set_audio_in_use(&context->res_ctx,
++ stream->audio);
++ }
++ }
++ }
++
++ /* acquire new resources */
++ for (i = 0; i < context->target_count; i++) {
++ struct core_target *target = context->targets[i];
++ if (context->target_flags[i].unchanged)
++ continue;
++ for (j = 0; j < target->stream_count; j++) {
++ struct core_stream *stream = target->streams[j];
++ struct core_stream *curr_stream;
++
++ if (!assign_first_free_controller(
++ &context->res_ctx, stream))
++ return DC_NO_CONTROLLER_RESOURCE;
++
++ attach_stream_to_controller(&context->res_ctx, stream);
++
++ stream->stream_enc =
++ find_first_free_match_stream_enc_for_link(
++ &context->res_ctx,
++ stream->sink->link);
++
++ if (!stream->stream_enc)
++ return DC_NO_STREAM_ENG_RESOURCE;
++
++ set_stream_engine_in_use(
++ &context->res_ctx,
++ stream->stream_enc);
++ stream->signal =
++ stream->sink->public.sink_signal;
++
++ if (dc_is_dp_signal(stream->signal))
++ stream->clock_source = context->res_ctx.
++ pool.clock_sources[DCE110_CLK_SRC_EXT];
++ else
++ stream->clock_source =
++ find_used_clk_src_for_sharing(
++ context, stream);
++ if (stream->clock_source == NULL)
++ stream->clock_source =
++ find_first_free_pll(&context->res_ctx);
++
++ if (stream->clock_source == NULL)
++ return DC_NO_CLOCK_SOURCE_RESOURCE;
++
++ reference_clock_source(
++ &context->res_ctx,
++ stream->clock_source);
++
++ /* TODO: Add check if ASIC support and EDID audio */
++ if (!stream->sink->converter_disable_audio &&
++ dc_is_audio_capable_signal(
++ stream->signal)) {
++ stream->audio = find_first_free_audio(
++ &context->res_ctx);
++
++ if (!stream->audio)
++ return DC_NO_STREAM_AUDIO_RESOURCE;
++
++ set_audio_in_use(&context->res_ctx,
++ stream->audio);
++ }
++ curr_stream =
++ dc->current_context.res_ctx.controller_ctx
++ [stream->controller_idx].stream;
++ context->res_ctx.controller_ctx[stream->controller_idx]
++ .flags.timing_changed =
++ check_timing_change(curr_stream, stream);
++
++ }
++ }
++
++ return DC_OK;
++}
++
++static enum audio_dto_source translate_to_dto_source(enum controller_id crtc_id)
++{
++ switch (crtc_id) {
++ case CONTROLLER_ID_D0:
++ return DTO_SOURCE_ID0;
++ case CONTROLLER_ID_D1:
++ return DTO_SOURCE_ID1;
++ case CONTROLLER_ID_D2:
++ return DTO_SOURCE_ID2;
++ case CONTROLLER_ID_D3:
++ return DTO_SOURCE_ID3;
++ case CONTROLLER_ID_D4:
++ return DTO_SOURCE_ID4;
++ case CONTROLLER_ID_D5:
++ return DTO_SOURCE_ID5;
++ default:
++ return DTO_SOURCE_UNKNOWN;
++ }
++}
++
++static void build_audio_output(
++ const struct core_stream *stream,
++ struct audio_output *audio_output)
++{
++ audio_output->engine_id = stream->stream_enc->id;
++
++ audio_output->signal = stream->signal;
++
++ /* audio_crtc_info */
++
++ audio_output->crtc_info.h_total =
++ stream->public.timing.h_total;
++
++ /* Audio packets are sent during actual CRTC blank physical signal, we
++ * need to specify actual active signal portion */
++ audio_output->crtc_info.h_active =
++ stream->public.timing.h_addressable
++ + stream->public.timing.h_border_left
++ + stream->public.timing.h_border_right;
++
++ audio_output->crtc_info.v_active =
++ stream->public.timing.v_addressable
++ + stream->public.timing.v_border_top
++ + stream->public.timing.v_border_bottom;
++
++ audio_output->crtc_info.pixel_repetition = 1;
++
++ audio_output->crtc_info.interlaced =
++ stream->public.timing.flags.INTERLACE;
++
++ audio_output->crtc_info.refresh_rate =
++ (stream->public.timing.pix_clk_khz*1000)/
++ (stream->public.timing.h_total*stream->public.timing.v_total);
++
++ audio_output->crtc_info.color_depth =
++ stream->public.timing.display_color_depth;
++
++ audio_output->crtc_info.requested_pixel_clock =
++ stream->pix_clk_params.requested_pix_clk;
++
++ /* TODO - Investigate why calculated pixel clk has to be
++ * requested pixel clk */
++ audio_output->crtc_info.calculated_pixel_clock =
++ stream->pix_clk_params.requested_pix_clk;
++
++ /* TODO: This is needed for DP */
++ if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT) {
++ audio_output->pll_info.dp_dto_source_clock_in_khz =
++ dal_display_clock_get_dp_ref_clk_frequency(
++ stream->dis_clk);
++ }
++
++ audio_output->pll_info.feed_back_divider =
++ stream->pll_settings.feedback_divider;
++
++ audio_output->pll_info.dto_source =
++ translate_to_dto_source(
++ stream->controller_idx + 1);
++
++ /* TODO hard code to enable for now. Need get from stream */
++ audio_output->pll_info.ss_enabled = true;
++
++ audio_output->pll_info.ss_percentage =
++ stream->pll_settings.ss_percentage;
++}
++
++static void get_pixel_clock_parameters(
++ const struct core_stream *stream,
++ struct pixel_clk_params *pixel_clk_params)
++{
++ pixel_clk_params->requested_pix_clk = stream->public.timing.pix_clk_khz;
++ pixel_clk_params->encoder_object_id = stream->sink->link->link_enc->id;
++ pixel_clk_params->signal_type = stream->sink->public.sink_signal;
++ pixel_clk_params->controller_id = stream->controller_idx + 1;
++ /* TODO: un-hardcode*/
++ pixel_clk_params->requested_sym_clk = LINK_RATE_LOW *
++ LINK_RATE_REF_FREQ_IN_KHZ;
++ pixel_clk_params->flags.ENABLE_SS = 0;
++ pixel_clk_params->color_depth =
++ stream->public.timing.display_color_depth;
++ pixel_clk_params->flags.DISPLAY_BLANKED = 1;
++}
++
++static enum dc_status build_stream_hw_param(struct core_stream *stream)
++{
++ /*TODO: unhardcode*/
++ stream->max_tmds_clk_from_edid_in_mhz = 0;
++ stream->max_hdmi_deep_color = COLOR_DEPTH_121212;
++ stream->max_hdmi_pixel_clock = 600000;
++
++ get_pixel_clock_parameters(stream, &stream->pix_clk_params);
++ dal_clock_source_get_pix_clk_dividers(
++ stream->clock_source,
++ &stream->pix_clk_params,
++ &stream->pll_settings);
++
++ build_audio_output(stream, &stream->audio_output);
++
++ return DC_OK;
++}
++
++static enum dc_status validate_mapped_resource(
++ const struct dc *dc,
++ struct validate_context *context)
++{
++ enum dc_status status = DC_OK;
++ uint8_t i, j;
++
++ for (i = 0; i < context->target_count; i++) {
++ struct core_target *target = context->targets[i];
++ if (context->target_flags[i].unchanged)
++ continue;
++ for (j = 0; j < target->stream_count; j++) {
++ struct core_stream *stream = target->streams[j];
++ struct core_link *link = stream->sink->link;
++ status = build_stream_hw_param(stream);
++
++ if (status != DC_OK)
++ return status;
++
++ if (!dce110_timing_generator_validate_timing(
++ stream->tg,
++ &stream->public.timing,
++ SIGNAL_TYPE_HDMI_TYPE_A))
++ return DC_FAIL_CONTROLLER_VALIDATE;
++
++
++ if (dce110_link_encoder_validate_output_with_stream(
++ link->link_enc,
++ stream)
++ != ENCODER_RESULT_OK)
++ return DC_FAIL_ENC_VALIDATE;
++
++ /* TODO: validate audio ASIC caps, encoder */
++
++ status = dc_link_validate_mode_timing(stream->sink,
++ link,
++ &stream->public.timing);
++
++ if (status != DC_OK)
++ return status;
++
++ build_info_frame(stream);
++ }
++ }
++
++ return DC_OK;
++}
++
++enum dc_status dce110_validate_bandwidth(
++ const struct dc *dc,
++ struct validate_context *context)
++{
++ uint8_t i, j;
++ enum dc_status result = DC_ERROR_UNEXPECTED;
++ uint8_t number_of_displays = 0;
++
++ memset(&context->bw_mode_data, 0, sizeof(context->bw_mode_data));
++
++ for (i = 0; i < context->target_count; i++) {
++ struct core_target *target = context->targets[i];
++ for (j = 0; j < target->stream_count; j++) {
++ struct core_stream *stream = target->streams[j];
++ struct bw_calcs_input_single_display *disp = &context->
++ bw_mode_data.displays_data[number_of_displays];
++
++ if (target->status.surface_count == 0) {
++ disp->graphics_scale_ratio = int_to_fixed(1);
++ disp->graphics_h_taps = 4;
++ disp->graphics_v_taps = 4;
++
++ } else {
++ disp->graphics_scale_ratio =
++ fixed31_32_to_bw_fixed(
++ stream->ratios.vert.value);
++ disp->graphics_h_taps = stream->taps.h_taps;
++ disp->graphics_v_taps = stream->taps.v_taps;
++ }
++
++ disp->graphics_src_width =
++ stream->public.timing.h_addressable;
++ disp->graphics_src_height =
++ stream->public.timing.v_addressable;
++ disp->h_total = stream->public.timing.h_total;
++ disp->pixel_rate = frc_to_fixed(
++ stream->public.timing.pix_clk_khz, 1000);
++
++ /*TODO: get from surface*/
++ disp->graphics_bytes_per_pixel = 4;
++ disp->graphics_tiling_mode = tiled;
++
++ /* DCE11 defaults*/
++ disp->graphics_lb_bpc = 10;
++ disp->graphics_interlace_mode = false;
++ disp->fbc_enable = false;
++ disp->lpt_enable = false;
++ disp->graphics_stereo_mode = mono;
++ disp->underlay_mode = ul_none;
++
++ number_of_displays++;
++ }
++ }
++
++ context->bw_mode_data.number_of_displays = number_of_displays;
++ context->bw_mode_data.display_synchronization_enabled = false;
++
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_BWM,
++ LOG_MINOR_BWM_REQUIRED_BANDWIDTH_CALCS,
++ "%s: Start bandwidth calculations",
++ __func__);
++ if (true == bw_calcs(
++ dc->ctx,
++ &dc->bw_dceip,
++ &dc->bw_vbios,
++ &context->bw_mode_data,
++ &context->bw_results))
++ result = DC_OK;
++ else {
++ result = DC_FAIL_BANDWIDTH_VALIDATE;
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_BWM,
++ LOG_MINOR_BWM_MODE_VALIDATION,
++ "%s: Bandwidth validation failed!",
++ __func__);
++ }
++
++
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_BWM,
++ LOG_MINOR_BWM_REQUIRED_BANDWIDTH_CALCS,
++ "%s: Finish bandwidth calculations\n nbpMark: %d",
++ __func__,
++ context->bw_results.nbp_state_change_watermark[0].b_mark);
++
++ return result;
++}
++
++static void set_target_unchanged(
++ struct validate_context *context,
++ uint8_t target_idx)
++{
++ uint8_t i;
++ struct core_target *target = context->targets[target_idx];
++ context->target_flags[target_idx].unchanged = true;
++ for (i = 0; i < target->stream_count; i++) {
++ uint8_t index = target->streams[i]->controller_idx;
++ context->res_ctx.controller_ctx[index].flags.unchanged = true;
++ }
++}
++
++enum dc_status dce110_validate_with_context(
++ const struct dc *dc,
++ const struct dc_validation_set set[],
++ uint8_t set_count,
++ struct validate_context *context)
++{
++ enum dc_status result = DC_ERROR_UNEXPECTED;
++ uint8_t i, j;
++ struct dc_context *dc_ctx = dc->ctx;
++
++ for (i = 0; i < set_count; i++) {
++ context->targets[i] = DC_TARGET_TO_CORE(set[i].target);
++
++ for (j = 0; j < dc->current_context.target_count; j++)
++ if (dc->current_context.targets[j] == context->targets[i])
++ set_target_unchanged(context, i);
++
++ if (!context->target_flags[i].unchanged)
++ if (!logical_attach_surfaces_to_target(
++ (struct dc_surface **)set[i].surfaces,
++ set[i].surface_count,
++ &context->targets[i]->public)) {
++ DC_ERROR("Failed to attach surface to target!\n");
++ return DC_FAIL_ATTACH_SURFACES;
++ }
++ }
++
++ context->target_count = set_count;
++
++ context->res_ctx.pool = dc->res_pool;
++
++ result = map_resources(dc, context);
++
++ if (result == DC_OK)
++ result = validate_mapped_resource(dc, context);
++
++ if (result == DC_OK)
++ build_scaling_params_for_context(dc, context);
++
++ if (result == DC_OK)
++ result = dce110_validate_bandwidth(dc, context);
++
++ return result;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.h
+new file mode 100644
+index 0000000..e113d11
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_resource.h
+@@ -0,0 +1,55 @@
++/*
++* Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_RESOURCE_DCE110_H__
++#define __DC_RESOURCE_DCE110_H__
++
++#include "core_types.h"
++
++struct adapter_service;
++struct dc;
++struct resource_pool;
++struct dc_validation_set;
++
++
++bool dce110_construct_resource_pool(
++ struct adapter_service *adapter_serv,
++ struct dc *dc,
++ struct resource_pool *pool);
++
++void dce110_destruct_resource_pool(struct resource_pool *pool);
++
++enum dc_status dce110_validate_with_context(
++ const struct dc *dc,
++ const struct dc_validation_set set[],
++ uint8_t set_count,
++ struct validate_context *context);
++
++enum dc_status dce110_validate_bandwidth(
++ const struct dc *dc,
++ struct validate_context *context);
++
++#endif /* __DC_RESOURCE_DCE110_H__ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
+new file mode 100644
+index 0000000..a9edf96
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.c
+@@ -0,0 +1,1168 @@
++/*
++ * 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 "dal_services.h"
++#include "stream_encoder_types.h"
++#include "dce110_stream_encoder.h"
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++#include "dce/dce_11_0_enum.h"
++
++static const uint32_t fe_engine_offsets[] = {
++ mmDIG0_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG1_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++ mmDIG2_DIG_FE_CNTL - mmDIG0_DIG_FE_CNTL,
++};
++
++#define VBI_LINE_0 0
++#define DP_BLANK_MAX_RETRY 20
++#define HDMI_CLOCK_CHANNEL_RATE_MORE_340M 340000
++
++#ifndef HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN_MASK
++ #define HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN_MASK 0x2
++ #define HDMI_CONTROL__HDMI_DATA_SCRAMBLE_EN__SHIFT 0x1
++#endif
++
++static void construct(
++ struct stream_encoder *enc,
++ struct stream_enc_init_data *init)
++{
++ enc->ctx = init->ctx;
++ enc->id = init->stream_engine_id;
++ enc->adapter_service = init->adapter_service;
++}
++
++struct stream_encoder *dce110_stream_encoder_create(
++ struct stream_enc_init_data *init)
++{
++ struct stream_encoder *enc =
++ dc_service_alloc(init->ctx, sizeof(struct stream_encoder));
++
++ if (!enc)
++ goto enc_create_fail;
++
++ construct(enc, init);
++
++ return enc;
++
++enc_create_fail:
++ return NULL;
++}
++
++void dce110_stream_encoder_destroy(struct stream_encoder **enc)
++{
++ dc_service_free((*enc)->ctx, *enc);
++ *enc = NULL;
++}
++
++static void stop_hdmi_info_packets(struct dc_context *ctx, uint32_t offset)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ /* stop generic packets 0 & 1 on HDMI */
++ addr = mmHDMI_GENERIC_PACKET_CONTROL0 + offset;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC1_CONT);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC1_LINE);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC1_SEND);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC0_CONT);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC0_LINE);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC0_SEND);
++
++ dal_write_reg(ctx, addr, value);
++
++ /* stop generic packets 2 & 3 on HDMI */
++ addr = mmHDMI_GENERIC_PACKET_CONTROL1 + offset;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL1,
++ HDMI_GENERIC2_CONT);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL1,
++ HDMI_GENERIC2_LINE);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL1,
++ HDMI_GENERIC2_SEND);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL1,
++ HDMI_GENERIC3_CONT);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL1,
++ HDMI_GENERIC3_LINE);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_GENERIC_PACKET_CONTROL1,
++ HDMI_GENERIC3_SEND);
++
++ dal_write_reg(ctx, addr, value);
++
++ /* stop AVI packet on HDMI */
++ addr = mmHDMI_INFOFRAME_CONTROL0 + offset;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_SEND);
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_CONT);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void stop_dp_info_packets(struct dc_context *ctx, int32_t offset)
++{
++ /* stop generic packets on DP */
++
++ const uint32_t addr = mmDP_SEC_CNTL + offset;
++
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP0_ENABLE);
++ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP1_ENABLE);
++ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP2_ENABLE);
++ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_GSP3_ENABLE);
++ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_AVI_ENABLE);
++ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_MPG_ENABLE);
++ set_reg_field_value(value, 0, DP_SEC_CNTL, DP_SEC_STREAM_ENABLE);
++
++ /* this register shared with audio info frame.
++ * therefore we need to keep master enabled
++ * if at least one of the fields is not 0 */
++
++ if (value)
++ set_reg_field_value(
++ value,
++ 1,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++void dce110_stream_encoder_stop_info_packets(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ enum signal_type signal)
++{
++ if (dc_is_hdmi_signal(signal))
++ stop_hdmi_info_packets(
++ enc->ctx,
++ fe_engine_offsets[engine]);
++ else if (dc_is_dp_signal(signal))
++ stop_dp_info_packets(
++ enc->ctx,
++ fe_engine_offsets[engine]);
++}
++
++
++static void update_avi_info_packet(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ enum signal_type signal,
++ const struct encoder_info_packet *info_packet)
++{
++ const int32_t offset = fe_engine_offsets[engine];
++
++ uint32_t regval;
++ uint32_t addr;
++
++ if (info_packet->valid) {
++ const uint32_t *content =
++ (const uint32_t *) &info_packet->sb[0];
++
++ {
++ regval = content[0];
++
++ dal_write_reg(
++ enc->ctx,
++ mmAFMT_AVI_INFO0 + offset,
++ regval);
++ }
++ {
++ regval = content[1];
++
++ dal_write_reg(
++ enc->ctx,
++ mmAFMT_AVI_INFO1 + offset,
++ regval);
++ }
++ {
++ regval = content[2];
++
++ dal_write_reg(
++ enc->ctx,
++ mmAFMT_AVI_INFO2 + offset,
++ regval);
++ }
++ {
++ regval = content[3];
++
++ /* move version to AVI_INFO3 */
++ set_reg_field_value(
++ regval,
++ info_packet->hb1,
++ AFMT_AVI_INFO3,
++ AFMT_AVI_INFO_VERSION);
++
++ dal_write_reg(
++ enc->ctx,
++ mmAFMT_AVI_INFO3 + offset,
++ regval);
++ }
++
++ if (dc_is_hdmi_signal(signal)) {
++
++ uint32_t control0val;
++ uint32_t control1val;
++
++ addr = mmHDMI_INFOFRAME_CONTROL0 + offset;
++
++ control0val = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(
++ control0val,
++ 1,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_SEND);
++
++ set_reg_field_value(
++ control0val,
++ 1,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_CONT);
++
++ dal_write_reg(enc->ctx, addr, control0val);
++
++ addr = mmHDMI_INFOFRAME_CONTROL1 + offset;
++
++ control1val = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(
++ control1val,
++ VBI_LINE_0 + 2,
++ HDMI_INFOFRAME_CONTROL1,
++ HDMI_AVI_INFO_LINE);
++
++ dal_write_reg(enc->ctx, addr, control1val);
++ }
++ } else if (dc_is_hdmi_signal(signal)) {
++ addr = mmHDMI_INFOFRAME_CONTROL0 + offset;
++
++ regval = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(
++ regval,
++ 0,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_SEND);
++
++ set_reg_field_value(
++ regval,
++ 0,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AVI_INFO_CONT);
++
++ dal_write_reg(enc->ctx, addr, regval);
++ }
++}
++
++static void update_generic_info_packet(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ uint32_t packet_index,
++ const struct encoder_info_packet *info_packet)
++{
++ uint32_t addr;
++ uint32_t regval;
++ /* choose which generic packet to use */
++ {
++ addr = mmAFMT_VBI_PACKET_CONTROL + fe_engine_offsets[engine];
++
++ regval = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(
++ regval,
++ packet_index,
++ AFMT_VBI_PACKET_CONTROL,
++ AFMT_GENERIC_INDEX);
++
++ dal_write_reg(enc->ctx, addr, regval);
++ }
++
++ /* write generic packet header
++ * (4th byte is for GENERIC0 only) */
++ {
++ addr = mmAFMT_GENERIC_HDR + fe_engine_offsets[engine];
++
++ regval = 0;
++
++ set_reg_field_value(
++ regval,
++ info_packet->hb0,
++ AFMT_GENERIC_HDR,
++ AFMT_GENERIC_HB0);
++
++ set_reg_field_value(
++ regval,
++ info_packet->hb1,
++ AFMT_GENERIC_HDR,
++ AFMT_GENERIC_HB1);
++
++ set_reg_field_value(
++ regval,
++ info_packet->hb2,
++ AFMT_GENERIC_HDR,
++ AFMT_GENERIC_HB2);
++
++ set_reg_field_value(
++ regval,
++ info_packet->hb3,
++ AFMT_GENERIC_HDR,
++ AFMT_GENERIC_HB3);
++
++ dal_write_reg(enc->ctx, addr, regval);
++ }
++
++ /* write generic packet contents
++ * (we never use last 4 bytes)
++ * there are 8 (0-7) mmDIG0_AFMT_GENERIC0_x registers */
++ {
++ const uint32_t *content =
++ (const uint32_t *) &info_packet->sb[0];
++
++ uint32_t counter = 0;
++
++ addr = mmAFMT_GENERIC_0 + fe_engine_offsets[engine];
++
++ do {
++ dal_write_reg(enc->ctx, addr++, *content++);
++
++ ++counter;
++ } while (counter < 7);
++ }
++
++ dal_write_reg(
++ enc->ctx,
++ mmAFMT_GENERIC_7 + fe_engine_offsets[engine],
++ 0);
++
++ /* force double-buffered packet update */
++ {
++ addr = mmAFMT_VBI_PACKET_CONTROL + fe_engine_offsets[engine];
++
++ regval = dal_read_reg(enc->ctx, addr);
++
++ set_reg_field_value(
++ regval,
++ (packet_index == 0),
++ AFMT_VBI_PACKET_CONTROL,
++ AFMT_GENERIC0_UPDATE);
++
++ set_reg_field_value(
++ regval,
++ (packet_index == 2),
++ AFMT_VBI_PACKET_CONTROL,
++ AFMT_GENERIC2_UPDATE);
++
++ dal_write_reg(enc->ctx, addr, regval);
++ }
++}
++
++static void update_hdmi_info_packet(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ uint32_t packet_index,
++ const struct encoder_info_packet *info_packet)
++{
++ uint32_t cont, send, line;
++ uint32_t addr = fe_engine_offsets[engine];
++ uint32_t regval;
++
++ if (info_packet->valid) {
++ update_generic_info_packet(
++ enc,
++ engine,
++ packet_index,
++ info_packet);
++
++ /* enable transmission of packet(s) -
++ * packet transmission begins on the next frame */
++ cont = 1;
++ /* send packet(s) every frame */
++ send = 1;
++ /* select line number to send packets on */
++ line = 2;
++ } else {
++ cont = 0;
++ send = 0;
++ line = 0;
++ }
++
++ /* choose which generic packet control to use */
++
++ switch (packet_index) {
++ case 0:
++ case 1:
++ addr += mmHDMI_GENERIC_PACKET_CONTROL0;
++ break;
++ case 2:
++ case 3:
++ addr += mmHDMI_GENERIC_PACKET_CONTROL1;
++ break;
++ default:
++ /* invalid HW packet index */
++ dal_logger_write(
++ enc->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_ENCODER,
++ "Invalid HW packet index: %s()\n",
++ __func__);
++ break;
++ }
++
++ regval = dal_read_reg(enc->ctx, addr);
++
++ switch (packet_index) {
++ case 0:
++ case 2:
++ set_reg_field_value(
++ regval,
++ cont,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC0_CONT);
++ set_reg_field_value(
++ regval,
++ send,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC0_SEND);
++ set_reg_field_value(
++ regval,
++ line,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC0_LINE);
++ break;
++ case 1:
++ case 3:
++ set_reg_field_value(
++ regval,
++ cont,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC1_CONT);
++ set_reg_field_value(
++ regval,
++ send,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC1_SEND);
++ set_reg_field_value(
++ regval,
++ line,
++ HDMI_GENERIC_PACKET_CONTROL0,
++ HDMI_GENERIC1_LINE);
++ break;
++ default:
++ /* invalid HW packet index */
++ dal_logger_write(
++ enc->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_ENCODER,
++ "Invalid HW packet index: %s()\n",
++ __func__);
++ break;
++ }
++
++ dal_write_reg(enc->ctx, addr, regval);
++}
++
++static void update_dp_info_packet(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ uint32_t packet_index,
++ const struct encoder_info_packet *info_packet)
++{
++ const uint32_t addr = mmDP_SEC_CNTL + fe_engine_offsets[engine];
++
++ uint32_t value;
++
++ if (info_packet->valid)
++ update_generic_info_packet(
++ enc,
++ engine,
++ packet_index,
++ info_packet);
++
++ /* enable/disable transmission of packet(s).
++ * If enabled, packet transmission begins on the next frame */
++
++ value = dal_read_reg(enc->ctx, addr);
++
++ switch (packet_index) {
++ case 0:
++ set_reg_field_value(
++ value,
++ info_packet->valid,
++ DP_SEC_CNTL,
++ DP_SEC_GSP0_ENABLE);
++ break;
++ case 1:
++ set_reg_field_value(
++ value,
++ info_packet->valid,
++ DP_SEC_CNTL,
++ DP_SEC_GSP1_ENABLE);
++ break;
++ case 2:
++ set_reg_field_value(
++ value,
++ info_packet->valid,
++ DP_SEC_CNTL,
++ DP_SEC_GSP2_ENABLE);
++ break;
++ case 3:
++ set_reg_field_value(
++ value,
++ info_packet->valid,
++ DP_SEC_CNTL,
++ DP_SEC_GSP3_ENABLE);
++ break;
++ default:
++ /* invalid HW packet index */
++ ASSERT_CRITICAL(false);
++ return;
++ }
++
++ /* This bit is the master enable bit.
++ * When enabling secondary stream engine,
++ * this master bit must also be set.
++ * This register shared with audio info frame.
++ * Therefore we need to enable master bit
++ * if at least on of the fields is not 0 */
++
++ if (value)
++ set_reg_field_value(
++ value,
++ 1,
++ DP_SEC_CNTL,
++ DP_SEC_STREAM_ENABLE);
++
++ dal_write_reg(enc->ctx, addr, value);
++}
++
++void dce110_stream_encoder_update_info_packets(
++ struct stream_encoder *enc,
++ enum signal_type signal,
++ const struct encoder_info_frame *info_frame)
++{
++ if (dc_is_hdmi_signal(signal)) {
++ update_avi_info_packet(
++ enc,
++ enc->id,
++ signal,
++ &info_frame->avi);
++ update_hdmi_info_packet(enc, enc->id, 0, &info_frame->vendor);
++ update_hdmi_info_packet(enc, enc->id, 1, &info_frame->gamut);
++ update_hdmi_info_packet(enc, enc->id, 2, &info_frame->spd);
++ } else if (dc_is_dp_signal(signal))
++ update_dp_info_packet(enc, enc->id, 0, &info_frame->vsc);
++}
++
++static void dp_steer_fifo_reset(
++ struct dc_context *ctx,
++ enum engine_id engine,
++ bool reset)
++{
++ const uint32_t addr = mmDP_STEER_FIFO + fe_engine_offsets[engine];
++
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, reset, DP_STEER_FIFO, DP_STEER_FIFO_RESET);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++/*
++ * @brief
++ * Output blank data,
++ * prevents output of the actual surface data on active transmitter
++ */
++enum encoder_result dce110_stream_encoder_blank(
++ struct stream_encoder *enc,
++ enum signal_type signal)
++{
++ enum engine_id engine = enc->id;
++ const uint32_t addr = mmDP_VID_STREAM_CNTL + fe_engine_offsets[engine];
++ uint32_t value = dal_read_reg(enc->ctx, addr);
++ uint32_t retries = 0;
++ uint32_t max_retries = DP_BLANK_MAX_RETRY * 10;
++
++ if (!dc_is_dp_signal(signal))
++ return ENCODER_RESULT_OK;
++
++ /* Note: For CZ, we are changing driver default to disable
++ * stream deferred to next VBLANK. If results are positive, we
++ * will make the same change to all DCE versions. There are a
++ * handful of panels that cannot handle disable stream at
++ * HBLANK and will result in a white line flash across the
++ * screen on stream disable. */
++
++ /* Specify the video stream disable point
++ * (2 = start of the next vertical blank) */
++ set_reg_field_value(
++ value,
++ 2,
++ DP_VID_STREAM_CNTL,
++ DP_VID_STREAM_DIS_DEFER);
++ /* Larger delay to wait until VBLANK - use max retry of
++ * 10us*3000=30ms. This covers 16.6ms of typical 60 Hz mode +
++ * a little more because we may not trust delay accuracy. */
++ max_retries = DP_BLANK_MAX_RETRY * 150;
++
++ /* disable DP stream */
++ set_reg_field_value(value, 0, DP_VID_STREAM_CNTL, DP_VID_STREAM_ENABLE);
++ dal_write_reg(enc->ctx, addr, value);
++
++ /* the encoder stops sending the video stream
++ * at the start of the vertical blanking.
++ * Poll for DP_VID_STREAM_STATUS == 0 */
++
++ do {
++ value = dal_read_reg(enc->ctx, addr);
++
++ if (!get_reg_field_value(
++ value,
++ DP_VID_STREAM_CNTL,
++ DP_VID_STREAM_STATUS))
++ break;
++
++ dc_service_delay_in_microseconds(enc->ctx, 10);
++
++ ++retries;
++ } while (retries < max_retries);
++
++ ASSERT(retries <= max_retries);
++
++ /* Tell the DP encoder to ignore timing from CRTC, must be done after
++ * the polling. If we set DP_STEER_FIFO_RESET before DP stream blank is
++ * complete, stream status will be stuck in video stream enabled state,
++ * i.e. DP_VID_STREAM_STATUS stuck at 1. */
++ dp_steer_fifo_reset(enc->ctx, engine, true);
++
++ return ENCODER_RESULT_OK;
++}
++
++static void unblank_dp_output(
++ struct stream_encoder *enc,
++ enum engine_id engine)
++{
++ uint32_t addr;
++ uint32_t value;
++
++ /* set DIG_START to 0x1 to resync FIFO */
++ addr = mmDIG_FE_CNTL + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, 1, DIG_FE_CNTL, DIG_START);
++ dal_write_reg(enc->ctx, addr, value);
++
++ /* switch DP encoder to CRTC data */
++ dp_steer_fifo_reset(enc->ctx, engine, false);
++
++ /* wait 100us for DIG/DP logic to prime
++ * (i.e. a few video lines) */
++ dc_service_delay_in_microseconds(enc->ctx, 100);
++
++ /* the hardware would start sending video at the start of the next DP
++ * frame (i.e. rising edge of the vblank).
++ * NOTE: We used to program DP_VID_STREAM_DIS_DEFER = 2 here, but this
++ * register has no effect on enable transition! HW always guarantees
++ * VID_STREAM enable at start of next frame, and this is not
++ * programmable */
++ addr = mmDP_VID_STREAM_CNTL + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(
++ value,
++ true,
++ DP_VID_STREAM_CNTL,
++ DP_VID_STREAM_ENABLE);
++ dal_write_reg(enc->ctx, addr, value);
++
++}
++
++static void setup_vid_stream(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ uint32_t m_vid,
++ uint32_t n_vid)
++{
++ uint32_t addr;
++ uint32_t value;
++
++ /* enable auto measurement */
++ addr = mmDP_VID_TIMING + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, 0, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
++ dal_write_reg(enc->ctx, addr, value);
++
++ /* auto measurement need 1 full 0x8000 symbol cycle to kick in,
++ * therefore program initial value for Mvid and Nvid */
++ addr = mmDP_VID_N + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, n_vid, DP_VID_N, DP_VID_N);
++ dal_write_reg(enc->ctx, addr, value);
++
++ addr = mmDP_VID_M + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, m_vid, DP_VID_M, DP_VID_M);
++ dal_write_reg(enc->ctx, addr, value);
++
++ addr = mmDP_VID_TIMING + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, 1, DP_VID_TIMING, DP_VID_M_N_GEN_EN);
++ dal_write_reg(enc->ctx, addr, value);
++}
++/*
++ * @brief
++ * Stop sending blank data,
++ * output the actual surface data on active transmitter
++ */
++enum encoder_result dce110_stream_encoder_unblank(
++ struct stream_encoder *enc,
++ const struct encoder_unblank_param *param)
++{
++ bool is_dp_signal = param->signal == SIGNAL_TYPE_DISPLAY_PORT
++ || param->signal == SIGNAL_TYPE_DISPLAY_PORT_MST
++ || param->signal == SIGNAL_TYPE_EDP;
++
++ if (!is_dp_signal)
++ return ENCODER_RESULT_OK;
++
++ if (param->link_settings.link_rate != LINK_RATE_UNKNOWN) {
++ uint32_t n_vid = 0x8000;
++ uint32_t m_vid;
++
++ /* M / N = Fstream / Flink
++ * m_vid / n_vid = pixel rate / link rate */
++
++ uint64_t m_vid_l = n_vid;
++
++ m_vid_l *= param->crtc_timing.pixel_clock;
++ m_vid_l = div_u64(m_vid_l,
++ param->link_settings.link_rate
++ * LINK_RATE_REF_FREQ_IN_KHZ);
++
++ m_vid = (uint32_t) m_vid_l;
++
++ setup_vid_stream(enc,
++ enc->id, m_vid, n_vid);
++ }
++
++ unblank_dp_output(enc, enc->id);
++
++ return ENCODER_RESULT_OK;
++}
++
++static void set_dp_stream_attributes(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ const struct dc_crtc_timing *timing)
++{
++ const uint32_t addr = mmDP_PIXEL_FORMAT + fe_engine_offsets[engine];
++ uint32_t value = dal_read_reg(enc->ctx, addr);
++
++ /* set pixel encoding */
++ switch (timing->pixel_encoding) {
++ case PIXEL_ENCODING_YCBCR422:
++ set_reg_field_value(
++ value,
++ DP_PIXEL_ENCODING_YCBCR422,
++ DP_PIXEL_FORMAT,
++ DP_PIXEL_ENCODING);
++ break;
++ case PIXEL_ENCODING_YCBCR444:
++ set_reg_field_value(
++ value,
++ DP_PIXEL_ENCODING_YCBCR444,
++ DP_PIXEL_FORMAT,
++ DP_PIXEL_ENCODING);
++
++ if (timing->flags.Y_ONLY)
++ if (timing->display_color_depth != COLOR_DEPTH_666)
++ /* HW testing only, no use case yet.
++ * Color depth of Y-only could be
++ * 8, 10, 12, 16 bits */
++ set_reg_field_value(
++ value,
++ DP_PIXEL_ENCODING_Y_ONLY,
++ DP_PIXEL_FORMAT,
++ DP_PIXEL_ENCODING);
++ /* Note: DP_MSA_MISC1 bit 7 is the indicator
++ * of Y-only mode.
++ * This bit is set in HW if register
++ * DP_PIXEL_ENCODING is programmed to 0x4 */
++ break;
++ default:
++ set_reg_field_value(
++ value,
++ DP_PIXEL_ENCODING_RGB444,
++ DP_PIXEL_FORMAT,
++ DP_PIXEL_ENCODING);
++ break;
++ }
++
++ /* set color depth */
++
++ switch (timing->display_color_depth) {
++ case COLOR_DEPTH_888:
++ set_reg_field_value(
++ value,
++ DP_COMPONENT_DEPTH_8BPC,
++ DP_PIXEL_FORMAT,
++ DP_COMPONENT_DEPTH);
++ break;
++ case COLOR_DEPTH_101010:
++ set_reg_field_value(
++ value,
++ DP_COMPONENT_DEPTH_10BPC,
++ DP_PIXEL_FORMAT,
++ DP_COMPONENT_DEPTH);
++ break;
++ case COLOR_DEPTH_121212:
++ set_reg_field_value(
++ value,
++ DP_COMPONENT_DEPTH_12BPC,
++ DP_PIXEL_FORMAT,
++ DP_COMPONENT_DEPTH);
++ break;
++ default:
++ set_reg_field_value(
++ value,
++ DP_COMPONENT_DEPTH_6BPC,
++ DP_PIXEL_FORMAT,
++ DP_COMPONENT_DEPTH);
++ break;
++ }
++
++ /* set dynamic range and YCbCr range */
++ set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_DYN_RANGE);
++ set_reg_field_value(value, 0, DP_PIXEL_FORMAT, DP_YCBCR_RANGE);
++
++ dal_write_reg(enc->ctx, addr, value);
++}
++
++static void setup_hdmi(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ const struct dc_crtc_timing *timing)
++{
++ uint32_t output_pixel_clock = timing->pix_clk_khz;
++ uint32_t value;
++ uint32_t addr;
++
++ addr = mmHDMI_CONTROL + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, 1, HDMI_CONTROL, HDMI_PACKET_GEN_VERSION);
++ set_reg_field_value(value, 1, HDMI_CONTROL, HDMI_KEEPOUT_MODE);
++ set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_DEEP_COLOR_ENABLE);
++ set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_DATA_SCRAMBLE_EN);
++ set_reg_field_value(value, 0, HDMI_CONTROL, HDMI_CLOCK_CHANNEL_RATE);
++
++ switch (timing->display_color_depth) {
++ case COLOR_DEPTH_888:
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_CONTROL,
++ HDMI_DEEP_COLOR_DEPTH);
++ break;
++ case COLOR_DEPTH_101010:
++ set_reg_field_value(
++ value,
++ 1,
++ HDMI_CONTROL,
++ HDMI_DEEP_COLOR_DEPTH);
++ set_reg_field_value(
++ value,
++ 1,
++ HDMI_CONTROL,
++ HDMI_DEEP_COLOR_ENABLE);
++ output_pixel_clock = (timing->pix_clk_khz * 30) / 24;
++ break;
++ case COLOR_DEPTH_121212:
++ set_reg_field_value(
++ value,
++ 2,
++ HDMI_CONTROL,
++ HDMI_DEEP_COLOR_DEPTH);
++ set_reg_field_value(
++ value,
++ 1,
++ HDMI_CONTROL,
++ HDMI_DEEP_COLOR_ENABLE);
++ output_pixel_clock = (timing->pix_clk_khz * 36) / 24;
++ break;
++ case COLOR_DEPTH_161616:
++ set_reg_field_value(
++ value,
++ 3,
++ HDMI_CONTROL,
++ HDMI_DEEP_COLOR_DEPTH);
++ set_reg_field_value(
++ value,
++ 1,
++ HDMI_CONTROL,
++ HDMI_DEEP_COLOR_ENABLE);
++ output_pixel_clock = (timing->pix_clk_khz * 48) / 24;
++ break;
++ default:
++ break;
++ }
++
++ if (output_pixel_clock >= HDMI_CLOCK_CHANNEL_RATE_MORE_340M) {
++ /* enable HDMI data scrambler */
++ set_reg_field_value(
++ value,
++ 1,
++ HDMI_CONTROL,
++ HDMI_DATA_SCRAMBLE_EN);
++
++ /* HDMI_CLOCK_CHANNEL_RATE_MORE_340M
++ * Clock channel frequency is 1/4 of character rate.*/
++ set_reg_field_value(
++ value,
++ 1,
++ HDMI_CONTROL,
++ HDMI_CLOCK_CHANNEL_RATE);
++ } else if (timing->flags.LTE_340MCSC_SCRAMBLE) {
++
++ /* TODO: New feature for DCE11, still need to implement */
++
++ /* enable HDMI data scrambler */
++ set_reg_field_value(
++ value,
++ 1,
++ HDMI_CONTROL,
++ HDMI_DATA_SCRAMBLE_EN);
++
++ /* HDMI_CLOCK_CHANNEL_FREQ_EQUAL_TO_CHAR_RATE
++ * Clock channel frequency is the same
++ * as character rate */
++ set_reg_field_value(
++ value,
++ 0,
++ HDMI_CONTROL,
++ HDMI_CLOCK_CHANNEL_RATE);
++ }
++
++ dal_write_reg(enc->ctx, addr, value);
++
++ addr = mmHDMI_VBI_PACKET_CONTROL + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_GC_CONT);
++ set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_GC_SEND);
++ set_reg_field_value(value, 1, HDMI_VBI_PACKET_CONTROL, HDMI_NULL_SEND);
++
++ dal_write_reg(enc->ctx, addr, value);
++
++ /* following belongs to audio */
++ addr = mmHDMI_INFOFRAME_CONTROL0 + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ HDMI_INFOFRAME_CONTROL0,
++ HDMI_AUDIO_INFO_SEND);
++ dal_write_reg(enc->ctx, addr, value);
++
++ addr = mmAFMT_INFOFRAME_CONTROL0 + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(
++ value,
++ 1,
++ AFMT_INFOFRAME_CONTROL0,
++ AFMT_AUDIO_INFO_UPDATE);
++ dal_write_reg(enc->ctx, addr, value);
++
++ addr = mmHDMI_INFOFRAME_CONTROL1 + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(
++ value,
++ VBI_LINE_0 + 2,
++ HDMI_INFOFRAME_CONTROL1,
++ HDMI_AUDIO_INFO_LINE);
++ dal_write_reg(enc->ctx, addr, value);
++
++ addr = mmHDMI_GC + fe_engine_offsets[engine];
++ value = dal_read_reg(enc->ctx, addr);
++ set_reg_field_value(value, 0, HDMI_GC, HDMI_GC_AVMUTE);
++ dal_write_reg(enc->ctx, addr, value);
++
++}
++
++static void set_tmds_stream_attributes(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ enum signal_type signal,
++ const struct dc_crtc_timing *timing)
++{
++ uint32_t addr = mmDIG_FE_CNTL + fe_engine_offsets[engine];
++ uint32_t value = dal_read_reg(enc->ctx, addr);
++
++ switch (timing->pixel_encoding) {
++ case PIXEL_ENCODING_YCBCR422:
++ set_reg_field_value(value, 1, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
++ break;
++ default:
++ set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_PIXEL_ENCODING);
++ break;
++ }
++
++ switch (timing->pixel_encoding) {
++ case COLOR_DEPTH_101010:
++ if ((signal == SIGNAL_TYPE_DVI_SINGLE_LINK
++ || signal == SIGNAL_TYPE_DVI_DUAL_LINK)
++ && timing->pixel_encoding == PIXEL_ENCODING_RGB)
++ set_reg_field_value(
++ value,
++ 2,
++ DIG_FE_CNTL,
++ TMDS_COLOR_FORMAT);
++ else
++ set_reg_field_value(
++ value,
++ 0,
++ DIG_FE_CNTL,
++ TMDS_COLOR_FORMAT);
++ break;
++ default:
++ set_reg_field_value(value, 0, DIG_FE_CNTL, TMDS_COLOR_FORMAT);
++ break;
++ }
++ dal_write_reg(enc->ctx, addr, value);
++}
++
++/*
++ * @brief
++ * Associate digital encoder with specified output transmitter
++ * and configure to output signal.
++ * Encoder will be activated later in enable_output()
++ */
++enum encoder_result dce110_stream_encoder_setup(
++ struct stream_encoder *enc,
++ struct dc_crtc_timing *crtc_timing,
++ enum signal_type signal,
++ bool enable_audio)
++{
++ if (!dc_is_dp_signal(signal)) {
++ struct bp_encoder_control cntl;
++
++ cntl.action = ENCODER_CONTROL_SETUP;
++ cntl.engine_id = enc->id;
++ cntl.signal = signal;
++ cntl.enable_dp_audio = enable_audio;
++ cntl.pixel_clock = crtc_timing->pix_clk_khz;
++ cntl.lanes_number = (signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
++ LANE_COUNT_EIGHT : LANE_COUNT_FOUR;
++ cntl.color_depth = crtc_timing->display_color_depth;
++
++ if (dal_bios_parser_encoder_control(
++ dal_adapter_service_get_bios_parser(
++ enc->adapter_service),
++ &cntl) != BP_RESULT_OK)
++ return ENCODER_RESULT_ERROR;
++ }
++
++ switch (signal) {
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ /* set signal format */
++ set_tmds_stream_attributes(
++ enc, enc->id, signal,
++ crtc_timing);
++ break;
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ /* set signal format */
++ set_tmds_stream_attributes(
++ enc, enc->id, signal,
++ crtc_timing);
++ /* setup HDMI engine */
++ setup_hdmi(
++ enc, enc->id, crtc_timing);
++ break;
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ /* set signal format */
++ set_dp_stream_attributes(enc, enc->id, crtc_timing);
++ break;
++ default:
++ break;
++ }
++
++ return ENCODER_RESULT_OK;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.h
+new file mode 100644
+index 0000000..d2c7b90
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_stream_encoder.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 __DC_STREAM_ENCODER_DCE110_H__
++#define __DC_STREAM_ENCODER_DCE110_H__
++
++struct stream_enc_init_data {
++ enum engine_id stream_engine_id;
++ struct adapter_service *adapter_service;
++ struct dc_context *ctx;
++};
++
++struct stream_encoder *dce110_stream_encoder_create(
++ struct stream_enc_init_data *init);
++
++void dce110_stream_encoder_destroy(struct stream_encoder **enc);
++
++void dce110_stream_encoder_stop_info_packets(
++ struct stream_encoder *enc,
++ enum engine_id engine,
++ enum signal_type signal);
++
++void dce110_stream_encoder_update_info_packets(
++ struct stream_encoder *enc,
++ enum signal_type signal,
++ const struct encoder_info_frame *info_frame);
++
++enum encoder_result dce110_stream_encoder_blank(
++ struct stream_encoder *enc,
++ enum signal_type signal);
++
++enum encoder_result dce110_stream_encoder_unblank(
++ struct stream_encoder *enc,
++ const struct encoder_unblank_param *param);
++
++enum encoder_result dce110_stream_encoder_setup(
++ struct stream_encoder *enc,
++ struct dc_crtc_timing *crtc_timing,
++ enum signal_type signal,
++ bool enable_audio);
++
++#endif /* __DC_STREAM_ENCODER_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
+new file mode 100644
+index 0000000..198ff28
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.c
+@@ -0,0 +1,1878 @@
++/*
++ * 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 "dal_services.h"
++
++/* include DCE11 register header files */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dc_types.h"
++
++#include "include/grph_object_id.h"
++#include "include/adapter_service_interface.h"
++#include "include/logger_interface.h"
++#include "include/timing_generator_types.h"
++#include "dce110_timing_generator.h"
++
++
++enum tg_regs_idx {
++ IDX_CRTC_UPDATE_LOCK,
++ IDX_CRTC_MASTER_UPDATE_LOCK,
++ IDX_CRTC_MASTER_UPDATE_MODE,
++ IDX_CRTC_H_TOTAL,
++ IDX_CRTC_V_TOTAL,
++ IDX_CRTC_H_BLANK_START_END,
++ IDX_CRTC_V_BLANK_START_END,
++ IDX_CRTC_H_SYNC_A,
++ IDX_CRTC_V_SYNC_A,
++ IDX_CRTC_H_SYNC_A_CNTL,
++ IDX_CRTC_V_SYNC_A_CNTL,
++ IDX_CRTC_INTERLACE_CONTROL,
++ IDX_CRTC_BLANK_CONTROL,
++ IDX_PIPE_PG_STATUS,
++
++ IDX_CRTC_TEST_PATTERN_COLOR,
++ IDX_CRTC_TEST_PATTERN_CONTROL,
++ IDX_CRTC_TEST_PATTERN_PARAMETERS,
++ IDX_CRTC_FLOW_CONTROL,
++ IDX_CRTC_STATUS,
++ IDX_CRTC_STATUS_POSITION,
++ IDX_CRTC_STATUS_FRAME_COUNT,
++ IDX_CRTC_STEREO_CONTROL,
++ IDX_CRTC_STEREO_STATUS,
++ IDX_CRTC_STEREO_FORCE_NEXT_EYE,
++ IDX_CRTC_3D_STRUCTURE_CONTROL,
++ IDX_CRTC_DOUBLE_BUFFER_CONTROL,
++ IDX_CRTC_V_TOTAL_MIN,
++ IDX_CRTC_V_TOTAL_MAX,
++ IDX_CRTC_V_TOTAL_CONTROL,
++ IDX_CRTC_NOM_VERT_POSITION,
++ IDX_CRTC_STATIC_SCREEN_CONTROL,
++ IDX_CRTC_TRIGB_CNTL,
++ IDX_CRTC_FORCE_COUNT_CNTL,
++ IDX_CRTC_GSL_CONTROL,
++ IDX_CRTC_GSL_WINDOW,
++
++ IDX_CRTC_CONTROL,
++ IDX_CRTC_START_LINE_CONTROL,
++ IDX_CRTC_COUNT_CONTROL,
++
++ IDX_MODE_EXT_OVERSCAN_LEFT_RIGHT,
++ IDX_MODE_EXT_OVERSCAN_TOP_BOTTOM,
++ IDX_DCP_GSL_CONTROL,
++ IDX_GRPH_UPDATE,
++
++ IDX_CRTC_VBI_END,
++
++ IDX_BLND_UNDERFLOW_INTERRUPT,
++ IDX_CRTC_BLACK_COLOR,
++ IDX_CRTC_OVERSCAN_COLOR,
++ IDX_CRTC_BLANK_DATA_COLOR,
++
++ TG_REGS_IDX_SIZE
++};
++
++enum black_color_format {
++ BLACK_COLOR_FORMAT_RGB_FULLRANGE = 0, /* used as index in array */
++ BLACK_COLOR_FORMAT_RGB_LIMITED,
++ BLACK_COLOR_FORMAT_YUV_TV,
++ BLACK_COLOR_FORMAT_YUV_CV,
++ BLACK_COLOR_FORMAT_YUV_SUPER_AA,
++
++ BLACK_COLOR_FORMAT_COUNT
++};
++
++#define regs_for_controller(id)\
++[CONTROLLER_ID_D ## id - 1] =\
++{[IDX_CRTC_UPDATE_LOCK] = mmCRTC ## id ## _CRTC_UPDATE_LOCK,\
++[IDX_CRTC_MASTER_UPDATE_LOCK] = mmCRTC ## id ## _CRTC_MASTER_UPDATE_LOCK,\
++[IDX_CRTC_MASTER_UPDATE_MODE] = mmCRTC ## id ## _CRTC_MASTER_UPDATE_MODE,\
++[IDX_CRTC_H_TOTAL] = mmCRTC ## id ## _CRTC_H_TOTAL,\
++[IDX_CRTC_V_TOTAL] = mmCRTC ## id ## _CRTC_V_TOTAL,\
++[IDX_CRTC_H_BLANK_START_END] = mmCRTC ## id ## _CRTC_H_BLANK_START_END,\
++[IDX_CRTC_V_BLANK_START_END] = mmCRTC ## id ## _CRTC_V_BLANK_START_END,\
++[IDX_CRTC_H_SYNC_A] = mmCRTC ## id ## _CRTC_H_SYNC_A,\
++[IDX_CRTC_V_SYNC_A] = mmCRTC ## id ## _CRTC_V_SYNC_A,\
++[IDX_CRTC_H_SYNC_A_CNTL] = mmCRTC ## id ## _CRTC_H_SYNC_A_CNTL,\
++[IDX_CRTC_V_SYNC_A_CNTL] = mmCRTC ## id ## _CRTC_V_SYNC_A_CNTL,\
++[IDX_CRTC_INTERLACE_CONTROL] = mmCRTC ## id ## _CRTC_INTERLACE_CONTROL,\
++[IDX_CRTC_BLANK_CONTROL] = mmCRTC ## id ## _CRTC_BLANK_CONTROL,\
++[IDX_PIPE_PG_STATUS] = mmPIPE ## id ## _PG_STATUS,\
++[IDX_CRTC_TEST_PATTERN_COLOR] = mmCRTC ## id ## _CRTC_TEST_PATTERN_COLOR,\
++[IDX_CRTC_TEST_PATTERN_CONTROL] = mmCRTC ## id ## _CRTC_TEST_PATTERN_CONTROL,\
++[IDX_CRTC_TEST_PATTERN_PARAMETERS] =\
++mmCRTC ## id ## _CRTC_TEST_PATTERN_PARAMETERS,\
++[IDX_CRTC_FLOW_CONTROL] = mmCRTC ## id ## _CRTC_FLOW_CONTROL,\
++[IDX_CRTC_STATUS] = mmCRTC ## id ## _CRTC_STATUS,\
++[IDX_CRTC_STATUS_POSITION] = mmCRTC ## id ## _CRTC_STATUS_POSITION,\
++[IDX_CRTC_STATUS_FRAME_COUNT] = mmCRTC ## id ## _CRTC_STATUS_FRAME_COUNT,\
++[IDX_CRTC_STEREO_CONTROL] = mmCRTC ## id ## _CRTC_STEREO_CONTROL,\
++[IDX_CRTC_STEREO_STATUS] = mmCRTC ## id ## _CRTC_STEREO_STATUS,\
++[IDX_CRTC_STEREO_FORCE_NEXT_EYE] = \
++mmCRTC ## id ## _CRTC_STEREO_FORCE_NEXT_EYE,\
++[IDX_CRTC_3D_STRUCTURE_CONTROL] = mmCRTC ## id ## _CRTC_3D_STRUCTURE_CONTROL,\
++[IDX_CRTC_DOUBLE_BUFFER_CONTROL] =\
++mmCRTC ## id ## _CRTC_DOUBLE_BUFFER_CONTROL,\
++[IDX_CRTC_V_TOTAL_MIN] = mmCRTC ## id ## _CRTC_V_TOTAL_MIN,\
++[IDX_CRTC_V_TOTAL_MAX] = mmCRTC ## id ## _CRTC_V_TOTAL_MAX,\
++[IDX_CRTC_V_TOTAL_CONTROL] = mmCRTC ## id ## _CRTC_V_TOTAL_CONTROL,\
++[IDX_CRTC_NOM_VERT_POSITION] = mmCRTC ## id ## _CRTC_NOM_VERT_POSITION,\
++[IDX_CRTC_STATIC_SCREEN_CONTROL] =\
++mmCRTC ## id ## _CRTC_STATIC_SCREEN_CONTROL,\
++[IDX_CRTC_TRIGB_CNTL] = mmCRTC ## id ## _CRTC_TRIGB_CNTL,\
++[IDX_CRTC_FORCE_COUNT_CNTL] = mmCRTC ## id ## _CRTC_FORCE_COUNT_NOW_CNTL,\
++[IDX_CRTC_GSL_CONTROL] = mmCRTC ## id ## _CRTC_GSL_CONTROL,\
++[IDX_CRTC_GSL_WINDOW] = mmCRTC ## id ## _CRTC_GSL_WINDOW,\
++[IDX_CRTC_CONTROL] = mmCRTC ## id ## _CRTC_CONTROL,\
++[IDX_CRTC_START_LINE_CONTROL] = mmCRTC ## id ## _CRTC_START_LINE_CONTROL,\
++[IDX_CRTC_COUNT_CONTROL] = mmCRTC ## id ## _CRTC_COUNT_CONTROL,\
++[IDX_MODE_EXT_OVERSCAN_LEFT_RIGHT] = mmSCL ## id ## _EXT_OVERSCAN_LEFT_RIGHT,\
++[IDX_MODE_EXT_OVERSCAN_TOP_BOTTOM] = mmSCL ## id ## _EXT_OVERSCAN_TOP_BOTTOM,\
++[IDX_DCP_GSL_CONTROL] = mmDCP ## id ## _DCP_GSL_CONTROL,\
++[IDX_GRPH_UPDATE] = mmDCP ## id ## _GRPH_UPDATE,\
++[IDX_CRTC_VBI_END] = mmCRTC ## id ## _CRTC_VBI_END,\
++[IDX_BLND_UNDERFLOW_INTERRUPT] = mmBLND ## id ## _BLND_UNDERFLOW_INTERRUPT,\
++[IDX_CRTC_BLACK_COLOR] = mmCRTC ## id ## _CRTC_BLACK_COLOR,\
++[IDX_CRTC_OVERSCAN_COLOR] = mmCRTC ## id ## _CRTC_OVERSCAN_COLOR,\
++[IDX_CRTC_BLANK_DATA_COLOR] = mmCRTC ## id ## _CRTC_BLANK_DATA_COLOR,\
++}
++
++#define NUMBER_OF_FRAME_TO_WAIT_ON_TRIGGERED_RESET 10
++
++#define MAX_H_TOTAL (CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1)
++#define MAX_V_TOTAL (CRTC_V_TOTAL__CRTC_V_TOTAL_MASKhw + 1)
++
++
++#define FROM_TIMING_GENERATOR(tg)\
++ container_of(tg, struct dce110_timing_generator, base)
++
++static uint32_t tg_regs[][TG_REGS_IDX_SIZE] = {
++ regs_for_controller(0),
++ regs_for_controller(1),
++ regs_for_controller(2),
++};
++
++/*******************************************************************************
++ * GSL Sync related values */
++
++/* In VSync mode, after 4 units of time, master pipe will generate
++ * flip_ready signal */
++#define VFLIP_READY_DELAY 4
++/* In HSync mode, after 2 units of time, master pipe will generate
++ * flip_ready signal */
++#define HFLIP_READY_DELAY 2
++/* 6 lines delay between forcing flip and checking all pipes ready */
++#define HFLIP_CHECK_DELAY 6
++/* 3 lines before end of frame */
++#define FLIP_READY_BACK_LOOKUP 3
++
++/* Trigger Source Select - ASIC-dependant, actual values for the
++ * register programming */
++enum trigger_source_select {
++ TRIGGER_SOURCE_SELECT_LOGIC_ZERO = 0,
++ TRIGGER_SOURCE_SELECT_CRTC_VSYNCA = 1,
++ TRIGGER_SOURCE_SELECT_CRTC_HSYNCA = 2,
++ TRIGGER_SOURCE_SELECT_CRTC_VSYNCB = 3,
++ TRIGGER_SOURCE_SELECT_CRTC_HSYNCB = 4,
++ TRIGGER_SOURCE_SELECT_GENERICF = 5,
++ TRIGGER_SOURCE_SELECT_GENERICE = 6,
++ TRIGGER_SOURCE_SELECT_VSYNCA = 7,
++ TRIGGER_SOURCE_SELECT_HSYNCA = 8,
++ TRIGGER_SOURCE_SELECT_VSYNCB = 9,
++ TRIGGER_SOURCE_SELECT_HSYNCB = 10,
++ TRIGGER_SOURCE_SELECT_HPD1 = 11,
++ TRIGGER_SOURCE_SELECT_HPD2 = 12,
++ TRIGGER_SOURCE_SELECT_GENERICD = 13,
++ TRIGGER_SOURCE_SELECT_GENERICC = 14,
++ TRIGGER_SOURCE_SELECT_VIDEO_CAPTURE = 15,
++ TRIGGER_SOURCE_SELECT_GSL_GROUP0 = 16,
++ TRIGGER_SOURCE_SELECT_GSL_GROUP1 = 17,
++ TRIGGER_SOURCE_SELECT_GSL_GROUP2 = 18,
++ TRIGGER_SOURCE_SELECT_BLONY = 19,
++ TRIGGER_SOURCE_SELECT_GENERICA = 20,
++ TRIGGER_SOURCE_SELECT_GENERICB = 21,
++ TRIGGER_SOURCE_SELECT_GSL_ALLOW_FLIP = 22,
++ TRIGGER_SOURCE_SELECT_MANUAL_TRIGGER = 23
++};
++
++/* Trigger Source Select - ASIC-dependant, actual values for the
++ * register programming */
++enum trigger_polarity_select {
++ TRIGGER_POLARITY_SELECT_LOGIC_ZERO = 0,
++ TRIGGER_POLARITY_SELECT_CRTC = 1,
++ TRIGGER_POLARITY_SELECT_GENERICA = 2,
++ TRIGGER_POLARITY_SELECT_GENERICB = 3,
++ TRIGGER_POLARITY_SELECT_HSYNCA = 4,
++ TRIGGER_POLARITY_SELECT_HSYNCB = 5,
++ TRIGGER_POLARITY_SELECT_VIDEO_CAPTURE = 6,
++ TRIGGER_POLARITY_SELECT_GENERICC = 7
++};
++
++/******************************************************************************/
++
++bool dce110_timing_generator_construct(
++ struct timing_generator *tg,
++ enum controller_id id)
++{
++ tg->controller_id = id;
++ return true;
++}
++
++static const struct crtc_black_color black_color_format[] = {
++ /* BlackColorFormat_RGB_FullRange */
++ {0, 0, 0},
++ /* BlackColorFormat_RGB_Limited */
++ {CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_RGB_LIMITED_RANGE,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_RGB_LIMITED_RANGE,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_RGB_LIMITED_RANGE},
++ /* BlackColorFormat_YUV_TV */
++ {CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4TV,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4TV,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4TV},
++ /* BlackColorFormat_YUV_CV */
++ {CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4CV,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4CV,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4CV},
++ /* BlackColorFormat_YUV_SuperAA */
++ {CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4SUPERAA,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4SUPERAA,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4SUPERAA}
++};
++
++void dce110_timing_generator_color_space_to_black_color(
++ enum color_space colorspace,
++ struct crtc_black_color *black_color)
++{
++ switch (colorspace) {
++ case COLOR_SPACE_YPBPR601:
++ *black_color = black_color_format[BLACK_COLOR_FORMAT_YUV_TV];
++ break;
++
++ case COLOR_SPACE_YPBPR709:
++ case COLOR_SPACE_YCBCR601:
++ case COLOR_SPACE_YCBCR709:
++ *black_color = black_color_format[BLACK_COLOR_FORMAT_YUV_CV];
++ break;
++
++ case COLOR_SPACE_N_MVPU_SUPER_AA:
++ /* In crossfire SuperAA mode, the slave overscan data is forced
++ * to 0 in the pixel mixer on the master. As a result, we need
++ * to adjust the blank color so that after blending the
++ * master+slave, it will appear black
++ */
++ *black_color =
++ black_color_format[BLACK_COLOR_FORMAT_YUV_SUPER_AA];
++ break;
++
++ case COLOR_SPACE_SRGB_LIMITED_RANGE:
++ *black_color =
++ black_color_format[BLACK_COLOR_FORMAT_RGB_LIMITED];
++ break;
++
++ default:
++ /* fefault is sRGB black (full range). */
++ *black_color =
++ black_color_format[BLACK_COLOR_FORMAT_RGB_FULLRANGE];
++ /* default is sRGB black 0. */
++ break;
++ }
++}
++
++/**
++* apply_front_porch_workaround
++*
++* This is a workaround for a bug that has existed since R5xx and has not been
++* fixed keep Front porch at minimum 2 for Interlaced mode or 1 for progressive.
++*/
++void dce110_timing_generator_apply_front_porch_workaround(
++ struct timing_generator *tg,
++ struct dc_crtc_timing *timing)
++{
++ if (timing->flags.INTERLACE == 1) {
++ if (timing->v_front_porch < 2)
++ timing->v_front_porch = 2;
++ } else {
++ if (timing->v_front_porch < 1)
++ timing->v_front_porch = 1;
++ }
++}
++
++int32_t dce110_timing_generator_get_vsynch_and_front_porch_size(
++ const struct dc_crtc_timing *timing)
++{
++ return timing->v_sync_width + timing->v_front_porch;
++}
++
++
++void dce110_timing_generator_set_early_control(
++ struct timing_generator *tg,
++ uint32_t early_cntl)
++{
++ uint32_t regval;
++ uint32_t address = tg->regs[IDX_CRTC_CONTROL];
++
++ regval = dal_read_reg(tg->ctx, address);
++ set_reg_field_value(regval, early_cntl,
++ CRTC_CONTROL, CRTC_HBLANK_EARLY_CONTROL);
++ dal_write_reg(tg->ctx, address, regval);
++}
++
++/**
++ * Enable CRTC
++ * Enable CRTC - call ASIC Control Object to enable Timing generator.
++ */
++bool dce110_timing_generator_enable_crtc(struct timing_generator *tg)
++{
++ enum bp_result result;
++
++ /* 0 value is needed by DRR and is also suggested default value for CZ
++ */
++ uint32_t value;
++
++ value = dal_read_reg(tg->ctx,
++ tg->regs[IDX_CRTC_MASTER_UPDATE_MODE]);
++ set_reg_field_value(value, 3,
++ CRTC_MASTER_UPDATE_MODE, MASTER_UPDATE_MODE);
++ dal_write_reg(tg->ctx,
++ tg->regs[IDX_CRTC_MASTER_UPDATE_MODE], value);
++
++ result = dal_bios_parser_enable_crtc(tg->bp, tg->controller_id, true);
++
++ return result == BP_RESULT_OK;
++}
++
++void dce110_timing_generator_program_blank_color(
++ struct timing_generator *tg,
++ enum color_space color_space)
++{
++ struct crtc_black_color black_color;
++ uint32_t addr = tg->regs[IDX_CRTC_BLACK_COLOR];
++ uint32_t value = dal_read_reg(tg->ctx, addr);
++
++ dce110_timing_generator_color_space_to_black_color(
++ color_space,
++ &black_color);
++
++ set_reg_field_value(
++ value,
++ black_color.black_color_b_cb,
++ CRTC_BLACK_COLOR,
++ CRTC_BLACK_COLOR_B_CB);
++ set_reg_field_value(
++ value,
++ black_color.black_color_g_y,
++ CRTC_BLACK_COLOR,
++ CRTC_BLACK_COLOR_G_Y);
++ set_reg_field_value(
++ value,
++ black_color.black_color_r_cr,
++ CRTC_BLACK_COLOR,
++ CRTC_BLACK_COLOR_R_CR);
++
++ dal_write_reg(tg->ctx, addr, value);
++}
++
++/**
++ * blank_crtc
++ * Call ASIC Control Object to Blank CRTC.
++ */
++
++bool dce110_timing_generator_blank_crtc(struct timing_generator *tg)
++{
++ uint32_t addr = tg->regs[IDX_CRTC_BLANK_CONTROL];
++ uint32_t value = dal_read_reg(tg->ctx, addr);
++ uint8_t counter = 100;
++
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_BLANK_CONTROL,
++ CRTC_BLANK_DATA_EN);
++
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_BLANK_CONTROL,
++ CRTC_BLANK_DE_MODE);
++
++ dal_write_reg(tg->ctx, addr, value);
++
++ while (counter > 0) {
++ value = dal_read_reg(tg->ctx, addr);
++
++ if (get_reg_field_value(
++ value,
++ CRTC_BLANK_CONTROL,
++ CRTC_BLANK_DATA_EN) == 1 &&
++ get_reg_field_value(
++ value,
++ CRTC_BLANK_CONTROL,
++ CRTC_CURRENT_BLANK_STATE) == 1)
++ break;
++
++ dc_service_sleep_in_milliseconds(tg->ctx, 1);
++ counter--;
++ }
++
++ if (!counter) {
++ dal_logger_write(tg->ctx->logger, LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ "timing generator %d blank timing out.\n",
++ tg->controller_id);
++ return false;
++ }
++
++ return true;
++}
++
++/**
++ * unblank_crtc
++ * Call ASIC Control Object to UnBlank CRTC.
++ */
++bool dce110_timing_generator_unblank_crtc(struct timing_generator *tg)
++{
++ uint32_t addr = tg->regs[IDX_CRTC_BLANK_CONTROL];
++ uint32_t value = dal_read_reg(tg->ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ CRTC_BLANK_CONTROL,
++ CRTC_BLANK_DATA_EN);
++
++ set_reg_field_value(
++ value,
++ 0,
++ CRTC_BLANK_CONTROL,
++ CRTC_BLANK_DE_MODE);
++
++ dal_write_reg(tg->ctx, addr, value);
++
++ return true;
++}
++
++/**
++ *****************************************************************************
++ * Function: is_in_vertical_blank
++ *
++ * @brief
++ * check the current status of CRTC to check if we are in Vertical Blank
++ * regioneased" state
++ *
++ * @return
++ * true if currently in blank region, false otherwise
++ *
++ *****************************************************************************
++ */
++bool dce110_timing_generator_is_in_vertical_blank(struct timing_generator *tg)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++ uint32_t field = 0;
++
++ addr = tg->regs[IDX_CRTC_STATUS];
++ value = dal_read_reg(tg->ctx, addr);
++ field = get_reg_field_value(value, CRTC_STATUS, CRTC_V_BLANK);
++ return field == 1;
++}
++
++/**
++ *****************************************************************************
++ * Function: disable_stereo
++ *
++ * @brief
++ * Disables active stereo on controller
++ * Frame Packing need to be disabled in vBlank or when CRTC not running
++ *****************************************************************************
++ */
++#if 0
++@TODOSTEREO
++static void disable_stereo(struct timing_generator *tg)
++{
++ uint32_t addr = tg->regs[IDX_CRTC_3D_STRUCTURE_CONTROL];
++ uint32_t value = 0;
++ uint32_t test = 0;
++ uint32_t field = 0;
++ uint32_t struc_en = 0;
++ uint32_t struc_stereo_sel_ovr = 0;
++
++ value = dal_read_reg(tg->ctx, addr);
++ struc_en = get_reg_field_value(
++ value,
++ CRTC_3D_STRUCTURE_CONTROL,
++ CRTC_3D_STRUCTURE_EN);
++
++ struc_stereo_sel_ovr = get_reg_field_value(
++ value,
++ CRTC_3D_STRUCTURE_CONTROL,
++ CRTC_3D_STRUCTURE_STEREO_SEL_OVR);
++
++ /*
++ * When disabling Frame Packing in 2 step mode, we need to program both
++ * registers at the same frame
++ * Programming it in the beginning of VActive makes sure we are ok
++ */
++
++ if (struc_en != 0 && struc_stereo_sel_ovr == 0) {
++ tg->funcs->wait_for_vblank(tg);
++ tg->funcs->wait_for_vactive(tg);
++ }
++
++ value = 0;
++ dal_write_reg(tg->ctx, addr, value);
++
++
++ addr = tg->regs[IDX_CRTC_STEREO_CONTROL];
++ dal_write_reg(tg->ctx, addr, value);
++}
++#endif
++
++/**
++ * disable_crtc - call ASIC Control Object to disable Timing generator.
++ */
++bool dce110_timing_generator_disable_crtc(struct timing_generator *tg)
++{
++ enum bp_result result;
++
++ result = dal_bios_parser_enable_crtc(tg->bp, tg->controller_id, false);
++
++ /* Need to make sure stereo is disabled according to the DCE5.0 spec */
++
++ /*
++ * @TODOSTEREO call this when adding stereo support
++ * tg->funcs->disable_stereo(tg);
++ */
++
++ return result == BP_RESULT_OK;
++}
++
++/**
++* program_horz_count_by_2
++* Programs DxCRTC_HORZ_COUNT_BY2_EN - 1 for DVI 30bpp mode, 0 otherwise
++*
++*/
++static void program_horz_count_by_2(
++ struct timing_generator *tg,
++ const struct dc_crtc_timing *timing)
++{
++ uint32_t regval;
++
++ regval = dal_read_reg(tg->ctx,
++ tg->regs[IDX_CRTC_COUNT_CONTROL]);
++
++ set_reg_field_value(regval, 0, CRTC_COUNT_CONTROL,
++ CRTC_HORZ_COUNT_BY2_EN);
++
++ if (timing->flags.HORZ_COUNT_BY_TWO)
++ set_reg_field_value(regval, 1, CRTC_COUNT_CONTROL,
++ CRTC_HORZ_COUNT_BY2_EN);
++
++ dal_write_reg(tg->ctx,
++ tg->regs[IDX_CRTC_COUNT_CONTROL], regval);
++}
++
++/**
++ * program_timing_generator
++ * Program CRTC Timing Registers - DxCRTC_H_*, DxCRTC_V_*, Pixel repetition.
++ * Call ASIC Control Object to program Timings.
++ */
++bool dce110_timing_generator_program_timing_generator(
++ struct timing_generator *tg,
++ struct dc_crtc_timing *dc_crtc_timing)
++{
++ enum bp_result result;
++ struct bp_hw_crtc_timing_parameters bp_params;
++ uint32_t regval;
++
++ uint32_t vsync_offset = dc_crtc_timing->v_border_bottom +
++ dc_crtc_timing->v_front_porch;
++ uint32_t v_sync_start =dc_crtc_timing->v_addressable + vsync_offset;
++
++ uint32_t hsync_offset = dc_crtc_timing->h_border_right +
++ dc_crtc_timing->h_front_porch;
++ uint32_t h_sync_start = dc_crtc_timing->h_addressable + hsync_offset;
++
++ dc_service_memset(&bp_params, 0, sizeof(struct bp_hw_crtc_timing_parameters));
++
++ /* Due to an asic bug we need to apply the Front Porch workaround prior
++ * to programming the timing.
++ */
++ dce110_timing_generator_apply_front_porch_workaround(tg, dc_crtc_timing);
++
++ bp_params.controller_id = tg->controller_id;
++
++ bp_params.h_total = dc_crtc_timing->h_total;
++ bp_params.h_addressable =
++ dc_crtc_timing->h_addressable;
++ bp_params.v_total = dc_crtc_timing->v_total;
++ bp_params.v_addressable = dc_crtc_timing->v_addressable;
++
++ bp_params.h_sync_start = h_sync_start;
++ bp_params.h_sync_width = dc_crtc_timing->h_sync_width;
++ bp_params.v_sync_start = v_sync_start;
++ bp_params.v_sync_width = dc_crtc_timing->v_sync_width;
++
++ /* Set overscan */
++ bp_params.h_overscan_left =
++ dc_crtc_timing->h_border_left;
++ bp_params.h_overscan_right =
++ dc_crtc_timing->h_border_right;
++ bp_params.v_overscan_top = dc_crtc_timing->v_border_top;
++ bp_params.v_overscan_bottom =
++ dc_crtc_timing->v_border_bottom;
++
++ /* Set flags */
++ if (dc_crtc_timing->flags.HSYNC_POSITIVE_POLARITY == 1)
++ bp_params.flags.HSYNC_POSITIVE_POLARITY = 1;
++
++ if (dc_crtc_timing->flags.VSYNC_POSITIVE_POLARITY == 1)
++ bp_params.flags.VSYNC_POSITIVE_POLARITY = 1;
++
++ if (dc_crtc_timing->flags.INTERLACE == 1)
++ bp_params.flags.INTERLACE = 1;
++
++ if (dc_crtc_timing->flags.HORZ_COUNT_BY_TWO == 1)
++ bp_params.flags.HORZ_COUNT_BY_TWO = 1;
++
++ result = dal_bios_parser_program_crtc_timing(tg->bp, &bp_params);
++
++ program_horz_count_by_2(tg, dc_crtc_timing);
++
++
++ regval = dal_read_reg(tg->ctx,
++ tg->regs[IDX_CRTC_START_LINE_CONTROL]);
++
++ if (dce110_timing_generator_get_vsynch_and_front_porch_size(dc_crtc_timing) <= 3) {
++ set_reg_field_value(regval, 3,
++ CRTC_START_LINE_CONTROL,
++ CRTC_ADVANCED_START_LINE_POSITION);
++
++ set_reg_field_value(regval, 0,
++ CRTC_START_LINE_CONTROL,
++ CRTC_PREFETCH_EN);
++ } else {
++ set_reg_field_value(regval, 4,
++ CRTC_START_LINE_CONTROL,
++ CRTC_ADVANCED_START_LINE_POSITION);
++
++ set_reg_field_value(regval, 1,
++ CRTC_START_LINE_CONTROL,
++ CRTC_PREFETCH_EN);
++ }
++ dal_write_reg(tg->ctx,
++ tg->regs[IDX_CRTC_START_LINE_CONTROL], regval);
++
++ /* Enable stereo - only when we need to pack 3D frame. Other types
++ * of stereo handled in explicit call */
++
++ /* TODOSTEREO
++ if (hw_crtc_timing->flags.PACK_3D_FRAME) {
++ struct crtc_stereo_parameters stereo_params = { false };
++ stereo_params.PROGRAM_STEREO = true;
++ stereo_params.PROGRAM_POLARITY = true;
++ stereo_params.FRAME_PACKED = true;
++ stereo_params.RIGHT_EYE_POLARITY =
++ hw_crtc_timing->flags.RIGHT_EYE_3D_POLARITY;
++ tg->funcs->enable_stereo(tg, &stereo_params);
++ }*/
++
++ return result == BP_RESULT_OK;
++}
++
++/**
++ *****************************************************************************
++ * Function: program_drr
++ *
++ * @brief
++ * Program dynamic refresh rate registers m_DxCRTC_V_TOTAL_*.
++ *
++ * @param [in] pHwCrtcTiming: point to H
++ * wCrtcTiming struct
++ *****************************************************************************
++ */
++void dce110_timing_generator_program_drr(
++ struct timing_generator *tg,
++ const struct hw_ranged_timing *timing)
++{
++ /* register values */
++ uint32_t v_total_min = 0;
++ uint32_t v_total_max = 0;
++ uint32_t v_total_cntl = 0;
++ uint32_t static_screen_cntl = 0;
++
++ uint32_t addr = 0;
++
++ addr = tg->regs[IDX_CRTC_V_TOTAL_MIN];
++ v_total_min = dal_read_reg(tg->ctx, addr);
++
++ addr = tg->regs[IDX_CRTC_V_TOTAL_MAX];
++ v_total_max = dal_read_reg(tg->ctx, addr);
++
++ addr = tg->regs[IDX_CRTC_V_TOTAL_CONTROL];
++ v_total_cntl = dal_read_reg(tg->ctx, addr);
++
++ addr = tg->regs[IDX_CRTC_STATIC_SCREEN_CONTROL];
++ static_screen_cntl = dal_read_reg(tg->ctx, addr);
++
++ if (timing != NULL) {
++ /* Set Static Screen trigger events
++ * If CRTC_SET_V_TOTAL_MIN_MASK_EN is set, use legacy event mask
++ * register
++ */
++ if (get_reg_field_value(
++ v_total_cntl,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_SET_V_TOTAL_MIN_MASK_EN)) {
++ set_reg_field_value(v_total_cntl,
++ /* TODO: add implementation
++ translate_to_dce_static_screen_events(
++ timing->control.event_mask.u_all),
++ */ 0,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_SET_V_TOTAL_MIN_MASK);
++ } else {
++ set_reg_field_value(static_screen_cntl,
++ /* TODO: add implementation
++ translate_to_dce_static_screen_events(
++ timing->control.event_mask.u_all),
++ */ 0,
++ CRTC_STATIC_SCREEN_CONTROL,
++ CRTC_STATIC_SCREEN_EVENT_MASK);
++ }
++
++ /* Number of consecutive static screen frames before interrupt
++ * is triggered. 0 is an invalid setting, which means we should
++ * leaving HW setting unchanged. */
++ if (timing->control.static_frame_count != 0) {
++ set_reg_field_value(
++ static_screen_cntl,
++ timing->control.static_frame_count,
++ CRTC_STATIC_SCREEN_CONTROL,
++ CRTC_STATIC_SCREEN_FRAME_COUNT);
++ }
++
++ /* This value is reduced by 1 based on the register definition
++ * of the VTOTAL value:
++ * CRTC_V_TOTAL should be set to Vertical total minus one. (E.g.
++ * for 525 lines, set to 524 = 0x20C)
++ */
++ set_reg_field_value(v_total_min,
++ timing->vertical_total_min,
++ CRTC_V_TOTAL_MIN,
++ CRTC_V_TOTAL_MIN);
++ set_reg_field_value(v_total_max,
++ timing->vertical_total_max,
++ CRTC_V_TOTAL_MAX,
++ CRTC_V_TOTAL_MAX);
++
++ /* set VTotalControl value according to ranged timing control.
++ */
++
++ if (timing->vertical_total_min != 0) {
++ set_reg_field_value(v_total_cntl,
++ 1,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_V_TOTAL_MIN_SEL);
++ } else {
++ set_reg_field_value(v_total_cntl,
++ 0,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_V_TOTAL_MIN_SEL);
++ }
++ if (timing->vertical_total_max != 0) {
++ set_reg_field_value(v_total_cntl,
++ 1,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_V_TOTAL_MAX_SEL);
++ } else {
++ set_reg_field_value(v_total_cntl,
++ 0,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_V_TOTAL_MAX_SEL);
++ }
++ set_reg_field_value(v_total_cntl,
++ timing->control.force_lock_on_event,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_FORCE_LOCK_ON_EVENT);
++ set_reg_field_value(v_total_cntl,
++ timing->control.lock_to_master_vsync,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_FORCE_LOCK_TO_MASTER_VSYNC);
++ } else {
++ set_reg_field_value(v_total_cntl,
++ 0,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_SET_V_TOTAL_MIN_MASK);
++ set_reg_field_value(static_screen_cntl,
++ 0,
++ CRTC_STATIC_SCREEN_CONTROL,
++ CRTC_STATIC_SCREEN_EVENT_MASK);
++ set_reg_field_value(v_total_min,
++ 0,
++ CRTC_V_TOTAL_MIN,
++ CRTC_V_TOTAL_MIN);
++ set_reg_field_value(v_total_max,
++ 0,
++ CRTC_V_TOTAL_MAX,
++ CRTC_V_TOTAL_MAX);
++ set_reg_field_value(v_total_cntl,
++ 0,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_V_TOTAL_MIN_SEL);
++ set_reg_field_value(v_total_cntl,
++ 0,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_V_TOTAL_MAX_SEL);
++ set_reg_field_value(v_total_cntl,
++ 0,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_FORCE_LOCK_ON_EVENT);
++ set_reg_field_value(v_total_cntl,
++ 0,
++ CRTC_V_TOTAL_CONTROL,
++ CRTC_FORCE_LOCK_TO_MASTER_VSYNC);
++ }
++
++ addr = tg->regs[IDX_CRTC_V_TOTAL_MIN];
++ dal_write_reg(tg->ctx, addr, v_total_min);
++
++ addr = tg->regs[IDX_CRTC_V_TOTAL_MAX];
++ dal_write_reg(tg->ctx, addr, v_total_max);
++
++ addr = tg->regs[IDX_CRTC_V_TOTAL_CONTROL];
++ dal_write_reg(tg->ctx, addr, v_total_cntl);
++
++ addr = tg->regs[IDX_CRTC_STATIC_SCREEN_CONTROL];
++ dal_write_reg(tg->ctx, addr, static_screen_cntl);
++}
++
++/*
++ * get_vblank_counter
++ *
++ * @brief
++ * Get counter for vertical blanks. use register CRTC_STATUS_FRAME_COUNT which
++ * holds the counter of frames.
++ *
++ * @param
++ * struct timing_generator *tg - [in] timing generator which controls the
++ * desired CRTC
++ *
++ * @return
++ * Counter of frames, which should equal to number of vblanks.
++ */
++uint32_t dce110_timing_generator_get_vblank_counter(struct timing_generator *tg)
++{
++ uint32_t addr = tg->regs[IDX_CRTC_STATUS_FRAME_COUNT];
++ uint32_t value = dal_read_reg(tg->ctx, addr);
++ uint32_t field = get_reg_field_value(
++ value, CRTC_STATUS_FRAME_COUNT, CRTC_FRAME_COUNT);
++
++ return field;
++}
++
++/**
++ *****************************************************************************
++ * Function: dce110_get_crtc_positions
++ *
++ * @brief
++ * Returns CRTC vertical/horizontal counters
++ *
++ * @param [out] v_position, h_position
++ *****************************************************************************
++ */
++
++void dce110_timing_generator_get_crtc_positions(
++ struct timing_generator *tg,
++ int32_t *h_position,
++ int32_t *v_position)
++{
++ uint32_t value;
++
++ value = dal_read_reg(tg->ctx, tg->regs[IDX_CRTC_STATUS_POSITION]);
++
++ *h_position = get_reg_field_value(
++ value,
++ CRTC_STATUS_POSITION,
++ CRTC_HORZ_COUNT);
++
++ *v_position = get_reg_field_value(
++ value,
++ CRTC_STATUS_POSITION,
++ CRTC_VERT_COUNT);
++}
++
++/**
++ *****************************************************************************
++ * Function: get_crtc_scanoutpos
++ *
++ * @brief
++ * Returns CRTC vertical/horizontal counters
++ *
++ * @param [out] vpos, hpos
++ *****************************************************************************
++ */
++uint32_t dce110_timing_generator_get_crtc_scanoutpos(
++ struct timing_generator *tg,
++ int32_t *vbl,
++ int32_t *position)
++{
++ /* TODO 1: Update the implementation once caller is updated
++ * WARNING!! This function is returning the whole register value
++ * because the caller is expecting it instead of proper vertical and
++ * horizontal position. This should be a temporary implementation
++ * until the caller is updated. */
++
++ /* TODO 2: re-use dce110_timing_generator_get_crtc_positions() */
++
++ *vbl = dal_read_reg(tg->ctx,
++ tg->regs[IDX_CRTC_V_BLANK_START_END]);
++
++ *position = dal_read_reg(tg->ctx,
++ tg->regs[IDX_CRTC_STATUS_POSITION]);
++
++ /* @TODO: return value should indicate if current
++ * crtc is inside vblank*/
++ return 0;
++}
++
++/* TODO: is it safe to assume that mask/shift of Primary and Underlay
++ * are the same?
++ * For example: today CRTC_H_TOTAL == CRTCV_H_TOTAL but is it always
++ * guaranteed? */
++void dce110_timing_generator_program_blanking(
++ struct timing_generator *tg,
++ const struct dc_crtc_timing *timing)
++{
++ uint32_t vsync_offset = timing->v_border_bottom +
++ timing->v_front_porch;
++ uint32_t v_sync_start =timing->v_addressable + vsync_offset;
++
++ uint32_t hsync_offset = timing->h_border_right +
++ timing->h_front_porch;
++ uint32_t h_sync_start = timing->h_addressable + hsync_offset;
++
++ struct dc_context *ctx = tg->ctx;
++ uint32_t value = 0;
++ uint32_t addr = 0;
++ uint32_t tmp = 0;
++
++ addr = tg->regs[IDX_CRTC_H_TOTAL];
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ timing->h_total - 1,
++ CRTC_H_TOTAL,
++ CRTC_H_TOTAL);
++ dal_write_reg(ctx, addr, value);
++
++ addr = tg->regs[IDX_CRTC_V_TOTAL];
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ timing->v_total - 1,
++ CRTC_V_TOTAL,
++ CRTC_V_TOTAL);
++ dal_write_reg(ctx, addr, value);
++
++ addr = tg->regs[IDX_CRTC_H_BLANK_START_END];
++ value = dal_read_reg(ctx, addr);
++
++ tmp = timing->h_total -
++ (h_sync_start + timing->h_border_left);
++
++ set_reg_field_value(
++ value,
++ tmp,
++ CRTC_H_BLANK_START_END,
++ CRTC_H_BLANK_END);
++
++ tmp = tmp + timing->h_addressable +
++ timing->h_border_left + timing->h_border_right;
++
++ set_reg_field_value(
++ value,
++ tmp,
++ CRTC_H_BLANK_START_END,
++ CRTC_H_BLANK_START);
++
++ dal_write_reg(ctx, addr, value);
++
++ addr = tg->regs[IDX_CRTC_V_BLANK_START_END];
++ value = dal_read_reg(ctx, addr);
++
++ tmp = timing->v_total - (v_sync_start + timing->v_border_top);
++
++ set_reg_field_value(
++ value,
++ tmp,
++ CRTC_V_BLANK_START_END,
++ CRTC_V_BLANK_END);
++
++ tmp = tmp + timing->v_addressable + timing->v_border_top +
++ timing->v_border_bottom;
++
++ set_reg_field_value(
++ value,
++ tmp,
++ CRTC_V_BLANK_START_END,
++ CRTC_V_BLANK_START);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++void dce110_timing_generator_set_test_pattern(
++ struct timing_generator *tg,
++ /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode'
++ * because this is not DP-specific (which is probably somewhere in DP
++ * encoder) */
++ enum controller_dp_test_pattern test_pattern,
++ enum dc_color_depth color_depth)
++{
++ struct dc_context *ctx = tg->ctx;
++ uint32_t value;
++ uint32_t addr;
++
++ /* TODO: add support for other test patterns */
++ switch (test_pattern) {
++ default:
++ value = 0;
++ addr = tg->regs[IDX_CRTC_TEST_PATTERN_PARAMETERS];
++
++ set_reg_field_value(
++ value,
++ 6,
++ CRTC_TEST_PATTERN_PARAMETERS,
++ CRTC_TEST_PATTERN_VRES);
++ set_reg_field_value(
++ value,
++ 6,
++ CRTC_TEST_PATTERN_PARAMETERS,
++ CRTC_TEST_PATTERN_HRES);
++
++ dal_write_reg(ctx, addr, value);
++
++ addr = tg->regs[IDX_CRTC_TEST_PATTERN_CONTROL];
++ value = 0;
++
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_TEST_PATTERN_CONTROL,
++ CRTC_TEST_PATTERN_EN);
++
++ set_reg_field_value(
++ value,
++ 0,
++ CRTC_TEST_PATTERN_CONTROL,
++ CRTC_TEST_PATTERN_MODE);
++
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_TEST_PATTERN_CONTROL,
++ CRTC_TEST_PATTERN_DYNAMIC_RANGE);
++ /* add color depth translation here */
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_TEST_PATTERN_CONTROL,
++ CRTC_TEST_PATTERN_COLOR_FORMAT);
++ dal_write_reg(ctx, addr, value);
++ break;
++ } /* switch() */
++}
++
++/**
++* dce110_timing_generator_validate_timing
++* The timing generators support a maximum display size of is 8192 x 8192 pixels,
++* including both active display and blanking periods. Check H Total and V Total.
++*/
++bool dce110_timing_generator_validate_timing(
++ struct timing_generator *tg,
++ const struct dc_crtc_timing *timing,
++ enum signal_type signal)
++{
++ uint32_t h_blank;
++ uint32_t h_back_porch;
++ uint32_t hsync_offset = timing->h_border_right +
++ timing->h_front_porch;
++ uint32_t h_sync_start = timing->h_addressable + hsync_offset;
++
++ ASSERT(timing != NULL);
++
++ if (!timing)
++ return false;
++
++ /* Check maximum number of pixels supported by Timing Generator
++ * (Currently will never fail, in order to fail needs display which
++ * needs more than 8192 horizontal and
++ * more than 8192 vertical total pixels)
++ */
++ if (timing->h_total > tg->max_h_total ||
++ timing->v_total > tg->max_v_total)
++ return false;
++
++ h_blank = (timing->h_total - timing->h_addressable -
++ timing->h_border_right -
++ timing->h_border_left);
++
++ if (h_blank < tg->min_h_blank)
++ return false;
++
++ if (timing->h_front_porch < tg->min_h_front_porch)
++ return false;
++
++ h_back_porch = h_blank - (h_sync_start -
++ timing->h_addressable -
++ timing->h_border_right -
++ timing->h_sync_width);
++
++ if (h_back_porch < tg->min_h_back_porch)
++ return false;
++
++ return true;
++}
++
++/**
++* Wait till we are at the beginning of VBlank.
++*/
++void dce110_timing_generator_wait_for_vblank(struct timing_generator *tg)
++{
++ /* We want to catch beginning of VBlank here, so if the first try are
++ * in VBlank, we might be very close to Active, in this case wait for
++ * another frame
++ */
++ while (dce110_timing_generator_is_in_vertical_blank(tg)) {
++ if (!dce110_timing_generator_is_counter_moving(tg)) {
++ /* error - no point to wait if counter is not moving */
++ break;
++ }
++ }
++
++ while (!dce110_timing_generator_is_in_vertical_blank(tg)) {
++ if (!dce110_timing_generator_is_counter_moving(tg)) {
++ /* error - no point to wait if counter is not moving */
++ break;
++ }
++ }
++}
++
++/**
++* Wait till we are in VActive (anywhere in VActive)
++*/
++void dce110_timing_generator_wait_for_vactive(struct timing_generator *tg)
++{
++ while (dce110_timing_generator_is_in_vertical_blank(tg)) {
++ if (!dce110_timing_generator_is_counter_moving(tg)) {
++ /* error - no point to wait if counter is not moving */
++ break;
++ }
++ }
++}
++
++void dce110_timing_generator_destroy(struct timing_generator **tg)
++{
++ dc_service_free((*tg)->ctx, FROM_TIMING_GENERATOR(*tg));
++ *tg = NULL;
++}
++
++static bool timing_generator_dce110_construct(struct timing_generator *tg,
++ struct dc_context *ctx,
++ struct adapter_service *as,
++ enum controller_id id)
++{
++ if (!as)
++ return false;
++
++ switch (id) {
++ case CONTROLLER_ID_D0:
++ case CONTROLLER_ID_D1:
++ case CONTROLLER_ID_D2:
++ break;
++ default:
++ return false;
++ }
++
++ if (!dce110_timing_generator_construct(tg, id))
++ return false;
++
++ tg->ctx = ctx;
++ tg->bp = dal_adapter_service_get_bios_parser(as);
++ tg->regs = tg_regs[id-1];
++
++ tg->max_h_total = CRTC_H_TOTAL__CRTC_H_TOTAL_MASK + 1;
++ tg->max_v_total = CRTC_V_TOTAL__CRTC_V_TOTAL_MASK + 1;
++
++ tg->min_h_blank = 56;
++ tg->min_h_front_porch = 4;
++ tg->min_h_back_porch = 4;
++
++ return true;
++}
++
++struct timing_generator *dce110_timing_generator_create(
++ struct adapter_service *as,
++ struct dc_context *ctx,
++ enum controller_id id)
++{
++ struct dce110_timing_generator *tg =
++ dc_service_alloc(ctx, sizeof(struct dce110_timing_generator));
++
++ if (!tg)
++ return NULL;
++
++ if (timing_generator_dce110_construct(&tg->base, ctx,
++ as, id))
++ return &tg->base;
++
++ BREAK_TO_DEBUGGER();
++ dc_service_free(ctx, tg);
++ return NULL;
++}
++
++/**
++ *****************************************************************************
++ * Function: dce110_timing_generator_setup_global_swap_lock
++ *
++ * @brief
++ * Setups Global Swap Lock group for current pipe
++ * Pipe can join or leave GSL group, become a TimingServer or TimingClient
++ *
++ * @param [in] gsl_params: setup data
++ *****************************************************************************
++ */
++
++void dce110_timing_generator_setup_global_swap_lock(
++ struct timing_generator *tg,
++ const struct dcp_gsl_params *gsl_params)
++{
++ uint32_t value;
++ uint32_t address = tg->regs[IDX_DCP_GSL_CONTROL];
++ uint32_t check_point = FLIP_READY_BACK_LOOKUP;
++
++ value = dal_read_reg(tg->ctx, address);
++
++ /* This pipe will belong to GSL Group zero. */
++ set_reg_field_value(value,
++ 1,
++ DCP_GSL_CONTROL,
++ DCP_GSL0_EN);
++
++ set_reg_field_value(value,
++ gsl_params->timing_server,
++ DCP_GSL_CONTROL,
++ DCP_GSL_MASTER_EN);
++
++ set_reg_field_value(value,
++ HFLIP_READY_DELAY,
++ DCP_GSL_CONTROL,
++ DCP_GSL_HSYNC_FLIP_FORCE_DELAY);
++
++ /* Keep signal low (pending high) during 6 lines.
++ * Also defines minimum interval before re-checking signal. */
++ set_reg_field_value(value,
++ HFLIP_CHECK_DELAY,
++ DCP_GSL_CONTROL,
++ DCP_GSL_HSYNC_FLIP_CHECK_DELAY);
++
++ /* DCP_GSL_PURPOSE_SURFACE_FLIP */
++ {
++ uint32_t value_crtc_vtotal;
++
++ value_crtc_vtotal = dal_read_reg(tg->ctx, tg->regs[IDX_CRTC_V_TOTAL]);
++
++ set_reg_field_value(value,
++ gsl_params->gsl_purpose,
++ DCP_GSL_CONTROL,
++ DCP_GSL_SYNC_SOURCE);
++
++ /* Checkpoint relative to end of frame */
++ check_point = get_reg_field_value(value_crtc_vtotal,
++ CRTC_V_TOTAL,
++ CRTC_V_TOTAL);
++
++ dal_write_reg(tg->ctx, tg->regs[IDX_CRTC_GSL_WINDOW], 0);
++ }
++
++ set_reg_field_value(value,
++ 1,
++ DCP_GSL_CONTROL,
++ DCP_GSL_DELAY_SURFACE_UPDATE_PENDING);
++
++ dal_write_reg(tg->ctx, address, value);
++
++ /********************************************************************/
++ address = tg->regs[IDX_CRTC_GSL_CONTROL];
++
++ value = 0;
++ set_reg_field_value(value,
++ check_point - FLIP_READY_BACK_LOOKUP,
++ CRTC_GSL_CONTROL,
++ CRTC_GSL_CHECK_LINE_NUM);
++
++ set_reg_field_value(value,
++ VFLIP_READY_DELAY,
++ CRTC_GSL_CONTROL,
++ CRTC_GSL_FORCE_DELAY);
++
++ dal_write_reg(tg->ctx, address, value);
++}
++
++
++void dce110_timing_generator_tear_down_global_swap_lock(
++ struct timing_generator *tg)
++{
++ /* Clear all the register writes done by
++ * dce110_timing_generator_setup_global_swap_lock
++ */
++
++ uint32_t value;
++ uint32_t address = tg->regs[IDX_DCP_GSL_CONTROL];
++
++ value = 0;
++
++ /* This pipe will belong to GSL Group zero. */
++ /* Settig HW default values from reg specs */
++ set_reg_field_value(value,
++ 0,
++ DCP_GSL_CONTROL,
++ DCP_GSL0_EN);
++
++ set_reg_field_value(value,
++ 0,
++ DCP_GSL_CONTROL,
++ DCP_GSL_MASTER_EN);
++
++ set_reg_field_value(value,
++ 0x2,
++ DCP_GSL_CONTROL,
++ DCP_GSL_HSYNC_FLIP_FORCE_DELAY);
++
++
++ set_reg_field_value(value,
++ 0x6,
++ DCP_GSL_CONTROL,
++ DCP_GSL_HSYNC_FLIP_CHECK_DELAY);
++
++ /* Restore DCP_GSL_PURPOSE_SURFACE_FLIP */
++ {
++ uint32_t value_crtc_vtotal;
++
++ value_crtc_vtotal = dal_read_reg(tg->ctx, tg->regs[IDX_CRTC_V_TOTAL]);
++
++ set_reg_field_value(value,
++ 0,
++ DCP_GSL_CONTROL,
++ DCP_GSL_SYNC_SOURCE);
++ }
++
++ set_reg_field_value(value,
++ 0,
++ DCP_GSL_CONTROL,
++ DCP_GSL_DELAY_SURFACE_UPDATE_PENDING);
++
++ dal_write_reg(tg->ctx, address, value);
++
++ /********************************************************************/
++ address = tg->regs[IDX_CRTC_GSL_CONTROL];
++
++ value = 0;
++ set_reg_field_value(value,
++ 0,
++ CRTC_GSL_CONTROL,
++ CRTC_GSL_CHECK_LINE_NUM);
++
++ set_reg_field_value(value,
++ 0x2,
++ CRTC_GSL_CONTROL,
++ CRTC_GSL_FORCE_DELAY);
++
++ dal_write_reg(tg->ctx, address, value);
++}
++/**
++ *****************************************************************************
++ * Function: is_counter_moving
++ *
++ * @brief
++ * check if the timing generator is currently going
++ *
++ * @return
++ * true if currently going, false if currently paused or stopped.
++ *
++ *****************************************************************************
++ */
++
++bool dce110_timing_generator_is_counter_moving(struct timing_generator *tg)
++{
++ uint32_t addr = 0;
++ uint32_t value_1 = 0;
++ uint32_t field_1 = 0;
++ uint32_t value_2 = 0;
++ uint32_t field_2 = 0;
++
++ addr = tg->regs[IDX_CRTC_STATUS_POSITION];
++ value_1 = dal_read_reg(tg->ctx, addr);
++ value_2 = dal_read_reg(tg->ctx, addr);
++
++ field_1 = get_reg_field_value(
++ value_1, CRTC_STATUS_POSITION, CRTC_HORZ_COUNT);
++ field_2 = get_reg_field_value(
++ value_2, CRTC_STATUS_POSITION, CRTC_HORZ_COUNT);
++
++ if (field_1 == field_2) {
++ field_1 = get_reg_field_value(
++ value_1, CRTC_STATUS_POSITION, CRTC_VERT_COUNT);
++ field_2 = get_reg_field_value(
++ value_2, CRTC_STATUS_POSITION, CRTC_VERT_COUNT);
++ return field_1 != field_2;
++ }
++
++ return true;
++}
++
++/*TODO: Figure out if we need this function. */
++void dce110_timing_generator_enable_advanced_request(
++ struct timing_generator *tg,
++ bool enable,
++ const struct dc_crtc_timing *timing)
++{
++ uint32_t addr = tg->regs[IDX_CRTC_START_LINE_CONTROL];
++ uint32_t value = dal_read_reg(tg->ctx, addr);
++
++ if (enable && FROM_TIMING_GENERATOR(tg)->advanced_request_enable) {
++ set_reg_field_value(
++ value,
++ 0,
++ CRTC_START_LINE_CONTROL,
++ CRTC_LEGACY_REQUESTOR_EN);
++ } else {
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_START_LINE_CONTROL,
++ CRTC_LEGACY_REQUESTOR_EN);
++ }
++
++ if (dce110_timing_generator_get_vsynch_and_front_porch_size(timing) <= 3) {
++ set_reg_field_value(
++ value,
++ 3,
++ CRTC_START_LINE_CONTROL,
++ CRTC_ADVANCED_START_LINE_POSITION);
++ set_reg_field_value(
++ value,
++ 0,
++ CRTC_START_LINE_CONTROL,
++ CRTC_PREFETCH_EN);
++ } else {
++ set_reg_field_value(
++ value,
++ 4,
++ CRTC_START_LINE_CONTROL,
++ CRTC_ADVANCED_START_LINE_POSITION);
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_START_LINE_CONTROL,
++ CRTC_PREFETCH_EN);
++ }
++
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_START_LINE_CONTROL,
++ CRTC_PROGRESSIVE_START_LINE_EARLY);
++
++ set_reg_field_value(
++ value,
++ 1,
++ CRTC_START_LINE_CONTROL,
++ CRTC_INTERLACE_START_LINE_EARLY);
++
++ dal_write_reg(tg->ctx, addr, value);
++}
++
++/*TODO: Figure out if we need this function. */
++void dce110_timing_generator_set_lock_master(struct timing_generator *tg,
++ bool lock)
++{
++ struct dc_context *ctx = tg->ctx;
++ uint32_t addr = tg->regs[IDX_CRTC_MASTER_UPDATE_LOCK];
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ lock ? 1 : 0,
++ CRTC_MASTER_UPDATE_LOCK,
++ MASTER_UPDATE_LOCK);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++void dce110_timing_generator_enable_reset_trigger(
++ struct timing_generator *tg,
++ const struct trigger_params *trigger_params)
++{
++ uint32_t value;
++ struct dc_context *dc_ctx = tg->ctx;
++ uint32_t rising_edge = 0;
++ uint32_t falling_edge = 0;
++ enum trigger_source_select trig_src_select = TRIGGER_SOURCE_SELECT_LOGIC_ZERO;
++
++ /* Setup trigger edge */
++ switch (trigger_params->edge) {
++ /* Default = based on current timing polarity */
++ case TRIGGER_EDGE_DEFAULT:
++ {
++ uint32_t pol_value = dal_read_reg(tg->ctx,
++ tg->regs[IDX_CRTC_V_SYNC_A_CNTL]);
++
++ /* Register spec has reversed definition:
++ * 0 for positive, 1 for negative */
++ if (get_reg_field_value(pol_value,
++ CRTC_V_SYNC_A_CNTL,
++ CRTC_V_SYNC_A_POL) == 0) {
++ rising_edge = 1;
++ } else {
++ falling_edge = 1;
++ }
++ }
++ break;
++ case TRIGGER_EDGE_RISING:
++ rising_edge = 1;
++ break;
++ case TRIGGER_EDGE_FALLING:
++ falling_edge = 1;
++ break;
++ case TRIGGER_EDGE_BOTH:
++ rising_edge = 1;
++ falling_edge = 1;
++ break;
++ default:
++ DC_ERROR("Invalid Trigger Edge!\n");
++ return;
++ }
++
++ value = dal_read_reg(tg->ctx, tg->regs[IDX_CRTC_TRIGB_CNTL]);
++
++ switch(trigger_params->source) {
++ /* Currently supporting only a single group, the group zero. */
++ case SYNC_SOURCE_GSL_GROUP0:
++ trig_src_select = TRIGGER_SOURCE_SELECT_GSL_GROUP0;
++ break;
++ default:
++ DC_ERROR("Unsupported GSL Group!\n");
++ return;
++ }
++
++ set_reg_field_value(value,
++ trig_src_select,
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_SOURCE_SELECT);
++
++ set_reg_field_value(value,
++ TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_POLARITY_SELECT);
++
++ set_reg_field_value(value,
++ rising_edge,
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_RISING_EDGE_DETECT_CNTL);
++
++ set_reg_field_value(value,
++ falling_edge,
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_FALLING_EDGE_DETECT_CNTL);
++
++ set_reg_field_value(value,
++ 0, /* send every signal */
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_FREQUENCY_SELECT);
++
++ set_reg_field_value(value,
++ 0, /* no delay */
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_DELAY);
++
++ set_reg_field_value(value,
++ 1, /* clear trigger status */
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_CLEAR);
++
++ dal_write_reg(tg->ctx, tg->regs[IDX_CRTC_TRIGB_CNTL], value);
++
++ /**************************************************************/
++
++ value = dal_read_reg(tg->ctx, tg->regs[IDX_CRTC_FORCE_COUNT_CNTL]);
++
++ set_reg_field_value(value,
++ 2, /* force H count to H_TOTAL and V count to V_TOTAL */
++ CRTC_FORCE_COUNT_NOW_CNTL,
++ CRTC_FORCE_COUNT_NOW_MODE);
++
++ set_reg_field_value(value,
++ 1, /* TriggerB - we never use TriggerA */
++ CRTC_FORCE_COUNT_NOW_CNTL,
++ CRTC_FORCE_COUNT_NOW_TRIG_SEL);
++
++ set_reg_field_value(value,
++ 1, /* clear trigger status */
++ CRTC_FORCE_COUNT_NOW_CNTL,
++ CRTC_FORCE_COUNT_NOW_CLEAR);
++
++ dal_write_reg(tg->ctx, tg->regs[IDX_CRTC_FORCE_COUNT_CNTL], value);
++}
++
++void dce110_timing_generator_disable_reset_trigger(
++ struct timing_generator *tg)
++{
++ uint32_t value;
++
++ value = dal_read_reg(tg->ctx, tg->regs[IDX_CRTC_FORCE_COUNT_CNTL]);
++
++ set_reg_field_value(value,
++ 0, /* force counter now mode is disabled */
++ CRTC_FORCE_COUNT_NOW_CNTL,
++ CRTC_FORCE_COUNT_NOW_MODE);
++
++ set_reg_field_value(value,
++ 1, /* clear trigger status */
++ CRTC_FORCE_COUNT_NOW_CNTL,
++ CRTC_FORCE_COUNT_NOW_CLEAR);
++
++ dal_write_reg(tg->ctx, tg->regs[IDX_CRTC_FORCE_COUNT_CNTL], value);
++
++ /********************************************************************/
++ value = dal_read_reg(tg->ctx, tg->regs[IDX_CRTC_TRIGB_CNTL]);
++
++ set_reg_field_value(value,
++ TRIGGER_SOURCE_SELECT_LOGIC_ZERO,
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_SOURCE_SELECT);
++
++ set_reg_field_value(value,
++ TRIGGER_POLARITY_SELECT_LOGIC_ZERO,
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_POLARITY_SELECT);
++
++ set_reg_field_value(value,
++ 1, /* clear trigger status */
++ CRTC_TRIGB_CNTL,
++ CRTC_TRIGB_CLEAR);
++
++ dal_write_reg(tg->ctx, tg->regs[IDX_CRTC_TRIGB_CNTL], value);
++}
++
++/**
++ *****************************************************************************
++ * @brief
++ * Checks whether CRTC triggered reset occurred
++ *
++ * @return
++ * true if triggered reset occurred, false otherwise
++ *****************************************************************************
++ */
++bool dce110_timing_generator_did_triggered_reset_occur(
++ struct timing_generator *tg)
++{
++ uint32_t value = dal_read_reg(tg->ctx, tg->regs[IDX_CRTC_FORCE_COUNT_CNTL]);
++
++ return get_reg_field_value(value,
++ CRTC_FORCE_COUNT_NOW_CNTL,
++ CRTC_FORCE_COUNT_NOW_OCCURRED) != 0;
++}
++
++/**
++ * dce110_timing_generator_disable_vga
++ * Turn OFF VGA Mode and Timing - DxVGA_CONTROL
++ * VGA Mode and VGA Timing is used by VBIOS on CRT Monitors;
++ */
++void dce110_timing_generator_disable_vga(
++ struct timing_generator *tg)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++ switch (tg->controller_id) {
++ case CONTROLLER_ID_D0:
++ addr = mmD1VGA_CONTROL;
++ break;
++ case CONTROLLER_ID_D1:
++ addr = mmD2VGA_CONTROL;
++ break;
++ case CONTROLLER_ID_D2:
++ addr = mmD3VGA_CONTROL;
++ break;
++ default:
++ break;
++ }
++ value = dal_read_reg(tg->ctx, addr);
++
++ set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_MODE_ENABLE);
++ set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_TIMING_SELECT);
++ set_reg_field_value(
++ value, 0, D1VGA_CONTROL, D1VGA_SYNC_POLARITY_SELECT);
++ set_reg_field_value(value, 0, D1VGA_CONTROL, D1VGA_OVERSCAN_COLOR_EN);
++
++ dal_write_reg(tg->ctx, addr, value);
++}
++
++
++/**
++* set_overscan_color_black
++*
++* @param :black_color is one of the color space
++* :this routine will set overscan black color according to the color space.
++* @return none
++*/
++
++void dce110_timing_generator_set_overscan_color_black(
++ struct timing_generator *tg,
++ enum color_space black_color)
++{
++ struct dc_context *ctx = tg->ctx;
++ uint32_t value = 0;
++ uint32_t addr;
++
++ /* Overscan Color for YUV display modes:
++ * to achieve a black color for both the explicit and implicit overscan,
++ * the overscan color registers should be programmed to: */
++
++ switch (black_color) {
++ case COLOR_SPACE_YPBPR601:
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4TV,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_BLUE);
++
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4TV,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_GREEN);
++
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4TV,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_RED);
++ break;
++
++ case COLOR_SPACE_YPBPR709:
++ case COLOR_SPACE_YCBCR601:
++ case COLOR_SPACE_YCBCR709:
++ case COLOR_SPACE_YCBCR601_YONLY:
++ case COLOR_SPACE_YCBCR709_YONLY:
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4CV,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_BLUE);
++
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4TV,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_GREEN);
++
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4CV,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_RED);
++ break;
++
++ case COLOR_SPACE_N_MVPU_SUPER_AA:
++ /* In crossfire SuperAA mode, the slave overscan data is forced
++ * to 0 in the pixel mixer on the master. As a result, we need
++ * to adjust the blank color so that after blending the
++ * master+slave, it will appear black */
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4SUPERAA,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_BLUE);
++
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4SUPERAA,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_GREEN);
++
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4SUPERAA,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_RED);
++ break;
++
++ case COLOR_SPACE_SRGB_LIMITED_RANGE:
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_RGB_LIMITED_RANGE,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_BLUE);
++
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_RGB_LIMITED_RANGE,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_GREEN);
++
++ set_reg_field_value(
++ value,
++ CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_RGB_LIMITED_RANGE,
++ CRTC_OVERSCAN_COLOR,
++ CRTC_OVERSCAN_COLOR_RED);
++ break;
++
++ default:
++ /* default is sRGB black 0. */
++ break;
++ }
++ addr = tg->regs[IDX_CRTC_OVERSCAN_COLOR];
++ dal_write_reg(ctx, addr, value);
++ addr = tg->regs[IDX_CRTC_BLACK_COLOR];
++ dal_write_reg(ctx, addr, value);
++ /* This is desirable to have a constant DAC output voltage during the
++ * blank time that is higher than the 0 volt reference level that the
++ * DAC outputs when the NBLANK signal
++ * is asserted low, such as for output to an analog TV. */
++ addr = tg->regs[IDX_CRTC_BLANK_DATA_COLOR];
++ dal_write_reg(ctx, addr, value);
++
++ /* TO DO we have to program EXT registers and we need to know LB DATA
++ * format because it is used when more 10 , i.e. 12 bits per color
++ *
++ * m_mmDxCRTC_OVERSCAN_COLOR_EXT
++ * m_mmDxCRTC_BLACK_COLOR_EXT
++ * m_mmDxCRTC_BLANK_DATA_COLOR_EXT
++ */
++
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.h
+new file mode 100644
+index 0000000..d95a2a0
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_timing_generator.h
+@@ -0,0 +1,178 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_TIMING_GENERATOR_DCE110_H__
++#define __DC_TIMING_GENERATOR_DCE110_H__
++
++
++#include "../include/timing_generator_types.h"
++#include "../include/grph_object_id.h"
++
++/* overscan in blank for YUV color space. For RGB, it is zero for black. */
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4CV 0x1f4
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4CV 0x40
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4CV 0x1f4
++
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4TV 0x200
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4TV 0x40
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4TV 0x200
++
++/* overscan in blank for YUV color space when in SuperAA crossfire mode */
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_CB_YUV_4SUPERAA 0x1a2
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_Y_YUV_4SUPERAA 0x20
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_CR_YUV_4SUPERAA 0x1a2
++
++/* OVERSCAN COLOR FOR RGB LIMITED RANGE
++ * (16~253) 16*4 (Multiple over 256 code leve) =64 (0x40) */
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_B_RGB_LIMITED_RANGE 0x40
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_G_RGB_LIMITED_RANGE 0x40
++#define CRTC_OVERSCAN_COLOR_BLACK_COLOR_R_RGB_LIMITED_RANGE 0X40
++
++struct dce110_timing_generator {
++ struct timing_generator base;
++ enum sync_source cached_gsl_group;
++ bool advanced_request_enable;
++};
++
++struct timing_generator *dce110_timing_generator_create(
++ struct adapter_service *as,
++ struct dc_context *ctx,
++ enum controller_id id);
++
++void dce110_timing_generator_destroy(struct timing_generator **tg);
++
++bool dce110_timing_generator_construct(
++ struct timing_generator *tg,
++ enum controller_id id);
++
++void dce110_timing_generator_program_blank_color(
++ struct timing_generator *tg,
++ enum color_space color_space);
++
++bool dce110_timing_generator_blank_crtc(struct timing_generator *tg);
++
++bool dce110_timing_generator_enable_crtc(struct timing_generator *tg);
++
++bool dce110_timing_generator_disable_crtc(struct timing_generator *tg);
++
++bool dce110_timing_generator_is_in_vertical_blank(struct timing_generator *tg);
++
++void dce110_timing_generator_program_blanking(
++ struct timing_generator *tg,
++ const struct dc_crtc_timing *timing);
++
++bool dce110_timing_generator_program_timing_generator(
++ struct timing_generator *tg,
++ struct dc_crtc_timing *dc_crtc_timing);
++
++void dce110_timing_generator_set_early_control(
++ struct timing_generator *tg,
++ uint32_t early_cntl);
++
++bool dce110_timing_generator_unblank_crtc(struct timing_generator *tg);
++
++bool dce110_timing_generator_validate_timing(
++ struct timing_generator *tg,
++ const struct dc_crtc_timing *timing,
++ enum signal_type signal);
++
++void dce110_timing_generator_wait_for_vblank(struct timing_generator *tg);
++
++void dce110_timing_generator_wait_for_vactive(struct timing_generator *tg);
++
++void dce110_timing_generator_set_test_pattern(
++ struct timing_generator *tg,
++ /* TODO: replace 'controller_dp_test_pattern' by 'test_pattern_mode'
++ * because this is not DP-specific (which is probably somewhere in DP
++ * encoder) */
++ enum controller_dp_test_pattern test_pattern,
++ enum dc_color_depth color_depth);
++
++void dce110_timing_generator_program_drr(
++ struct timing_generator *tg,
++ const struct hw_ranged_timing *timing);
++
++uint32_t dce110_timing_generator_get_crtc_scanoutpos(
++ struct timing_generator *tg,
++ int32_t *vbl,
++ int32_t *position);
++
++uint32_t dce110_timing_generator_get_vblank_counter(struct timing_generator *tg);
++
++void dce110_timing_generator_color_space_to_black_color(
++ enum color_space colorspace,
++ struct crtc_black_color *black_color);
++void dce110_timing_generator_apply_front_porch_workaround(
++ struct timing_generator *tg,
++ struct dc_crtc_timing *timing);
++int32_t dce110_timing_generator_get_vsynch_and_front_porch_size(
++ const struct dc_crtc_timing *timing);
++
++void dce110_timing_generator_get_crtc_positions(
++ struct timing_generator *tg,
++ int32_t *h_position,
++ int32_t *v_position);
++
++
++/* TODO: Figure out if we need these functions*/
++bool dce110_timing_generator_is_counter_moving(struct timing_generator *tg);
++
++void dce110_timing_generator_enable_advanced_request(
++ struct timing_generator *tg,
++ bool enable,
++ const struct dc_crtc_timing *timing);
++
++void dce110_timing_generator_set_lock_master(struct timing_generator *tg,
++ bool lock);
++
++void dce110_timing_generator_set_overscan_color_black(
++ struct timing_generator *tg,
++ enum color_space black_color);
++
++
++/**** Sync-related interfaces ****/
++void dce110_timing_generator_setup_global_swap_lock(
++ struct timing_generator *tg,
++ const struct dcp_gsl_params *gsl_params);
++void dce110_timing_generator_tear_down_global_swap_lock(
++ struct timing_generator *tg);
++
++
++void dce110_timing_generator_enable_reset_trigger(
++ struct timing_generator *tg,
++ const struct trigger_params *trigger_params);
++
++void dce110_timing_generator_disable_reset_trigger(
++ struct timing_generator *tg);
++
++bool dce110_timing_generator_did_triggered_reset_occur(
++ struct timing_generator *tg);
++
++void dce110_timing_generator_disable_vga(
++ struct timing_generator *tg);
++
++/**** End-of-Sync-related interfaces ****/
++
++#endif /* __DC_TIMING_GENERATOR_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform.c
+new file mode 100644
+index 0000000..f3b3630
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform.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 "dal_services.h"
++
++/* include DCE11 register header files */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dc_types.h"
++#include "core_types.h"
++
++#include "include/grph_object_id.h"
++#include "include/fixed31_32.h"
++#include "include/logger_interface.h"
++
++#include "dce110_transform.h"
++#include "dce110_transform_bit_depth.h"
++
++static const struct dce110_transform_reg_offsets reg_offsets[] = {
++{
++ .scl_offset = (mmSCL0_SCL_CONTROL - mmSCL0_SCL_CONTROL),
++ .dcfe_offset = (mmDCFE0_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP0_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .lb_offset = (mmLB0_LB_DATA_FORMAT - mmLB0_LB_DATA_FORMAT),
++},
++{ .scl_offset = (mmSCL1_SCL_CONTROL - mmSCL0_SCL_CONTROL),
++ .dcfe_offset = (mmDCFE1_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP1_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .lb_offset = (mmLB1_LB_DATA_FORMAT - mmLB0_LB_DATA_FORMAT),
++},
++{ .scl_offset = (mmSCL2_SCL_CONTROL - mmSCL0_SCL_CONTROL),
++ .dcfe_offset = (mmDCFE2_DCFE_MEM_PWR_CTRL - mmDCFE0_DCFE_MEM_PWR_CTRL),
++ .dcp_offset = (mmDCP2_GRPH_CONTROL - mmDCP0_GRPH_CONTROL),
++ .lb_offset = (mmLB2_LB_DATA_FORMAT - mmLB0_LB_DATA_FORMAT),
++}
++};
++
++/*****************************************/
++/* Constructor, Destructor */
++/*****************************************/
++
++bool dce110_transform_construct(
++ struct dce110_transform *xfm110,
++ struct dc_context *ctx,
++ uint32_t inst)
++{
++ if ((inst < 1) || (inst > ARRAY_SIZE(reg_offsets)))
++ return false;
++
++ xfm110->base.ctx = ctx;
++
++ xfm110->base.inst = inst;
++
++ xfm110->offsets = reg_offsets[inst - 1];
++
++ xfm110->lb_pixel_depth_supported =
++ LB_PIXEL_DEPTH_18BPP |
++ LB_PIXEL_DEPTH_24BPP |
++ LB_PIXEL_DEPTH_30BPP;
++
++ return true;
++}
++
++void dce110_transform_destroy(struct transform **xfm)
++{
++ dc_service_free((*xfm)->ctx, TO_DCE110_TRANSFORM(*xfm));
++ *xfm = NULL;
++}
++
++struct transform *dce110_transform_create(
++ struct dc_context *ctx,
++ uint32_t inst)
++{
++ struct dce110_transform *transform =
++ dc_service_alloc(ctx, sizeof(struct dce110_transform));
++
++ if (!transform)
++ return NULL;
++
++ if (dce110_transform_construct(transform,
++ ctx, inst))
++ return &transform->base;
++
++ BREAK_TO_DEBUGGER();
++ dc_service_free(ctx, transform);
++ return NULL;
++}
++
++bool dce110_transform_power_up(struct transform *xfm)
++{
++ return dce110_transform_power_up_line_buffer(xfm);
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform.h
+new file mode 100644
+index 0000000..edf016c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform.h
+@@ -0,0 +1,91 @@
++/* 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_TRANSFORM_DCE110_H__
++#define __DAL_TRANSFORM_DCE110_H__
++
++#include "inc/transform.h"
++#include "include/grph_csc_types.h"
++
++#define TO_DCE110_TRANSFORM(transform)\
++ container_of(transform, struct dce110_transform, base)
++
++struct dce110_transform_reg_offsets {
++ uint32_t scl_offset;
++ uint32_t dcfe_offset;
++ uint32_t dcp_offset;
++ uint32_t lb_offset;
++};
++
++struct dce110_transform {
++ struct transform base;
++ struct dce110_transform_reg_offsets offsets;
++
++ uint32_t lb_pixel_depth_supported;
++};
++
++bool dce110_transform_construct(struct dce110_transform *xfm110,
++ struct dc_context *ctx,
++ uint32_t inst);
++
++void dce110_transform_destroy(struct transform **xfm);
++
++struct transform *dce110_transform_create(
++ struct dc_context *ctx,
++ uint32_t inst);
++
++bool dce110_transform_power_up(struct transform *xfm);
++
++/* SCALER RELATED */
++bool dce110_transform_set_scaler(
++ struct transform *xfm,
++ const struct scaler_data *data);
++
++void dce110_transform_set_scaler_bypass(struct transform *xfm);
++
++bool dce110_transform_update_viewport(
++ struct transform *xfm,
++ const struct rect *view_port,
++ bool is_fbc_attached);
++
++void dce110_transform_set_scaler_filter(
++ struct transform *xfm,
++ struct scaler_filter *filter);
++
++/* GAMUT RELATED */
++void dce110_transform_set_gamut_remap(
++ struct transform *xfm,
++ const struct grph_csc_adjustment *adjust);
++
++/* BIT DEPTH RELATED */
++bool dce110_transform_set_pixel_storage_depth(
++ struct transform *xfm,
++ enum lb_pixel_depth depth);
++
++bool dce110_transform_get_current_pixel_storage_depth(
++ struct transform *xfm,
++ enum lb_pixel_depth *depth);
++
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_bit_depth.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_bit_depth.c
+new file mode 100644
+index 0000000..747f2c7
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_bit_depth.c
+@@ -0,0 +1,840 @@
++/*
++ * 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 "dal_services.h"
++
++/* include DCE11 register header files */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_transform.h"
++
++#include "include/logger_interface.h"
++#include "include/fixed32_32.h"
++
++#define DCP_REG(reg)\
++ (reg + xfm110->offsets.dcp_offset)
++
++#define LB_REG(reg)\
++ (reg + xfm110->offsets.lb_offset)
++
++#define LB_TOTAL_NUMBER_OF_ENTRIES 1712
++#define LB_BITS_PER_ENTRY 144
++
++enum dcp_out_trunc_round_mode {
++ DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE,
++ DCP_OUT_TRUNC_ROUND_MODE_ROUND
++};
++
++enum dcp_out_trunc_round_depth {
++ DCP_OUT_TRUNC_ROUND_DEPTH_14BIT,
++ DCP_OUT_TRUNC_ROUND_DEPTH_13BIT,
++ DCP_OUT_TRUNC_ROUND_DEPTH_12BIT,
++ DCP_OUT_TRUNC_ROUND_DEPTH_11BIT,
++ DCP_OUT_TRUNC_ROUND_DEPTH_10BIT,
++ DCP_OUT_TRUNC_ROUND_DEPTH_9BIT,
++ DCP_OUT_TRUNC_ROUND_DEPTH_8BIT
++};
++
++/* defines the various methods of bit reduction available for use */
++enum dcp_bit_depth_reduction_mode {
++ DCP_BIT_DEPTH_REDUCTION_MODE_DITHER,
++ DCP_BIT_DEPTH_REDUCTION_MODE_ROUND,
++ DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE,
++ DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED,
++ DCP_BIT_DEPTH_REDUCTION_MODE_INVALID
++};
++
++enum dcp_spatial_dither_mode {
++ DCP_SPATIAL_DITHER_MODE_AAAA,
++ DCP_SPATIAL_DITHER_MODE_A_AA_A,
++ DCP_SPATIAL_DITHER_MODE_AABBAABB,
++ DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC,
++ DCP_SPATIAL_DITHER_MODE_INVALID
++};
++
++enum dcp_spatial_dither_depth {
++ DCP_SPATIAL_DITHER_DEPTH_30BPP,
++ DCP_SPATIAL_DITHER_DEPTH_24BPP
++};
++
++static bool set_clamp(
++ struct dce110_transform *xfm110,
++ enum dc_color_depth depth);
++
++static bool set_round(
++ struct dce110_transform *xfm110,
++ enum dcp_out_trunc_round_mode mode,
++ enum dcp_out_trunc_round_depth depth);
++
++static bool set_dither(
++ struct dce110_transform *xfm110,
++ bool dither_enable,
++ enum dcp_spatial_dither_mode dither_mode,
++ enum dcp_spatial_dither_depth dither_depth,
++ bool frame_random_enable,
++ bool rgb_random_enable,
++ bool highpass_random_enable);
++
++/**
++ *******************************************************************************
++ * dce110_transform_bit_depth_reduction_program
++ *
++ * @brief
++ * Programs the DCP bit depth reduction registers (Clamp, Round/Truncate,
++ * Dither) for dce110
++ *
++ * @param depth : bit depth to set the clamp to (should match denorm)
++ *
++ * @return
++ * true if succeeds.
++ *******************************************************************************
++ */
++static bool program_bit_depth_reduction(
++ struct dce110_transform *xfm110,
++ enum dc_color_depth depth)
++{
++ enum dcp_bit_depth_reduction_mode depth_reduction_mode;
++ enum dcp_spatial_dither_mode spatial_dither_mode;
++ bool frame_random_enable;
++ bool rgb_random_enable;
++ bool highpass_random_enable;
++
++ if (depth > COLOR_DEPTH_121212) {
++ ASSERT_CRITICAL(false); /* Invalid clamp bit depth */
++ return false;
++ }
++
++ depth_reduction_mode = DCP_BIT_DEPTH_REDUCTION_MODE_DITHER;
++
++ spatial_dither_mode = DCP_SPATIAL_DITHER_MODE_A_AA_A;
++
++ frame_random_enable = true;
++ rgb_random_enable = true;
++ highpass_random_enable = true;
++
++ if (!set_clamp(xfm110, depth)) {
++ /* Failure in set_clamp() */
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++ switch (depth_reduction_mode) {
++ case DCP_BIT_DEPTH_REDUCTION_MODE_DITHER:
++ /* Spatial Dither: Set round/truncate to bypass (12bit),
++ * enable Dither (30bpp) */
++ set_round(xfm110,
++ DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE,
++ DCP_OUT_TRUNC_ROUND_DEPTH_12BIT);
++
++ set_dither(xfm110, true, spatial_dither_mode,
++ DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable,
++ rgb_random_enable, highpass_random_enable);
++ break;
++ case DCP_BIT_DEPTH_REDUCTION_MODE_ROUND:
++ /* Round: Enable round (10bit), disable Dither */
++ set_round(xfm110,
++ DCP_OUT_TRUNC_ROUND_MODE_ROUND,
++ DCP_OUT_TRUNC_ROUND_DEPTH_10BIT);
++
++ set_dither(xfm110, false, spatial_dither_mode,
++ DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable,
++ rgb_random_enable, highpass_random_enable);
++ break;
++ case DCP_BIT_DEPTH_REDUCTION_MODE_TRUNCATE: /* Truncate */
++ /* Truncate: Enable truncate (10bit), disable Dither */
++ set_round(xfm110,
++ DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE,
++ DCP_OUT_TRUNC_ROUND_DEPTH_10BIT);
++
++ set_dither(xfm110, false, spatial_dither_mode,
++ DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable,
++ rgb_random_enable, highpass_random_enable);
++ break;
++
++ case DCP_BIT_DEPTH_REDUCTION_MODE_DISABLED: /* Disabled */
++ /* Truncate: Set round/truncate to bypass (12bit),
++ * disable Dither */
++ set_round(xfm110,
++ DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE,
++ DCP_OUT_TRUNC_ROUND_DEPTH_12BIT);
++
++ set_dither(xfm110, false, spatial_dither_mode,
++ DCP_SPATIAL_DITHER_DEPTH_30BPP, frame_random_enable,
++ rgb_random_enable, highpass_random_enable);
++ break;
++ default:
++ /* Invalid DCP Depth reduction mode */
++ ASSERT_CRITICAL(false);
++ break;
++ }
++
++ return true;
++}
++
++/**
++ *******************************************************************************
++ * set_clamp
++ *
++ * @param depth : bit depth to set the clamp to (should match denorm)
++ *
++ * @brief
++ * Programs clamp according to panel bit depth.
++ *
++ * @return
++ * true if succeeds
++ *
++ *******************************************************************************
++ */
++static bool set_clamp(
++ struct dce110_transform *xfm110,
++ enum dc_color_depth depth)
++{
++ uint32_t clamp_max = 0;
++
++ /* At the clamp block the data will be MSB aligned, so we set the max
++ * clamp accordingly.
++ * For example, the max value for 6 bits MSB aligned (14 bit bus) would
++ * be "11 1111 0000 0000" in binary, so 0x3F00.
++ */
++ switch (depth) {
++ case COLOR_DEPTH_666:
++ /* 6bit MSB aligned on 14 bit bus '11 1111 0000 0000' */
++ clamp_max = 0x3F00;
++ break;
++ case COLOR_DEPTH_888:
++ /* 8bit MSB aligned on 14 bit bus '11 1111 1100 0000' */
++ clamp_max = 0x3FC0;
++ break;
++ case COLOR_DEPTH_101010:
++ /* 10bit MSB aligned on 14 bit bus '11 1111 1111 1100' */
++ clamp_max = 0x3FFC;
++ break;
++ case COLOR_DEPTH_121212:
++ /* 12bit MSB aligned on 14 bit bus '11 1111 1111 1111' */
++ clamp_max = 0x3FFF;
++ break;
++ default:
++ ASSERT_CRITICAL(false); /* Invalid clamp bit depth */
++ return false;
++ }
++
++ {
++ uint32_t value = 0;
++ /* always set min to 0 */
++ set_reg_field_value(
++ value,
++ 0,
++ OUT_CLAMP_CONTROL_B_CB,
++ OUT_CLAMP_MIN_B_CB);
++
++ set_reg_field_value(
++ value,
++ clamp_max,
++ OUT_CLAMP_CONTROL_B_CB,
++ OUT_CLAMP_MAX_B_CB);
++
++ dal_write_reg(xfm110->base.ctx,
++ DCP_REG(mmOUT_CLAMP_CONTROL_B_CB),
++ value);
++ }
++
++ {
++ uint32_t value = 0;
++ /* always set min to 0 */
++ set_reg_field_value(
++ value,
++ 0,
++ OUT_CLAMP_CONTROL_G_Y,
++ OUT_CLAMP_MIN_G_Y);
++
++ set_reg_field_value(
++ value,
++ clamp_max,
++ OUT_CLAMP_CONTROL_G_Y,
++ OUT_CLAMP_MAX_G_Y);
++
++ dal_write_reg(xfm110->base.ctx,
++ DCP_REG(mmOUT_CLAMP_CONTROL_G_Y),
++ value);
++ }
++
++ {
++ uint32_t value = 0;
++ /* always set min to 0 */
++ set_reg_field_value(
++ value,
++ 0,
++ OUT_CLAMP_CONTROL_R_CR,
++ OUT_CLAMP_MIN_R_CR);
++
++ set_reg_field_value(
++ value,
++ clamp_max,
++ OUT_CLAMP_CONTROL_R_CR,
++ OUT_CLAMP_MAX_R_CR);
++
++ dal_write_reg(xfm110->base.ctx,
++ DCP_REG(mmOUT_CLAMP_CONTROL_R_CR),
++ value);
++ }
++
++ return true;
++}
++
++/**
++ *******************************************************************************
++ * set_round
++ *
++ * @brief
++ * Programs Round/Truncate
++ *
++ * @param [in] mode :round or truncate
++ * @param [in] depth :bit depth to round/truncate to
++ OUT_ROUND_TRUNC_MODE 3:0 0xA Output data round or truncate mode
++ POSSIBLE VALUES:
++ 00 - truncate to u0.12
++ 01 - truncate to u0.11
++ 02 - truncate to u0.10
++ 03 - truncate to u0.9
++ 04 - truncate to u0.8
++ 05 - reserved
++ 06 - truncate to u0.14
++ 07 - truncate to u0.13 set_reg_field_value(
++ value,
++ clamp_max,
++ OUT_CLAMP_CONTROL_R_CR,
++ OUT_CLAMP_MAX_R_CR);
++ 08 - round to u0.12
++ 09 - round to u0.11
++ 10 - round to u0.10
++ 11 - round to u0.9
++ 12 - round to u0.8
++ 13 - reserved
++ 14 - round to u0.14
++ 15 - round to u0.13
++
++ * @return
++ * true if succeeds.
++ *******************************************************************************
++ */
++static bool set_round(
++ struct dce110_transform *xfm110,
++ enum dcp_out_trunc_round_mode mode,
++ enum dcp_out_trunc_round_depth depth)
++{
++ uint32_t depth_bits = 0;
++ uint32_t mode_bit = 0;
++ /* zero out all bits */
++ uint32_t value = 0;
++
++ /* set up bit depth */
++ switch (depth) {
++ case DCP_OUT_TRUNC_ROUND_DEPTH_14BIT:
++ depth_bits = 6;
++ break;
++ case DCP_OUT_TRUNC_ROUND_DEPTH_13BIT:
++ depth_bits = 7;
++ break;
++ case DCP_OUT_TRUNC_ROUND_DEPTH_12BIT:
++ depth_bits = 0;
++ break;
++ case DCP_OUT_TRUNC_ROUND_DEPTH_11BIT:
++ depth_bits = 1;
++ break;
++ case DCP_OUT_TRUNC_ROUND_DEPTH_10BIT:
++ depth_bits = 2;
++ break;
++ case DCP_OUT_TRUNC_ROUND_DEPTH_9BIT:
++ depth_bits = 3;
++ break;
++ case DCP_OUT_TRUNC_ROUND_DEPTH_8BIT:
++ depth_bits = 4;
++ break;
++ default:
++ /* Invalid dcp_out_trunc_round_depth */
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ set_reg_field_value(
++ value,
++ depth_bits,
++ OUT_ROUND_CONTROL,
++ OUT_ROUND_TRUNC_MODE);
++
++ /* set up round or truncate */
++ switch (mode) {
++ case DCP_OUT_TRUNC_ROUND_MODE_TRUNCATE:
++ mode_bit = 0;
++ break;
++ case DCP_OUT_TRUNC_ROUND_MODE_ROUND:
++ mode_bit = 1;
++ break;
++ default:
++ /* Invalid dcp_out_trunc_round_mode */
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ depth_bits |= mode_bit << 3;
++
++ set_reg_field_value(
++ value,
++ depth_bits,
++ OUT_ROUND_CONTROL,
++ OUT_ROUND_TRUNC_MODE);
++
++ /* write the register */
++ dal_write_reg(xfm110->base.ctx,
++ DCP_REG(mmOUT_ROUND_CONTROL),
++ value);
++
++ return true;
++}
++
++/**
++ *******************************************************************************
++ * set_dither
++ *
++ * @brief
++ * Programs Dither
++ *
++ * @param [in] dither_enable : enable dither
++ * @param [in] dither_mode : dither mode to set
++ * @param [in] dither_depth : bit depth to dither to
++ * @param [in] frame_random_enable : enable frame random
++ * @param [in] rgb_random_enable : enable rgb random
++ * @param [in] highpass_random_enable : enable highpass random
++ *
++ * @return
++ * true if succeeds.
++ *******************************************************************************
++ */
++
++static bool set_dither(
++ struct dce110_transform *xfm110,
++ bool dither_enable,
++ enum dcp_spatial_dither_mode dither_mode,
++ enum dcp_spatial_dither_depth dither_depth,
++ bool frame_random_enable,
++ bool rgb_random_enable,
++ bool highpass_random_enable)
++{
++ uint32_t dither_depth_bits = 0;
++ uint32_t dither_mode_bits = 0;
++ /* zero out all bits */
++ uint32_t value = 0;
++
++ /* set up the fields */
++ if (dither_enable)
++ set_reg_field_value(
++ value,
++ 1,
++ DCP_SPATIAL_DITHER_CNTL,
++ DCP_SPATIAL_DITHER_EN);
++
++ switch (dither_mode) {
++ case DCP_SPATIAL_DITHER_MODE_AAAA:
++ dither_mode_bits = 0;
++ break;
++ case DCP_SPATIAL_DITHER_MODE_A_AA_A:
++ dither_mode_bits = 1;
++ break;
++ case DCP_SPATIAL_DITHER_MODE_AABBAABB:
++ dither_mode_bits = 2;
++ break;
++ case DCP_SPATIAL_DITHER_MODE_AABBCCAABBCC:
++ dither_mode_bits = 3;
++ break;
++ default:
++ /* Invalid dcp_spatial_dither_mode */
++ ASSERT_CRITICAL(false);
++ return false;
++
++ }
++ set_reg_field_value(
++ value,
++ dither_mode_bits,
++ DCP_SPATIAL_DITHER_CNTL,
++ DCP_SPATIAL_DITHER_MODE);
++
++ switch (dither_depth) {
++ case DCP_SPATIAL_DITHER_DEPTH_30BPP:
++ dither_depth_bits = 0;
++ break;
++ case DCP_SPATIAL_DITHER_DEPTH_24BPP:
++ dither_depth_bits = 1;
++ break;
++ default:
++ /* Invalid dcp_spatial_dither_depth */
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ set_reg_field_value(
++ value,
++ dither_depth_bits,
++ DCP_SPATIAL_DITHER_CNTL,
++ DCP_SPATIAL_DITHER_DEPTH);
++
++ if (frame_random_enable)
++ set_reg_field_value(
++ value,
++ 1,
++ DCP_SPATIAL_DITHER_CNTL,
++ DCP_FRAME_RANDOM_ENABLE);
++
++ if (rgb_random_enable)
++ set_reg_field_value(
++ value,
++ 1,
++ DCP_SPATIAL_DITHER_CNTL,
++ DCP_RGB_RANDOM_ENABLE);
++
++ if (highpass_random_enable)
++ set_reg_field_value(
++ value,
++ 1,
++ DCP_SPATIAL_DITHER_CNTL,
++ DCP_HIGHPASS_RANDOM_ENABLE);
++
++ /* write the register */
++ dal_write_reg(xfm110->base.ctx,
++ DCP_REG(mmDCP_SPATIAL_DITHER_CNTL),
++ value);
++
++ return true;
++}
++
++bool dce110_transform_get_max_num_of_supported_lines(
++ struct dce110_transform *xfm110,
++ enum lb_pixel_depth depth,
++ uint32_t pixel_width,
++ uint32_t *lines)
++{
++ uint32_t pixels_per_entries = 0;
++ uint32_t max_pixels_supports = 0;
++
++ if (pixel_width == 0)
++ return false;
++
++ /* Find number of pixels that can fit into a single LB entry and
++ * take floor of the value since we cannot store a single pixel
++ * across multiple entries. */
++ switch (depth) {
++ case LB_PIXEL_DEPTH_18BPP:
++ pixels_per_entries = LB_BITS_PER_ENTRY / 18;
++ break;
++
++ case LB_PIXEL_DEPTH_24BPP:
++ pixels_per_entries = LB_BITS_PER_ENTRY / 24;
++ break;
++
++ case LB_PIXEL_DEPTH_30BPP:
++ pixels_per_entries = LB_BITS_PER_ENTRY / 30;
++ break;
++
++ case LB_PIXEL_DEPTH_36BPP:
++ pixels_per_entries = LB_BITS_PER_ENTRY / 36;
++ break;
++
++ default:
++ dal_logger_write(xfm110->base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Invalid LB pixel depth",
++ __func__);
++ break;
++ }
++
++ if (pixels_per_entries == 0)
++ return false;
++
++ max_pixels_supports = pixels_per_entries * LB_TOTAL_NUMBER_OF_ENTRIES;
++
++ *lines = max_pixels_supports / pixel_width;
++ return true;
++}
++
++void dce110_transform_enable_alpha(
++ struct dce110_transform *xfm110,
++ bool enable)
++{
++ struct dc_context *ctx = xfm110->base.ctx;
++ uint32_t value;
++ uint32_t addr = LB_REG(mmLB_DATA_FORMAT);
++
++ value = dal_read_reg(ctx, addr);
++
++ if (enable == 1)
++ set_reg_field_value(
++ value,
++ 1,
++ LB_DATA_FORMAT,
++ ALPHA_EN);
++ else
++ set_reg_field_value(
++ value,
++ 0,
++ LB_DATA_FORMAT,
++ ALPHA_EN);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static enum lb_pixel_depth translate_display_bpp_to_lb_depth(
++ uint32_t display_bpp)
++{
++ switch (display_bpp) {
++ case 18:
++ return LB_PIXEL_DEPTH_18BPP;
++ case 24:
++ return LB_PIXEL_DEPTH_24BPP;
++ case 36:
++ case 42:
++ case 48:
++ return LB_PIXEL_DEPTH_36BPP;
++ case 30:
++ default:
++ return LB_PIXEL_DEPTH_30BPP;
++ }
++}
++
++bool dce110_transform_get_next_lower_pixel_storage_depth(
++ struct dce110_transform *xfm110,
++ uint32_t display_bpp,
++ enum lb_pixel_depth depth,
++ enum lb_pixel_depth *lower_depth)
++{
++ enum lb_pixel_depth depth_req_by_display =
++ translate_display_bpp_to_lb_depth(display_bpp);
++ uint32_t current_required_depth = depth_req_by_display;
++ uint32_t current_depth = depth;
++
++ /* if required display depth < current we could go down, for example
++ * from LB_PIXEL_DEPTH_30BPP to LB_PIXEL_DEPTH_24BPP
++ */
++ if (current_required_depth < current_depth) {
++ current_depth = current_depth >> 1;
++ if (xfm110->lb_pixel_depth_supported & current_depth) {
++ *lower_depth = current_depth;
++ return true;
++ }
++ }
++ return false;
++}
++
++bool dce110_transform_is_prefetch_enabled(
++ struct dce110_transform *xfm110)
++{
++ uint32_t value = dal_read_reg(
++ xfm110->base.ctx, LB_REG(mmLB_DATA_FORMAT));
++
++ if (get_reg_field_value(value, LB_DATA_FORMAT, PREFETCH) == 1)
++ return true;
++
++ return false;
++}
++
++bool dce110_transform_get_current_pixel_storage_depth(
++ struct transform *xfm,
++ enum lb_pixel_depth *depth)
++{
++ struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm);
++ uint32_t value = 0;
++
++ if (depth == NULL)
++ return false;
++
++ value = dal_read_reg(
++ xfm->ctx,
++ LB_REG(mmLB_DATA_FORMAT));
++
++ switch (get_reg_field_value(value, LB_DATA_FORMAT, PIXEL_DEPTH)) {
++ case 0:
++ *depth = LB_PIXEL_DEPTH_30BPP;
++ break;
++ case 1:
++ *depth = LB_PIXEL_DEPTH_24BPP;
++ break;
++ case 2:
++ *depth = LB_PIXEL_DEPTH_18BPP;
++ break;
++ case 3:
++ *depth = LB_PIXEL_DEPTH_36BPP;
++ break;
++ default:
++ dal_logger_write(xfm->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Invalid LB pixel depth",
++ __func__);
++ *depth = LB_PIXEL_DEPTH_30BPP;
++ break;
++ }
++ return true;
++
++}
++
++static void set_denormalization(
++ struct dce110_transform *xfm110,
++ enum dc_color_depth depth)
++{
++ uint32_t value = dal_read_reg(xfm110->base.ctx,
++ DCP_REG(mmDENORM_CONTROL));
++
++ switch (depth) {
++ case COLOR_DEPTH_666:
++ /* 63/64 for 6 bit output color depth */
++ set_reg_field_value(
++ value,
++ 1,
++ DENORM_CONTROL,
++ DENORM_MODE);
++ break;
++ case COLOR_DEPTH_888:
++ /* Unity for 8 bit output color depth
++ * because prescale is disabled by default */
++ set_reg_field_value(
++ value,
++ 0,
++ DENORM_CONTROL,
++ DENORM_MODE);
++ break;
++ case COLOR_DEPTH_101010:
++ /* 1023/1024 for 10 bit output color depth */
++ set_reg_field_value(
++ value,
++ 3,
++ DENORM_CONTROL,
++ DENORM_MODE);
++ break;
++ case COLOR_DEPTH_121212:
++ /* 4095/4096 for 12 bit output color depth */
++ set_reg_field_value(
++ value,
++ 5,
++ DENORM_CONTROL,
++ DENORM_MODE);
++ break;
++ case COLOR_DEPTH_141414:
++ case COLOR_DEPTH_161616:
++ default:
++ /* not valid used case! */
++ break;
++ }
++
++ dal_write_reg(xfm110->base.ctx,
++ DCP_REG(mmDENORM_CONTROL),
++ value);
++
++}
++
++bool dce110_transform_set_pixel_storage_depth(
++ struct transform *xfm,
++ enum lb_pixel_depth depth)
++{
++ struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm);
++ bool ret = true;
++ uint32_t value;
++ enum dc_color_depth color_depth;
++
++ value = dal_read_reg(
++ xfm->ctx,
++ LB_REG(mmLB_DATA_FORMAT));
++ switch (depth) {
++ case LB_PIXEL_DEPTH_18BPP:
++ color_depth = COLOR_DEPTH_666;
++ set_reg_field_value(value, 2, LB_DATA_FORMAT, PIXEL_DEPTH);
++ set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE);
++ break;
++ case LB_PIXEL_DEPTH_24BPP:
++ color_depth = COLOR_DEPTH_888;
++ set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_DEPTH);
++ set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE);
++ break;
++ case LB_PIXEL_DEPTH_30BPP:
++ color_depth = COLOR_DEPTH_101010;
++ set_reg_field_value(value, 0, LB_DATA_FORMAT, PIXEL_DEPTH);
++ set_reg_field_value(value, 1, LB_DATA_FORMAT, PIXEL_EXPAN_MODE);
++ break;
++ case LB_PIXEL_DEPTH_36BPP:
++ color_depth = COLOR_DEPTH_121212;
++ set_reg_field_value(value, 3, LB_DATA_FORMAT, PIXEL_DEPTH);
++ set_reg_field_value(value, 0, LB_DATA_FORMAT, PIXEL_EXPAN_MODE);
++ break;
++ default:
++ ret = false;
++ break;
++ }
++
++ if (ret == true) {
++ set_denormalization(xfm110, color_depth);
++ ret = program_bit_depth_reduction(xfm110, color_depth);
++
++ set_reg_field_value(value, 0, LB_DATA_FORMAT, ALPHA_EN);
++ dal_write_reg(
++ xfm->ctx, LB_REG(mmLB_DATA_FORMAT), value);
++ if (!(xfm110->lb_pixel_depth_supported & depth)) {
++ /*we should use unsupported capabilities
++ * unless it is required by w/a*/
++ dal_logger_write(xfm->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Capability not supported",
++ __func__);
++ }
++ }
++
++ return ret;
++}
++
++/* LB_MEMORY_CONFIG
++ * 00 - Use all three pieces of memory
++ * 01 - Use only one piece of memory of total 720x144 bits
++ * 10 - Use two pieces of memory of total 960x144 bits
++ * 11 - reserved
++ *
++ * LB_MEMORY_SIZE
++ * Total entries of LB memory.
++ * This number should be larger than 960. The default value is 1712(0x6B0) */
++bool dce110_transform_power_up_line_buffer(struct transform *xfm)
++{
++ struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm);
++ uint32_t value;
++
++ value = dal_read_reg(xfm110->base.ctx, LB_REG(mmLB_MEMORY_CTRL));
++
++ /*Use all three pieces of memory always*/
++ set_reg_field_value(value, 0, LB_MEMORY_CTRL, LB_MEMORY_CONFIG);
++ /*hard coded number DCE11 1712(0x6B0) Partitions: 720/960/1712*/
++ set_reg_field_value(value, LB_TOTAL_NUMBER_OF_ENTRIES, LB_MEMORY_CTRL,
++ LB_MEMORY_SIZE);
++
++ dal_write_reg(xfm110->base.ctx, LB_REG(mmLB_MEMORY_CTRL), value);
++
++ return true;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_bit_depth.h b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_bit_depth.h
+new file mode 100644
+index 0000000..ff100cc
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_bit_depth.h
+@@ -0,0 +1,51 @@
++/* Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_TRANSFORM_BIT_DEPTH_DCE110_H__
++#define __DC_TRANSFORM_BIT_DEPTH_DCE110_H__
++
++#include "dce110_transform.h"
++
++bool dce110_transform_power_up_line_buffer(struct transform *xfm);
++
++bool dce110_transform_get_max_num_of_supported_lines(
++ struct dce110_transform *xfm110,
++ enum lb_pixel_depth depth,
++ uint32_t pixel_width,
++ uint32_t *lines);
++
++void dce110_transform_enable_alpha(
++ struct dce110_transform *xfm110,
++ bool enable);
++
++bool dce110_transform_get_next_lower_pixel_storage_depth(
++ struct dce110_transform *xfm110,
++ uint32_t display_bpp,
++ enum lb_pixel_depth depth,
++ enum lb_pixel_depth *lower_depth);
++
++bool dce110_transform_is_prefetch_enabled(
++ struct dce110_transform *xfm110);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_gamut.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_gamut.c
+new file mode 100644
+index 0000000..a5b5b01
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_gamut.c
+@@ -0,0 +1,297 @@
++/* 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 "dal_services.h"
++#include "dce110_transform.h"
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++#include "include/fixed31_32.h"
++#include "include/hw_sequencer_types.h"
++#include "basics/conversion.h"
++#include "include/grph_object_id.h"
++
++enum {
++ GAMUT_MATRIX_SIZE = 12
++};
++
++#define DCP_REG(reg)\
++ (reg + xfm110->offsets.dcp_offset)
++
++#define DISP_BRIGHTNESS_DEFAULT_HW 0
++#define DISP_BRIGHTNESS_MIN_HW -25
++#define DISP_BRIGHTNESS_MAX_HW 25
++#define DISP_BRIGHTNESS_STEP_HW 1
++#define DISP_BRIGHTNESS_HW_DIVIDER 100
++
++#define DISP_HUE_DEFAULT_HW 0
++#define DISP_HUE_MIN_HW -30
++#define DISP_HUE_MAX_HW 30
++#define DISP_HUE_STEP_HW 1
++#define DISP_HUE_HW_DIVIDER 1
++
++#define DISP_CONTRAST_DEFAULT_HW 100
++#define DISP_CONTRAST_MIN_HW 50
++#define DISP_CONTRAST_MAX_HW 150
++#define DISP_CONTRAST_STEP_HW 1
++#define DISP_CONTRAST_HW_DIVIDER 100
++
++#define DISP_SATURATION_DEFAULT_HW 100
++#define DISP_SATURATION_MIN_HW 0
++#define DISP_SATURATION_MAX_HW 200
++#define DISP_SATURATION_STEP_HW 1
++#define DISP_SATURATION_HW_DIVIDER 100
++
++#define DISP_KELVIN_DEGRES_DEFAULT 6500
++#define DISP_KELVIN_DEGRES_MIN 4000
++#define DISP_KELVIN_DEGRES_MAX 10000
++#define DISP_KELVIN_DEGRES_STEP 100
++#define DISP_KELVIN_HW_DIVIDER 10000
++
++static void program_gamut_remap(
++ struct dce110_transform *xfm110,
++ const uint16_t *reg_val)
++{
++ struct dc_context *ctx = xfm110->base.ctx;
++ uint32_t value = 0;
++ uint32_t addr = DCP_REG(mmGAMUT_REMAP_CONTROL);
++
++ /* the register controls ovl also */
++ value = dal_read_reg(ctx, addr);
++
++ if (reg_val) {
++ {
++ uint32_t reg_data = 0;
++ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C11_C12);
++
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[0],
++ GAMUT_REMAP_C11_C12,
++ GAMUT_REMAP_C11);
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[1],
++ GAMUT_REMAP_C11_C12,
++ GAMUT_REMAP_C12);
++
++ dal_write_reg(ctx, addr, reg_data);
++ }
++ {
++ uint32_t reg_data = 0;
++ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C13_C14);
++
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[2],
++ GAMUT_REMAP_C13_C14,
++ GAMUT_REMAP_C13);
++
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[3],
++ GAMUT_REMAP_C13_C14,
++ GAMUT_REMAP_C14);
++
++ dal_write_reg(ctx, addr, reg_data);
++ }
++ {
++ uint32_t reg_data = 0;
++ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C21_C22);
++
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[4],
++ GAMUT_REMAP_C21_C22,
++ GAMUT_REMAP_C21);
++
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[5],
++ GAMUT_REMAP_C21_C22,
++ GAMUT_REMAP_C22);
++
++ dal_write_reg(ctx, addr, reg_data);
++ }
++ {
++ uint32_t reg_data = 0;
++ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C23_C24);
++
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[6],
++ GAMUT_REMAP_C23_C24,
++ GAMUT_REMAP_C23);
++
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[7],
++ GAMUT_REMAP_C23_C24,
++ GAMUT_REMAP_C24);
++
++ dal_write_reg(ctx, addr, reg_data);
++ }
++ {
++ uint32_t reg_data = 0;
++ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C31_C32);
++
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[8],
++ GAMUT_REMAP_C31_C32,
++ GAMUT_REMAP_C31);
++
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[9],
++ GAMUT_REMAP_C31_C32,
++ GAMUT_REMAP_C32);
++
++ dal_write_reg(ctx, addr, reg_data);
++ }
++ {
++ uint32_t reg_data = 0;
++ uint32_t addr = DCP_REG(mmGAMUT_REMAP_C33_C34);
++
++ /* fixed S2.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[10],
++ GAMUT_REMAP_C33_C34,
++ GAMUT_REMAP_C33);
++
++ /* fixed S0.13 format */
++ set_reg_field_value(
++ reg_data,
++ reg_val[11],
++ GAMUT_REMAP_C33_C34,
++ GAMUT_REMAP_C34);
++
++ dal_write_reg(ctx, addr, reg_data);
++ }
++
++ set_reg_field_value(
++ value,
++ 1,
++ GAMUT_REMAP_CONTROL,
++ GRPH_GAMUT_REMAP_MODE);
++
++ } else
++ set_reg_field_value(
++ value,
++ 0,
++ GAMUT_REMAP_CONTROL,
++ GRPH_GAMUT_REMAP_MODE);
++
++ addr = DCP_REG(mmGAMUT_REMAP_CONTROL);
++ dal_write_reg(ctx, addr, value);
++
++}
++
++/**
++ *****************************************************************************
++ * Function: dal_transform_wide_gamut_set_gamut_remap
++ *
++ * @param [in] const struct grph_csc_adjustment *adjust
++ *
++ * @return
++ * void
++ *
++ * @note calculate and apply color temperature adjustment to in Rgb color space
++ *
++ * @see
++ *
++ *****************************************************************************
++ */
++void dce110_transform_set_gamut_remap(
++ struct transform *xfm,
++ const struct grph_csc_adjustment *adjust)
++{
++ struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm);
++
++ if (adjust->gamut_adjust_type != GRAPHICS_GAMUT_ADJUST_TYPE_SW ||
++ adjust->temperature_divider == 0)
++ program_gamut_remap(xfm110, NULL);
++ else {
++ struct fixed31_32 arr_matrix[GAMUT_MATRIX_SIZE];
++ uint16_t arr_reg_val[GAMUT_MATRIX_SIZE];
++
++ arr_matrix[0] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[0],
++ adjust->temperature_divider);
++ arr_matrix[1] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[1],
++ adjust->temperature_divider);
++ arr_matrix[2] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[2],
++ adjust->temperature_divider);
++ arr_matrix[3] = dal_fixed31_32_zero;
++
++ arr_matrix[4] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[3],
++ adjust->temperature_divider);
++ arr_matrix[5] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[4],
++ adjust->temperature_divider);
++ arr_matrix[6] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[5],
++ adjust->temperature_divider);
++ arr_matrix[7] = dal_fixed31_32_zero;
++
++ arr_matrix[8] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[6],
++ adjust->temperature_divider);
++ arr_matrix[9] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[7],
++ adjust->temperature_divider);
++ arr_matrix[10] =
++ dal_fixed31_32_from_fraction(
++ adjust->temperature_matrix[8],
++ adjust->temperature_divider);
++ arr_matrix[11] = dal_fixed31_32_zero;
++
++ convert_float_matrix(
++ arr_reg_val, arr_matrix, GAMUT_MATRIX_SIZE);
++
++ program_gamut_remap(xfm110, arr_reg_val);
++ }
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_scl.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_scl.c
+new file mode 100644
+index 0000000..f313d2c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_scl.c
+@@ -0,0 +1,818 @@
++/*
++ * 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 "dal_services.h"
++
++/* include DCE11 register header files */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_transform.h"
++
++#define UP_SCALER_RATIO_MAX 16000
++#define DOWN_SCALER_RATIO_MAX 250
++#define SCALER_RATIO_DIVIDER 1000
++
++#define SCL_REG(reg)\
++ (reg + xfm110->offsets.scl_offset)
++
++#define DCFE_REG(reg)\
++ (reg + xfm110->offsets.dcfe_offset)
++
++static void disable_enhanced_sharpness(struct dce110_transform *xfm110)
++{
++ uint32_t value;
++
++ value = dal_read_reg(xfm110->base.ctx,
++ SCL_REG(mmSCL_F_SHARP_CONTROL));
++
++ set_reg_field_value(value, 0,
++ SCL_F_SHARP_CONTROL, SCL_HF_SHARP_EN);
++
++ set_reg_field_value(value, 0,
++ SCL_F_SHARP_CONTROL, SCL_VF_SHARP_EN);
++
++ set_reg_field_value(value, 0,
++ SCL_F_SHARP_CONTROL, SCL_HF_SHARP_SCALE_FACTOR);
++
++ set_reg_field_value(value, 0,
++ SCL_F_SHARP_CONTROL, SCL_VF_SHARP_SCALE_FACTOR);
++
++ dal_write_reg(xfm110->base.ctx,
++ SCL_REG(mmSCL_F_SHARP_CONTROL), value);
++}
++
++/**
++* Function:
++* void setup_scaling_configuration
++*
++* Purpose: setup scaling mode : bypass, RGb, YCbCr and nummber of taps
++* Input: data
++*
++* Output:
++ void
++*/
++static bool setup_scaling_configuration(
++ struct dce110_transform *xfm110,
++ const struct scaler_data *data)
++{
++ struct dc_context *ctx = xfm110->base.ctx;
++ uint32_t addr;
++ uint32_t value;
++
++ if (data->taps.h_taps + data->taps.v_taps <= 2) {
++ dce110_transform_set_scaler_bypass(&xfm110->base);
++ return false;
++ }
++
++ {
++ addr = SCL_REG(mmSCL_MODE);
++ value = dal_read_reg(ctx, addr);
++
++ if (data->dal_pixel_format <= PIXEL_FORMAT_GRPH_END)
++ set_reg_field_value(value, 1, SCL_MODE, SCL_MODE);
++ else
++ set_reg_field_value(value, 2, SCL_MODE, SCL_MODE);
++
++ set_reg_field_value(value, 1, SCL_MODE, SCL_PSCL_EN);
++
++ dal_write_reg(ctx, addr, value);
++ }
++ {
++ addr = SCL_REG(mmSCL_TAP_CONTROL);
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(value, data->taps.h_taps - 1,
++ SCL_TAP_CONTROL, SCL_H_NUM_OF_TAPS);
++
++ set_reg_field_value(value, data->taps.v_taps - 1,
++ SCL_TAP_CONTROL, SCL_V_NUM_OF_TAPS);
++
++ dal_write_reg(ctx, addr, value);
++ }
++ {
++ addr = SCL_REG(mmSCL_CONTROL);
++ value = dal_read_reg(ctx, addr);
++ /* 1 - Replaced out of bound pixels with edge */
++ set_reg_field_value(value, 1, SCL_CONTROL, SCL_BOUNDARY_MODE);
++
++ /* 1 - Replaced out of bound pixels with the edge pixel. */
++ dal_write_reg(ctx, addr, value);
++ }
++
++ return true;
++}
++
++/**
++* Function:
++* void program_overscan
++*
++* Purpose: Programs overscan border
++* Input: overscan
++*
++* Output:
++ void
++*/
++static void program_overscan(
++ struct dce110_transform *xfm110,
++ const struct overscan_info *overscan)
++{
++ uint32_t overscan_left_right = 0;
++ uint32_t overscan_top_bottom = 0;
++
++ set_reg_field_value(overscan_left_right, overscan->left,
++ EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT);
++
++ set_reg_field_value(overscan_left_right, overscan->right,
++ EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT);
++
++ set_reg_field_value(overscan_top_bottom, overscan->top,
++ EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP);
++
++ set_reg_field_value(overscan_top_bottom, overscan->bottom,
++ EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM);
++
++ dal_write_reg(xfm110->base.ctx,
++ SCL_REG(mmEXT_OVERSCAN_LEFT_RIGHT),
++ overscan_left_right);
++
++ dal_write_reg(xfm110->base.ctx,
++ SCL_REG(mmEXT_OVERSCAN_TOP_BOTTOM),
++ overscan_top_bottom);
++}
++
++static void program_two_taps_filter(
++ struct dce110_transform *xfm110,
++ bool enable,
++ bool vertical)
++{
++ uint32_t addr;
++ uint32_t value;
++ /* 1: Hard coded 2 tap filter
++ * 0: Programmable 2 tap filter from coefficient RAM
++ */
++ if (vertical) {
++ addr = SCL_REG(mmSCL_VERT_FILTER_CONTROL);
++ value = dal_read_reg(xfm110->base.ctx, addr);
++ set_reg_field_value(
++ value,
++ enable ? 1 : 0,
++ SCL_VERT_FILTER_CONTROL,
++ SCL_V_2TAP_HARDCODE_COEF_EN);
++
++ } else {
++ addr = SCL_REG(mmSCL_HORZ_FILTER_CONTROL);
++ value = dal_read_reg(xfm110->base.ctx, addr);
++ set_reg_field_value(
++ value,
++ enable ? 1 : 0,
++ SCL_HORZ_FILTER_CONTROL,
++ SCL_H_2TAP_HARDCODE_COEF_EN);
++ }
++
++ dal_write_reg(xfm110->base.ctx, addr, value);
++}
++
++static void set_coeff_update_complete(struct dce110_transform *xfm110)
++{
++ uint32_t value;
++ uint32_t addr = SCL_REG(mmSCL_UPDATE);
++
++ value = dal_read_reg(xfm110->base.ctx, addr);
++ set_reg_field_value(value, 1,
++ SCL_UPDATE, SCL_COEF_UPDATE_COMPLETE);
++ dal_write_reg(xfm110->base.ctx, addr, value);
++}
++
++static void program_filter(
++ struct dce110_transform *xfm110,
++ enum ram_filter_type filter_type,
++ struct scaler_filter_params *scl_filter_params,
++ uint32_t *coeffs,
++ uint32_t coeffs_num)
++{
++ uint32_t phase = 0;
++ uint32_t array_idx = 0;
++ uint32_t pair = 0;
++
++ uint32_t taps_pairs = (scl_filter_params->taps + 1) / 2;
++ uint32_t phases_to_program = scl_filter_params->phases / 2 + 1;
++
++ uint32_t i;
++ uint32_t addr;
++ uint32_t select_addr;
++ uint32_t select;
++ uint32_t data;
++ /* We need to disable power gating on coeff memory to do programming */
++
++ uint32_t pwr_ctrl_orig;
++ uint32_t pwr_ctrl_off;
++
++ addr = DCFE_REG(mmDCFE_MEM_PWR_CTRL);
++ pwr_ctrl_orig = dal_read_reg(xfm110->base.ctx, addr);
++ pwr_ctrl_off = pwr_ctrl_orig;
++ set_reg_field_value(
++ pwr_ctrl_off,
++ 1,
++ DCFE_MEM_PWR_CTRL,
++ SCL_COEFF_MEM_PWR_DIS);
++ dal_write_reg(xfm110->base.ctx, addr, pwr_ctrl_off);
++
++ addr = DCFE_REG(mmDCFE_MEM_PWR_STATUS);
++ /* Wait to disable gating: */
++ for (i = 0;
++ i < 10 &&
++ get_reg_field_value(
++ dal_read_reg(xfm110->base.ctx, addr),
++ DCFE_MEM_PWR_STATUS,
++ SCL_COEFF_MEM_PWR_STATE);
++ i++)
++ dc_service_delay_in_microseconds(xfm110->base.ctx, 1);
++
++ ASSERT(i < 10);
++
++ select_addr = SCL_REG(mmSCL_COEF_RAM_SELECT);
++ select = dal_read_reg(xfm110->base.ctx, select_addr);
++
++ set_reg_field_value(
++ select,
++ filter_type,
++ SCL_COEF_RAM_SELECT,
++ SCL_C_RAM_FILTER_TYPE);
++ set_reg_field_value(
++ select,
++ 0,
++ SCL_COEF_RAM_SELECT,
++ SCL_C_RAM_TAP_PAIR_IDX);
++ set_reg_field_value(
++ select,
++ 0,
++ SCL_COEF_RAM_SELECT,
++ SCL_C_RAM_PHASE);
++
++ data = 0;
++
++ for (phase = 0; phase < phases_to_program; phase++) {
++ /* we always program N/2 + 1 phases, total phases N, but N/2-1
++ * are just mirror phase 0 is unique and phase N/2 is unique
++ * if N is even
++ */
++
++ set_reg_field_value(
++ select,
++ phase,
++ SCL_COEF_RAM_SELECT,
++ SCL_C_RAM_PHASE);
++
++ for (pair = 0; pair < taps_pairs; pair++) {
++ set_reg_field_value(
++ select,
++ pair,
++ SCL_COEF_RAM_SELECT,
++ SCL_C_RAM_TAP_PAIR_IDX);
++ dal_write_reg(xfm110->base.ctx, select_addr, select);
++
++ /* even tap write enable */
++ set_reg_field_value(
++ data,
++ 1,
++ SCL_COEF_RAM_TAP_DATA,
++ SCL_C_RAM_EVEN_TAP_COEF_EN);
++ /* even tap data */
++ set_reg_field_value(
++ data,
++ coeffs[array_idx],
++ SCL_COEF_RAM_TAP_DATA,
++ SCL_C_RAM_EVEN_TAP_COEF);
++
++ /* if we have odd number of taps and the last pair is
++ * here then we do not need to program
++ */
++ if (scl_filter_params->taps % 2 &&
++ pair == taps_pairs - 1) {
++ /* odd tap write disable */
++ set_reg_field_value(
++ data,
++ 0,
++ SCL_COEF_RAM_TAP_DATA,
++ SCL_C_RAM_ODD_TAP_COEF_EN);
++ set_reg_field_value(
++ data,
++ 0,
++ SCL_COEF_RAM_TAP_DATA,
++ SCL_C_RAM_ODD_TAP_COEF);
++ array_idx += 1;
++ } else {
++ /* odd tap write enable */
++ set_reg_field_value(
++ data,
++ 1,
++ SCL_COEF_RAM_TAP_DATA,
++ SCL_C_RAM_ODD_TAP_COEF_EN);
++ /* dbg_val: 0x1000 / sclFilterParams->taps; */
++ set_reg_field_value(
++ data,
++ coeffs[array_idx + 1],
++ SCL_COEF_RAM_TAP_DATA,
++ SCL_C_RAM_ODD_TAP_COEF);
++
++ array_idx += 2;
++ }
++
++ dal_write_reg(
++ xfm110->base.ctx,
++ SCL_REG(mmSCL_COEF_RAM_TAP_DATA),
++ data);
++ }
++ }
++
++ ASSERT(coeffs_num == array_idx);
++
++ /* reset the power gating register */
++ dal_write_reg(
++ xfm110->base.ctx,
++ DCFE_REG(mmDCFE_MEM_PWR_CTRL),
++ pwr_ctrl_orig);
++
++ set_coeff_update_complete(xfm110);
++}
++
++/*
++ *
++ * Populates an array with filter coefficients in 1.1.12 fixed point form
++*/
++static bool get_filter_coefficients(
++ struct dce110_transform *xfm110,
++ uint32_t taps,
++ uint32_t **data_tab,
++ uint32_t *data_size)
++{
++ uint32_t num = 0;
++ uint32_t i;
++ const struct fixed31_32 *filter =
++ dal_scaler_filter_get(
++ xfm110->base.filter,
++ data_tab,
++ &num);
++ uint32_t *data_row;
++
++ if (!filter) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++ data_row = *data_tab;
++
++ for (i = 0; i < num; ++i) {
++ /* req. format sign fixed 1.1.12, the values are always between
++ * [-1; 1]
++ *
++ * Each phase is mirrored as follows :
++ * 0 : Phase 0
++ * 1 : Phase 1 or Phase 64 - 1 / 128 - 1
++ * N : Phase N or Phase 64 - N / 128 - N
++ *
++ * Convert from Fixed31_32 to 1.1.12 by using floor on value
++ * shifted by number of required fractional bits(12)
++ */
++ struct fixed31_32 value = filter[i];
++
++ data_row[i] =
++ dal_fixed31_32_floor(dal_fixed31_32_shl(value, 12)) &
++ 0x3FFC;
++ }
++ *data_size = num;
++
++ return true;
++}
++
++static bool program_multi_taps_filter(
++ struct dce110_transform *xfm110,
++ const struct scaler_data *data,
++ bool horizontal)
++{
++ struct scaler_filter_params filter_params;
++ enum ram_filter_type filter_type;
++ uint32_t src_size;
++ uint32_t dst_size;
++
++ uint32_t *filter_data = NULL;
++ uint32_t filter_data_size = 0;
++
++ /* 16 phases total for DCE11 */
++ filter_params.phases = 16;
++
++ if (horizontal) {
++ filter_params.taps = data->taps.h_taps;
++ filter_params.sharpness = data->h_sharpness;
++ filter_params.flags.bits.HORIZONTAL = 1;
++
++ src_size = data->viewport.width;
++ dst_size =
++ dal_fixed31_32_floor(
++ dal_fixed31_32_div(
++ dal_fixed31_32_from_int(
++ data->viewport.width),
++ data->ratios->horz));
++
++ filter_type = FILTER_TYPE_RGB_Y_HORIZONTAL;
++ } else {
++ filter_params.taps = data->taps.v_taps;
++ filter_params.sharpness = data->v_sharpness;
++ filter_params.flags.bits.HORIZONTAL = 0;
++
++ src_size = data->viewport.height;
++ dst_size =
++ dal_fixed31_32_floor(
++ dal_fixed31_32_div(
++ dal_fixed31_32_from_int(
++ data->viewport.height),
++ data->ratios->vert));
++
++ filter_type = FILTER_TYPE_RGB_Y_VERTICAL;
++ }
++
++ /* 1. Generate the coefficients */
++ if (!dal_scaler_filter_generate(
++ xfm110->base.filter,
++ &filter_params,
++ src_size,
++ dst_size))
++ return false;
++
++ /* 2. Convert coefficients to fixed point format 1.12 (note coeff.
++ * could be negative(!) and range is [ from -1 to 1 ]) */
++ if (!get_filter_coefficients(
++ xfm110,
++ filter_params.taps,
++ &filter_data,
++ &filter_data_size))
++ return false;
++
++ /* 3. Program the filter */
++ program_filter(
++ xfm110,
++ filter_type,
++ &filter_params,
++ filter_data,
++ filter_data_size);
++
++ /* 4. Program the alpha if necessary */
++ if (data->flags.bits.SHOULD_PROGRAM_ALPHA) {
++ if (horizontal)
++ filter_type = FILTER_TYPE_ALPHA_HORIZONTAL;
++ else
++ filter_type = FILTER_TYPE_ALPHA_VERTICAL;
++
++ program_filter(
++ xfm110,
++ filter_type,
++ &filter_params,
++ filter_data,
++ filter_data_size);
++ }
++
++ return true;
++}
++
++static void program_viewport(
++ struct dce110_transform *xfm110,
++ const struct rect *view_port)
++{
++ struct dc_context *ctx = xfm110->base.ctx;
++ uint32_t value = 0;
++ uint32_t addr = 0;
++
++ addr = SCL_REG(mmVIEWPORT_START);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ view_port->x,
++ VIEWPORT_START,
++ VIEWPORT_X_START);
++ set_reg_field_value(
++ value,
++ view_port->y,
++ VIEWPORT_START,
++ VIEWPORT_Y_START);
++ dal_write_reg(ctx, addr, value);
++
++ addr = SCL_REG(mmVIEWPORT_SIZE);
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ view_port->height,
++ VIEWPORT_SIZE,
++ VIEWPORT_HEIGHT);
++ set_reg_field_value(
++ value,
++ view_port->width,
++ VIEWPORT_SIZE,
++ VIEWPORT_WIDTH);
++ dal_write_reg(ctx, addr, value);
++
++ /* TODO: add stereo support */
++}
++
++static void calculate_inits(
++ struct dce110_transform *xfm110,
++ const struct scaler_data *data,
++ struct scl_ratios_inits *inits)
++{
++ struct fixed31_32 h_init;
++ struct fixed31_32 v_init;
++ struct fixed31_32 v_init_bot;
++
++ inits->bottom_enable = 0;
++ inits->h_int_scale_ratio =
++ dal_fixed31_32_u2d19(data->ratios->horz) << 5;
++ inits->v_int_scale_ratio =
++ dal_fixed31_32_u2d19(data->ratios->vert) << 5;
++
++ h_init =
++ dal_fixed31_32_div_int(
++ dal_fixed31_32_add(
++ data->ratios->horz,
++ dal_fixed31_32_from_int(data->taps.h_taps + 1)),
++ 2);
++ inits->h_init.integer = dal_fixed31_32_floor(h_init);
++ inits->h_init.fraction = dal_fixed31_32_u0d19(h_init) << 5;
++
++ v_init =
++ dal_fixed31_32_div_int(
++ dal_fixed31_32_add(
++ data->ratios->vert,
++ dal_fixed31_32_from_int(data->taps.v_taps + 1)),
++ 2);
++ inits->v_init.integer = dal_fixed31_32_floor(v_init);
++ inits->v_init.fraction = dal_fixed31_32_u0d19(v_init) << 5;
++
++ if (data->flags.bits.INTERLACED) {
++ v_init_bot =
++ dal_fixed31_32_add(
++ dal_fixed31_32_div_int(
++ dal_fixed31_32_add(
++ data->ratios->vert,
++ dal_fixed31_32_from_int(
++ data->taps.v_taps + 1)),
++ 2),
++ data->ratios->vert);
++ inits->v_init_bottom.integer = dal_fixed31_32_floor(v_init_bot);
++ inits->v_init_bottom.fraction =
++ dal_fixed31_32_u0d19(v_init_bot) << 5;
++
++ inits->bottom_enable = 1;
++ }
++}
++
++static void program_scl_ratios_inits(
++ struct dce110_transform *xfm110,
++ struct scl_ratios_inits *inits)
++{
++ uint32_t addr = SCL_REG(mmSCL_HORZ_FILTER_SCALE_RATIO);
++ uint32_t value = 0;
++
++ set_reg_field_value(
++ value,
++ inits->h_int_scale_ratio,
++ SCL_HORZ_FILTER_SCALE_RATIO,
++ SCL_H_SCALE_RATIO);
++ dal_write_reg(xfm110->base.ctx, addr, value);
++
++ addr = SCL_REG(mmSCL_VERT_FILTER_SCALE_RATIO);
++ value = 0;
++ set_reg_field_value(
++ value,
++ inits->v_int_scale_ratio,
++ SCL_VERT_FILTER_SCALE_RATIO,
++ SCL_V_SCALE_RATIO);
++ dal_write_reg(xfm110->base.ctx, addr, value);
++
++ addr = SCL_REG(mmSCL_HORZ_FILTER_INIT);
++ value = 0;
++ set_reg_field_value(
++ value,
++ inits->h_init.integer,
++ SCL_HORZ_FILTER_INIT,
++ SCL_H_INIT_INT);
++ set_reg_field_value(
++ value,
++ inits->h_init.fraction,
++ SCL_HORZ_FILTER_INIT,
++ SCL_H_INIT_FRAC);
++ dal_write_reg(xfm110->base.ctx, addr, value);
++
++ addr = SCL_REG(mmSCL_VERT_FILTER_INIT);
++ value = 0;
++ set_reg_field_value(
++ value,
++ inits->v_init.integer,
++ SCL_VERT_FILTER_INIT,
++ SCL_V_INIT_INT);
++ set_reg_field_value(
++ value,
++ inits->v_init.fraction,
++ SCL_VERT_FILTER_INIT,
++ SCL_V_INIT_FRAC);
++ dal_write_reg(xfm110->base.ctx, addr, value);
++
++ if (inits->bottom_enable) {
++ addr = SCL_REG(mmSCL_VERT_FILTER_INIT_BOT);
++ value = 0;
++ set_reg_field_value(
++ value,
++ inits->v_init_bottom.integer,
++ SCL_VERT_FILTER_INIT_BOT,
++ SCL_V_INIT_INT_BOT);
++ set_reg_field_value(
++ value,
++ inits->v_init_bottom.fraction,
++ SCL_VERT_FILTER_INIT_BOT,
++ SCL_V_INIT_FRAC_BOT);
++ dal_write_reg(xfm110->base.ctx, addr, value);
++ }
++
++ addr = SCL_REG(mmSCL_AUTOMATIC_MODE_CONTROL);
++ value = 0;
++ set_reg_field_value(
++ value,
++ 0,
++ SCL_AUTOMATIC_MODE_CONTROL,
++ SCL_V_CALC_AUTO_RATIO_EN);
++ set_reg_field_value(
++ value,
++ 0,
++ SCL_AUTOMATIC_MODE_CONTROL,
++ SCL_H_CALC_AUTO_RATIO_EN);
++ dal_write_reg(xfm110->base.ctx, addr, value);
++}
++
++static void get_viewport(
++ struct dce110_transform *xfm110,
++ struct rect *current_view_port)
++{
++ uint32_t value_start;
++ uint32_t value_size;
++
++ if (current_view_port == NULL)
++ return;
++
++ value_start = dal_read_reg(xfm110->base.ctx, SCL_REG(mmVIEWPORT_START));
++ value_size = dal_read_reg(xfm110->base.ctx, SCL_REG(mmVIEWPORT_SIZE));
++
++ current_view_port->x = get_reg_field_value(
++ value_start,
++ VIEWPORT_START,
++ VIEWPORT_X_START);
++ current_view_port->y = get_reg_field_value(
++ value_start,
++ VIEWPORT_START,
++ VIEWPORT_Y_START);
++ current_view_port->height = get_reg_field_value(
++ value_size,
++ VIEWPORT_SIZE,
++ VIEWPORT_HEIGHT);
++ current_view_port->width = get_reg_field_value(
++ value_size,
++ VIEWPORT_SIZE,
++ VIEWPORT_WIDTH);
++}
++
++
++bool dce110_transform_set_scaler(
++ struct transform *xfm,
++ const struct scaler_data *data)
++{
++ struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm);
++ bool is_scaling_required;
++ struct dc_context *ctx = xfm->ctx;
++
++ {
++ uint32_t addr = SCL_REG(mmSCL_BYPASS_CONTROL);
++ uint32_t value = dal_read_reg(xfm->ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ SCL_BYPASS_CONTROL,
++ SCL_BYPASS_MODE);
++ dal_write_reg(xfm->ctx, addr, value);
++ }
++
++ disable_enhanced_sharpness(xfm110);
++
++ /* 3. Program overscan */
++ program_overscan(xfm110, &data->overscan);
++
++ /* 4. Program taps and configuration */
++ is_scaling_required = setup_scaling_configuration(xfm110, data);
++ if (is_scaling_required) {
++ /* 5. Calculate and program ratio, filter initialization */
++ struct scl_ratios_inits inits = { 0 };
++
++ calculate_inits(xfm110, data, &inits);
++
++ program_scl_ratios_inits(xfm110, &inits);
++
++ /* 6. Program vertical filters */
++ if (data->taps.v_taps > 2) {
++ program_two_taps_filter(xfm110, false, true);
++
++ if (!program_multi_taps_filter(xfm110, data, false)) {
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_DCP,
++ LOG_MINOR_DCP_SCALER,
++ "Failed vertical taps programming\n");
++ return false;
++ }
++ } else
++ program_two_taps_filter(xfm110, true, true);
++
++ /* 7. Program horizontal filters */
++ if (data->taps.h_taps > 2) {
++ program_two_taps_filter(xfm110, false, false);
++
++ if (!program_multi_taps_filter(xfm110, data, true)) {
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_DCP,
++ LOG_MINOR_DCP_SCALER,
++ "Failed horizontal taps programming\n");
++ return false;
++ }
++ } else
++ program_two_taps_filter(xfm110, true, false);
++ }
++
++ return true;
++}
++
++void dce110_transform_set_scaler_bypass(struct transform *xfm)
++{
++ struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm);
++ uint32_t sclv_mode;
++
++ disable_enhanced_sharpness(xfm110);
++
++ sclv_mode = dal_read_reg(xfm->ctx, SCL_REG(mmSCL_MODE));
++ set_reg_field_value(sclv_mode, 0, SCL_MODE, SCL_MODE);
++ set_reg_field_value(sclv_mode, 0, SCL_MODE, SCL_PSCL_EN);
++ dal_write_reg(xfm->ctx, SCL_REG(mmSCL_MODE), sclv_mode);
++}
++
++bool dce110_transform_update_viewport(
++ struct transform *xfm,
++ const struct rect *view_port,
++ bool is_fbc_attached)
++{
++ struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm);
++ bool program_req = false;
++ struct rect current_view_port;
++
++ if (view_port == NULL)
++ return program_req;
++
++ get_viewport(xfm110, &current_view_port);
++
++ if (current_view_port.x != view_port->x ||
++ current_view_port.y != view_port->y ||
++ current_view_port.height != view_port->height ||
++ current_view_port.width != view_port->width)
++ program_req = true;
++
++ if (program_req) {
++ /*underlay viewport is programmed with scaler
++ *program_viewport function pointer is not exposed*/
++ program_viewport(xfm110, view_port);
++ }
++
++ return program_req;
++}
++
++void dce110_transform_set_scaler_filter(
++ struct transform *xfm,
++ struct scaler_filter *filter)
++{
++ xfm->filter = filter;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_sclv.c b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_sclv.c
+new file mode 100644
+index 0000000..bcf20bb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dce110/dce110_transform_sclv.c
+@@ -0,0 +1,531 @@
++/* 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 "dal_services.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "dce110_transform.h"
++
++#define NOT_IMPLEMENTED() DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_CONTROLLER,\
++ "TRANSFORM SCALER:%s()\n", __func__)
++
++/*
++*****************************************************************************
++* Function: calculateViewport
++*
++* @brief
++* Calculates all of the data required to set the viewport
++*
++* @param [in] pData: scaler settings data
++* @param [out] pLumaVp: luma viewport information
++* @param [out] pChromaVp: chroma viewport information
++* @param [out] srcResCx2: source chroma resolution times 2 - for multi-taps
++*
++*****************************************************************************
++*/
++static void calculate_viewport(
++ const struct scaler_data *scl_data,
++ struct rect *luma_viewport,
++ struct rect *chroma_viewport)
++{
++ /*Do not set chroma vp for rgb444 pixel format*/
++ luma_viewport->x = scl_data->viewport.x - scl_data->viewport.x % 2;
++ luma_viewport->y = scl_data->viewport.y - scl_data->viewport.y % 2;
++ luma_viewport->width =
++ scl_data->viewport.width - scl_data->viewport.width % 2;
++ luma_viewport->height =
++ scl_data->viewport.height - scl_data->viewport.height % 2;
++
++
++ if (scl_data->dal_pixel_format == PIXEL_FORMAT_422BPP16) {
++ luma_viewport->width += luma_viewport->width % 2;
++
++ chroma_viewport->x = luma_viewport->x / 2;
++ chroma_viewport->width = luma_viewport->width / 2;
++ } else if (scl_data->dal_pixel_format == PIXEL_FORMAT_420BPP12) {
++ luma_viewport->height += luma_viewport->height % 2;
++ luma_viewport->width += luma_viewport->width % 2;
++ /*for 420 video chroma is 1/4 the area of luma, scaled
++ *vertically and horizontally
++ */
++ chroma_viewport->x = luma_viewport->x / 2;
++ chroma_viewport->y = luma_viewport->y / 2;
++ chroma_viewport->height = luma_viewport->height / 2;
++ chroma_viewport->width = luma_viewport->width / 2;
++ }
++}
++
++
++static void program_viewport(
++ struct dce110_transform *xfm110,
++ struct rect *luma_view_port,
++ struct rect *chroma_view_port)
++{
++ struct dc_context *ctx = xfm110->base.ctx;
++ uint32_t value = 0;
++ uint32_t addr = 0;
++
++ if (luma_view_port->width != 0 && luma_view_port->height != 0) {
++ addr = mmSCLV_VIEWPORT_START;
++ value = 0;
++ set_reg_field_value(
++ value,
++ luma_view_port->x,
++ SCLV_VIEWPORT_START,
++ VIEWPORT_X_START);
++ set_reg_field_value(
++ value,
++ luma_view_port->y,
++ SCLV_VIEWPORT_START,
++ VIEWPORT_Y_START);
++ dal_write_reg(ctx, addr, value);
++
++ addr = mmSCLV_VIEWPORT_SIZE;
++ value = 0;
++ set_reg_field_value(
++ value,
++ luma_view_port->height,
++ SCLV_VIEWPORT_SIZE,
++ VIEWPORT_HEIGHT);
++ set_reg_field_value(
++ value,
++ luma_view_port->width,
++ SCLV_VIEWPORT_SIZE,
++ VIEWPORT_WIDTH);
++ dal_write_reg(ctx, addr, value);
++ }
++
++ if (chroma_view_port->width != 0 && chroma_view_port->height != 0) {
++ addr = mmSCLV_VIEWPORT_START_C;
++ value = 0;
++ set_reg_field_value(
++ value,
++ chroma_view_port->x,
++ SCLV_VIEWPORT_START_C,
++ VIEWPORT_X_START_C);
++ set_reg_field_value(
++ value,
++ chroma_view_port->y,
++ SCLV_VIEWPORT_START_C,
++ VIEWPORT_Y_START_C);
++ dal_write_reg(ctx, addr, value);
++
++ addr = mmSCLV_VIEWPORT_SIZE_C;
++ value = 0;
++ set_reg_field_value(
++ value,
++ chroma_view_port->height,
++ SCLV_VIEWPORT_SIZE_C,
++ VIEWPORT_HEIGHT_C);
++ set_reg_field_value(
++ value,
++ chroma_view_port->width,
++ SCLV_VIEWPORT_SIZE_C,
++ VIEWPORT_WIDTH_C);
++ dal_write_reg(ctx, addr, value);
++ }
++ /* TODO: add stereo support */
++}
++
++
++/* Until and For MPO video play story, to reduce time for implementation,
++ * below limits are applied for now: 2_TAPS only
++ * Use auto-calculated filter values
++ * Following routines will be empty for now:
++ *
++ * programSclRatiosInits -- calcualate scaler ratio manually
++ * calculateInits --- calcualate scaler ratio manually
++ * programFilter -- multi-taps
++ * GetOptimalNumberOfTaps -- will hard coded to 2 TAPS
++ * GetNextLowerNumberOfTaps -- will hard coded to 2TAPS
++ * validateRequestedScaleRatio - used by GetOptimalNumberOfTaps internally
++ */
++
++/**
++* Function:
++* void setup_scaling_configuration
++*
++* Purpose: setup scaling mode : bypass, RGb, YCbCr and nummber of taps
++* Input: data
++*
++* Output:
++ void
++*/
++static bool setup_scaling_configuration(
++ struct dce110_transform *xfm110,
++ const struct scaler_data *data)
++{
++ bool is_scaling_needed = false;
++ struct dc_context *ctx = xfm110->base.ctx;
++ uint32_t value = 0;
++
++ if (data->taps.h_taps + data->taps.v_taps > 2) {
++ set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE);
++ set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN);
++ is_scaling_needed = true;
++ } else {
++ set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE);
++ set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN);
++ }
++
++ if (data->taps.h_taps_c + data->taps.v_taps_c > 2) {
++ set_reg_field_value(value, 1, SCLV_MODE, SCL_MODE_C);
++ set_reg_field_value(value, 1, SCLV_MODE, SCL_PSCL_EN_C);
++ is_scaling_needed = true;
++ } else if (data->dal_pixel_format != PIXEL_FORMAT_420BPP12 &&
++ data->dal_pixel_format != PIXEL_FORMAT_422BPP16) {
++ set_reg_field_value(
++ value,
++ get_reg_field_value(value, SCLV_MODE, SCL_MODE),
++ SCLV_MODE,
++ SCL_MODE_C);
++ set_reg_field_value(
++ value,
++ get_reg_field_value(value, SCLV_MODE, SCL_PSCL_EN),
++ SCLV_MODE,
++ SCL_PSCL_EN_C);
++ } else {
++ set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE_C);
++ set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN_C);
++ }
++ dal_write_reg(ctx, mmSCLV_MODE, value);
++
++ {
++ value = dal_read_reg(ctx, mmSCLV_TAP_CONTROL);
++
++ set_reg_field_value(value, data->taps.h_taps - 1,
++ SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS);
++
++ set_reg_field_value(value, data->taps.v_taps - 1,
++ SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS);
++
++ set_reg_field_value(value, data->taps.h_taps_c - 1,
++ SCLV_TAP_CONTROL, SCL_H_NUM_OF_TAPS_C);
++
++ set_reg_field_value(value, data->taps.v_taps_c - 1,
++ SCLV_TAP_CONTROL, SCL_V_NUM_OF_TAPS_C);
++
++ dal_write_reg(ctx, mmSCLV_TAP_CONTROL, value);
++ }
++
++ {
++ /* we can ignore this register because we are ok with hw
++ * default 0 -- change to 1 according to dal2 code*/
++ value = dal_read_reg(ctx, mmSCLV_CONTROL);
++ /* 0 - Replaced out of bound pixels with black pixel
++ * (or any other required color) */
++ set_reg_field_value(value, 1, SCLV_CONTROL, SCL_BOUNDARY_MODE);
++
++ /* 1 - Replaced out of bound pixels with the edge pixel. */
++ dal_write_reg(ctx, mmSCLV_CONTROL, value);
++ }
++
++ return is_scaling_needed;
++}
++
++/**
++* Function:
++* void program_overscan
++*
++* Purpose: Programs overscan border
++* Input: overscan
++*
++* Output:
++ void
++*/
++static void program_overscan(
++ struct dce110_transform *xfm110,
++ const struct overscan_info *overscan)
++{
++ uint32_t overscan_left_right = 0;
++ uint32_t overscan_top_bottom = 0;
++
++ set_reg_field_value(overscan_left_right, overscan->left,
++ SCLV_EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_LEFT);
++
++ set_reg_field_value(overscan_left_right, overscan->right,
++ SCLV_EXT_OVERSCAN_LEFT_RIGHT, EXT_OVERSCAN_RIGHT);
++
++ set_reg_field_value(overscan_top_bottom, overscan->top,
++ SCLV_EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_TOP);
++
++ set_reg_field_value(overscan_top_bottom, overscan->bottom,
++ SCLV_EXT_OVERSCAN_TOP_BOTTOM, EXT_OVERSCAN_BOTTOM);
++
++ dal_write_reg(xfm110->base.ctx,
++ mmSCLV_EXT_OVERSCAN_LEFT_RIGHT,
++ overscan_left_right);
++
++ dal_write_reg(xfm110->base.ctx,
++ mmSCLV_EXT_OVERSCAN_TOP_BOTTOM,
++ overscan_top_bottom);
++}
++/*
++static void setup_auto_scaling(struct dce110_transform *xfm110)
++{
++ uint32_t value = 0;
++ set_reg_field_value(value, 1, SCLV_AUTOMATIC_MODE_CONTROL,
++ SCL_V_CALC_AUTO_RATIO_EN);
++ set_reg_field_value(value, 1, SCLV_AUTOMATIC_MODE_CONTROL,
++ SCL_H_CALC_AUTO_RATIO_EN);
++ dal_write_reg(xfm->ctx,
++ xfm->regs[IDX_SCL_AUTOMATIC_MODE_CONTROL],
++ value);
++}
++*/
++
++static void program_two_taps_filter_horz(
++ struct dce110_transform *xfm110,
++ bool hardcode_coff)
++{
++ uint32_t value = 0;
++
++ if (hardcode_coff)
++ set_reg_field_value(
++ value,
++ 1,
++ SCLV_HORZ_FILTER_CONTROL,
++ SCL_H_2TAP_HARDCODE_COEF_EN);
++
++ dal_write_reg(xfm110->base.ctx,
++ mmSCLV_HORZ_FILTER_CONTROL,
++ value);
++}
++
++static void program_two_taps_filter_vert(
++ struct dce110_transform *xfm110,
++ bool hardcode_coff)
++{
++ uint32_t value = 0;
++
++ if (hardcode_coff)
++ set_reg_field_value(value, 1, SCLV_VERT_FILTER_CONTROL,
++ SCL_V_2TAP_HARDCODE_COEF_EN);
++
++ dal_write_reg(xfm110->base.ctx,
++ mmSCLV_VERT_FILTER_CONTROL,
++ value);
++}
++
++static void set_coeff_update_complete(
++ struct dce110_transform *xfm110)
++{
++ /*TODO: Until now, only scaler bypass, up-scaler 2 -TAPS coeff auto
++ * calculation are implemented. Coefficient RAM is not used
++ * Do not check this flag yet
++ */
++
++ /*uint32_t value;
++ uint32_t addr = xfm->regs[IDX_SCL_UPDATE];
++
++ value = dal_read_reg(xfm->ctx, addr);
++ set_reg_field_value(value, 0,
++ SCL_UPDATE, SCL_COEF_UPDATE_COMPLETE);
++ dal_write_reg(xfm->ctx, addr, value);*/
++}
++
++static bool program_multi_taps_filter(
++ struct dce110_transform *xfm110,
++ const struct scaler_data *data,
++ bool horizontal)
++{
++ struct dc_context *ctx = xfm110->base.ctx;
++
++ NOT_IMPLEMENTED();
++ return false;
++}
++
++static void calculate_inits(
++ struct dce110_transform *xfm110,
++ const struct scaler_data *data,
++ struct sclv_ratios_inits *inits,
++ struct rect *luma_viewport,
++ struct rect *chroma_viewport)
++{
++ if (data->dal_pixel_format == PIXEL_FORMAT_420BPP12 ||
++ data->dal_pixel_format == PIXEL_FORMAT_422BPP16)
++ inits->chroma_enable = true;
++
++ /* TODO: implement rest of this function properly */
++ if (inits->chroma_enable) {
++ inits->h_int_scale_ratio_luma = 0x1000000;
++ inits->v_int_scale_ratio_luma = 0x1000000;
++ inits->h_int_scale_ratio_chroma = 0x800000;
++ inits->v_int_scale_ratio_chroma = 0x800000;
++ }
++}
++
++static void program_scl_ratios_inits(
++ struct dce110_transform *xfm110,
++ struct sclv_ratios_inits *inits)
++{
++ struct dc_context *ctx = xfm110->base.ctx;
++ uint32_t addr = mmSCLV_HORZ_FILTER_SCALE_RATIO;
++ uint32_t value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ inits->h_int_scale_ratio_luma,
++ SCLV_HORZ_FILTER_SCALE_RATIO,
++ SCL_H_SCALE_RATIO);
++ dal_write_reg(ctx, addr, value);
++
++ addr = mmSCLV_VERT_FILTER_SCALE_RATIO;
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ inits->v_int_scale_ratio_luma,
++ SCLV_VERT_FILTER_SCALE_RATIO,
++ SCL_V_SCALE_RATIO);
++ dal_write_reg(ctx, addr, value);
++
++ addr = mmSCLV_HORZ_FILTER_SCALE_RATIO_C;
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ inits->h_int_scale_ratio_chroma,
++ SCLV_HORZ_FILTER_SCALE_RATIO_C,
++ SCL_H_SCALE_RATIO_C);
++ dal_write_reg(ctx, addr, value);
++
++ addr = mmSCLV_VERT_FILTER_SCALE_RATIO_C;
++ value = dal_read_reg(ctx, addr);
++ set_reg_field_value(
++ value,
++ inits->v_int_scale_ratio_chroma,
++ SCLV_VERT_FILTER_SCALE_RATIO_C,
++ SCL_V_SCALE_RATIO_C);
++ dal_write_reg(ctx, addr, value);
++}
++
++void dce110_transform_underlay_set_scalerv_bypass(struct transform *xfm)
++{
++ uint32_t addr = mmSCLV_MODE;
++ uint32_t value = dal_read_reg(xfm->ctx, addr);
++
++ set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE);
++ set_reg_field_value(value, 0, SCLV_MODE, SCL_MODE_C);
++ set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN);
++ set_reg_field_value(value, 0, SCLV_MODE, SCL_PSCL_EN_C);
++ dal_write_reg(xfm->ctx, addr, value);
++}
++
++bool dce110_transform_underlay_is_scaling_enabled(struct transform *xfm)
++{
++ uint32_t value = dal_read_reg(xfm->ctx, mmSCLV_MODE);
++ uint8_t scl_mode = get_reg_field_value(value, SCLV_MODE, SCL_MODE);
++
++ return scl_mode == 0;
++}
++
++/* TODO: sync this one with DAL2 */
++bool dce110_transform_underlay_set_scaler(
++ struct transform *xfm,
++ const struct scaler_data *data)
++{
++ struct dce110_transform *xfm110 = TO_DCE110_TRANSFORM(xfm);
++ bool is_scaling_required;
++ struct rect luma_viewport = {0};
++ struct rect chroma_viewport = {0};
++ struct dc_context *ctx = xfm->ctx;
++
++ /* 1. Lock Scaler TODO: enable?*/
++ /*set_scaler_update_lock(xfm, true);*/
++
++ /* 2. Calculate viewport, viewport programming should happen after init
++ * calculations as they may require an adjustment in the viewport.
++ */
++
++ calculate_viewport(data, &luma_viewport, &chroma_viewport);
++
++ /* 3. Program overscan */
++ program_overscan(xfm110, &data->overscan);
++
++ /* 4. Program taps and configuration */
++ is_scaling_required = setup_scaling_configuration(xfm110, data);
++
++ if (is_scaling_required) {
++ /* 5. Calculate and program ratio, filter initialization */
++
++ struct sclv_ratios_inits inits = { 0 };
++
++ calculate_inits(
++ xfm110,
++ data,
++ &inits,
++ &luma_viewport,
++ &chroma_viewport);
++
++ program_scl_ratios_inits(xfm110, &inits);
++
++ /*scaler coeff of 2-TAPS use hardware auto calculated value*/
++
++ /* 6. Program vertical filters */
++ if (data->taps.v_taps > 2) {
++ program_two_taps_filter_vert(xfm110, false);
++
++ if (!program_multi_taps_filter(xfm110, data, false)) {
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_DCP,
++ LOG_MINOR_DCP_SCALER,
++ "Failed vertical taps programming\n");
++ return false;
++ }
++ } else
++ program_two_taps_filter_vert(xfm110, true);
++
++ /* 7. Program horizontal filters */
++ if (data->taps.h_taps > 2) {
++ program_two_taps_filter_horz(xfm110, false);
++
++ if (!program_multi_taps_filter(xfm110, data, true)) {
++ dal_logger_write(ctx->logger,
++ LOG_MAJOR_DCP,
++ LOG_MINOR_DCP_SCALER,
++ "Failed horizontal taps programming\n");
++ return false;
++ }
++ } else
++ program_two_taps_filter_horz(xfm110, true);
++ }
++
++ /* 8. Program the viewport */
++ if (data->flags.bits.SHOULD_PROGRAM_VIEWPORT)
++ program_viewport(xfm110, &luma_viewport, &chroma_viewport);
++
++ /* 9. Unlock the Scaler TODO: enable?*/
++ /* Every call to "set_scaler_update_lock(xfm, TRUE)"
++ * must have a corresponding call to
++ * "set_scaler_update_lock(xfm, FALSE)" */
++ /*set_scaler_update_lock(xfm, false);*/
++
++ /* TODO: investigate purpose/need of SHOULD_UNLOCK */
++ if (data->flags.bits.SHOULD_UNLOCK == false)
++ set_coeff_update_complete(xfm110);
++
++ return true;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/Makefile b/drivers/gpu/drm/amd/dal/dc/dcs/Makefile
+new file mode 100644
+index 0000000..a266942
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dcs/Makefile
+@@ -0,0 +1,10 @@
++#
++# Makefile for the 'gpu' sub-component of DAL.
++# It provides the control and status of HW adapter resources,
++# that are global for the ASIC and sharable between pipes.
++
++DCS = ddc_service.o ddc_i2caux_helper.o
++
++AMD_DAL_DCS = $(addprefix $(AMDDALPATH)/dc/dcs/,$(DCS))
++
++AMD_DAL_FILES += $(AMD_DAL_DCS)
+diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c
+new file mode 100644
+index 0000000..a4442d6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.c
+@@ -0,0 +1,159 @@
++/*
++ * 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 "dal_services.h"
++#include "ddc_i2caux_helper.h"
++#include "include/ddc_service_types.h"
++#include "include/vector.h"
++
++struct i2c_payloads {
++ struct vector payloads;
++};
++
++struct aux_payloads {
++ struct vector payloads;
++};
++
++struct i2c_payloads *dal_ddc_i2c_payloads_create(struct dc_context *ctx, uint32_t count)
++{
++ struct i2c_payloads *payloads;
++
++ payloads = dc_service_alloc(ctx, sizeof(struct i2c_payloads));
++
++ if (!payloads)
++ return NULL;
++
++ if (dal_vector_construct(
++ &payloads->payloads, ctx, count, sizeof(struct i2c_payload)))
++ return payloads;
++
++ dc_service_free(ctx, payloads);
++ return NULL;
++
++}
++
++struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p)
++{
++ return (struct i2c_payload *)p->payloads.container;
++}
++
++uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p)
++{
++ return p->payloads.count;
++}
++
++void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p)
++{
++ if (!p || !*p)
++ return;
++ dal_vector_destruct(&(*p)->payloads);
++ dc_service_free((*p)->payloads.ctx, *p);
++ *p = NULL;
++
++}
++
++struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count)
++{
++ struct aux_payloads *payloads;
++
++ payloads = dc_service_alloc(ctx, sizeof(struct aux_payloads));
++
++ if (!payloads)
++ return NULL;
++
++ if (dal_vector_construct(
++ &payloads->payloads, ctx, count, sizeof(struct aux_payloads)))
++ return payloads;
++
++ dc_service_free(ctx, payloads);
++ return NULL;
++}
++
++struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p)
++{
++ return (struct aux_payload *)p->payloads.container;
++}
++
++uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p)
++{
++ return p->payloads.count;
++}
++
++
++void dal_ddc_aux_payloads_destroy(struct aux_payloads **p)
++{
++ if (!p || !*p)
++ return;
++
++ dal_vector_destruct(&(*p)->payloads);
++ dc_service_free((*p)->payloads.ctx, *p);
++ *p = NULL;
++}
++
++#define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b))
++
++void dal_ddc_i2c_payloads_add(
++ struct i2c_payloads *payloads,
++ uint32_t address,
++ uint32_t len,
++ uint8_t *data,
++ bool write)
++{
++ uint32_t payload_size = EDID_SEGMENT_SIZE;
++ uint32_t pos;
++
++ for (pos = 0; pos < len; pos += payload_size) {
++ struct i2c_payload payload = {
++ .write = write,
++ .address = address,
++ .length = DDC_MIN(payload_size, len - pos),
++ .data = data + pos };
++ dal_vector_append(&payloads->payloads, &payload);
++ }
++
++}
++
++void dal_ddc_aux_payloads_add(
++ struct aux_payloads *payloads,
++ uint32_t address,
++ uint32_t len,
++ uint8_t *data,
++ bool write)
++{
++ uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE;
++ uint32_t pos;
++
++ for (pos = 0; pos < len; pos += payload_size) {
++ struct aux_payload payload = {
++ .i2c_over_aux = true,
++ .write = write,
++ .address = address,
++ .length = DDC_MIN(payload_size, len - pos),
++ .data = data + pos };
++ dal_vector_append(&payloads->payloads, &payload);
++ }
++}
++
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h
+new file mode 100644
+index 0000000..bb628cd
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_i2caux_helper.h
+@@ -0,0 +1,60 @@
++/*
++ * 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_I2CAUX_HELPER_H__
++#define __DAL_I2CAUX_HELPER_H__
++
++#include "include/i2caux_interface.h"
++
++#define EDID_SEGMENT_SIZE 256
++
++struct i2c_payloads;
++struct aux_payloads;
++
++struct i2c_payloads *dal_ddc_i2c_payloads_create(struct dc_context *ctx, uint32_t count);
++struct i2c_payload *dal_ddc_i2c_payloads_get(struct i2c_payloads *p);
++uint32_t dal_ddc_i2c_payloads_get_count(struct i2c_payloads *p);
++void dal_ddc_i2c_payloads_destroy(struct i2c_payloads **p);
++
++struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count);
++struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p);
++uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p);
++void dal_ddc_aux_payloads_destroy(struct aux_payloads **p);
++
++void dal_ddc_i2c_payloads_add(
++ struct i2c_payloads *payloads,
++ uint32_t address,
++ uint32_t len,
++ uint8_t *data,
++ bool write);
++
++void dal_ddc_aux_payloads_add(
++ struct aux_payloads *payloads,
++ uint32_t address,
++ uint32_t len,
++ uint8_t *data,
++ bool write);
++
++#endif /* __DAL_I2CAUX_HELPER_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c
+new file mode 100644
+index 0000000..5436704
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.c
+@@ -0,0 +1,1034 @@
++/*
++ * 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 "dal_services.h"
++#include "include/adapter_service_interface.h"
++#include "include/i2caux_interface.h"
++#include "include/ddc_service_interface.h"
++#include "include/ddc_service_types.h"
++#include "include/grph_object_id.h"
++#include "include/dpcd_defs.h"
++#include "include/logger_interface.h"
++#include "ddc_i2caux_helper.h"
++#include "ddc_service.h"
++#include "dal_services_types.h"
++
++#define AUX_POWER_UP_WA_DELAY 500
++#define I2C_OVER_AUX_DEFER_WA_DELAY 70
++
++/* CV smart dongle slave address for retrieving supported HDTV modes*/
++#define CV_SMART_DONGLE_ADDRESS 0x20
++/* DVI-HDMI dongle slave address for retrieving dongle signature*/
++#define DVI_HDMI_DONGLE_ADDRESS 0x68
++static const int8_t dvi_hdmi_dongle_signature_str[] = "6140063500G";
++struct dvi_hdmi_dongle_signature_data {
++ int8_t vendor[3];/* "AMD" */
++ uint8_t version[2];
++ uint8_t size;
++ int8_t id[11];/* "6140063500G"*/
++};
++/* DP-HDMI dongle slave address for retrieving dongle signature*/
++#define DP_HDMI_DONGLE_ADDRESS 0x40
++static const uint8_t dp_hdmi_dongle_signature_str[] = "DP-HDMI ADAPTOR";
++#define DP_HDMI_DONGLE_SIGNATURE_EOT 0x04
++
++struct dp_hdmi_dongle_signature_data {
++ int8_t id[15];/* "DP-HDMI ADAPTOR"*/
++ uint8_t eot;/* end of transmition '\x4' */
++};
++
++/* Address range from 0x00 to 0x1F.*/
++#define DP_ADAPTOR_TYPE2_SIZE 0x20
++#define DP_ADAPTOR_TYPE2_REG_ID 0x10
++#define DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK 0x1D
++/* Identifies adaptor as Dual-mode adaptor */
++#define DP_ADAPTOR_TYPE2_ID 0xA0
++/* MHz*/
++#define DP_ADAPTOR_TYPE2_MAX_TMDS_CLK 600
++/* MHz*/
++#define DP_ADAPTOR_TYPE2_MIN_TMDS_CLK 25
++/* kHZ*/
++#define DP_ADAPTOR_DVI_MAX_TMDS_CLK 165000
++/* kHZ*/
++#define DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK 165000
++
++#define DDC_I2C_COMMAND_ENGINE I2C_COMMAND_ENGINE_SW
++
++enum edid_read_result {
++ EDID_READ_RESULT_EDID_MATCH = 0,
++ EDID_READ_RESULT_EDID_MISMATCH,
++ EDID_READ_RESULT_CHECKSUM_READ_ERR,
++ EDID_READ_RESULT_VENDOR_READ_ERR
++};
++
++/* SCDC Address defines (HDMI 2.0)*/
++#define HDMI_SCDC_WRITE_UPDATE_0_ARRAY 3
++#define HDMI_SCDC_ADDRESS 0x54
++#define HDMI_SCDC_SINK_VERSION 0x01
++#define HDMI_SCDC_SOURCE_VERSION 0x02
++#define HDMI_SCDC_UPDATE_0 0x10
++#define HDMI_SCDC_TMDS_CONFIG 0x20
++#define HDMI_SCDC_SCRAMBLER_STATUS 0x21
++#define HDMI_SCDC_CONFIG_0 0x30
++#define HDMI_SCDC_STATUS_FLAGS 0x40
++#define HDMI_SCDC_ERR_DETECT 0x50
++#define HDMI_SCDC_TEST_CONFIG 0xC0
++
++
++union hdmi_scdc_update_read_data
++{
++ uint8_t byte[2];
++ struct
++ {
++ uint8_t STATUS_UPDATE:1;
++ uint8_t CED_UPDATE:1;
++ uint8_t RR_TEST:1;
++ uint8_t RESERVED:5;
++ uint8_t RESERVED2:8;
++ } fields;
++};
++
++union hdmi_scdc_status_flags_data
++{
++ uint8_t byte[2];
++ struct
++ {
++ uint8_t CLOCK_DETECTED:1;
++ uint8_t CH0_LOCKED:1;
++ uint8_t CH1_LOCKED:1;
++ uint8_t CH2_LOCKED:1;
++ uint8_t RESERVED:4;
++ uint8_t RESERVED2:8;
++ } fields;
++};
++
++union hdmi_scdc_ced_data
++{
++ uint8_t byte[7];
++ struct
++ {
++ uint8_t CH0_8LOW:8;
++ uint8_t CH0_7HIGH:7;
++ uint8_t CH0_VALID:1;
++ uint8_t CH1_8LOW:8;
++ uint8_t CH1_7HIGH:7;
++ uint8_t CH1_VALID:1;
++ uint8_t CH2_8LOW:8;
++ uint8_t CH2_7HIGH:7;
++ uint8_t CH2_VALID:1;
++ uint8_t CHECKSUM:8;
++ } fields;
++};
++
++union hdmi_scdc_test_config_Data
++{
++ uint8_t byte;
++ struct
++ {
++ uint8_t TEST_READ_REQUEST_DELAY:7;
++ uint8_t TEST_READ_REQUEST: 1;
++ } fields;
++};
++
++
++
++union ddc_wa {
++ struct {
++ uint32_t DP_SKIP_POWER_OFF:1;
++ uint32_t DP_AUX_POWER_UP_WA_DELAY:1;
++ } bits;
++ uint32_t raw;
++};
++
++struct ddc_flags {
++ uint8_t EDID_QUERY_DONE_ONCE:1;
++ uint8_t IS_INTERNAL_DISPLAY:1;
++ uint8_t FORCE_READ_REPEATED_START:1;
++ uint8_t EDID_STRESS_READ:1;
++
++};
++
++struct ddc_service {
++ struct ddc *ddc_pin;
++ struct ddc_flags flags;
++ union ddc_wa wa;
++ enum ddc_transaction_type transaction_type;
++ enum display_dongle_type dongle_type;
++ struct dp_receiver_id_info dp_receiver_id_info;
++ struct adapter_service *as;
++ struct dc_context *ctx;
++
++ uint32_t address;
++ uint32_t edid_buf_len;
++ uint8_t edid_buf[MAX_EDID_BUFFER_SIZE];
++};
++
++static bool construct(
++ struct ddc_service *ddc_service,
++ struct ddc_service_init_data *init_data)
++{
++ enum connector_id connector_id =
++ dal_graphics_object_id_get_connector_id(init_data->id);
++
++ ddc_service->ctx = init_data->ctx;
++ ddc_service->as = init_data->as;
++ ddc_service->ddc_pin = dal_adapter_service_obtain_ddc(
++ init_data->as, init_data->id);
++
++ ddc_service->flags.EDID_QUERY_DONE_ONCE = false;
++
++ ddc_service->flags.FORCE_READ_REPEATED_START =
++ dal_adapter_service_is_feature_supported(
++ FEATURE_DDC_READ_FORCE_REPEATED_START);
++
++ ddc_service->flags.EDID_STRESS_READ =
++ dal_adapter_service_is_feature_supported(
++ FEATURE_EDID_STRESS_READ);
++
++
++ ddc_service->flags.IS_INTERNAL_DISPLAY =
++ connector_id == CONNECTOR_ID_EDP ||
++ connector_id == CONNECTOR_ID_LVDS;
++
++ ddc_service->wa.raw = 0;
++ return true;
++}
++
++struct ddc_service *dal_ddc_service_create(
++ struct ddc_service_init_data *init_data)
++{
++ struct ddc_service *ddc_service;
++
++ ddc_service = dc_service_alloc(init_data->ctx, sizeof(struct ddc_service));
++
++ if (!ddc_service)
++ return NULL;
++
++ if (construct(ddc_service, init_data))
++ return ddc_service;
++
++ dc_service_free(init_data->ctx, ddc_service);
++ return NULL;
++}
++
++static void destruct(struct ddc_service *ddc)
++{
++ if (ddc->ddc_pin)
++ dal_adapter_service_release_ddc(ddc->as, ddc->ddc_pin);
++}
++
++void dal_ddc_service_destroy(struct ddc_service **ddc)
++{
++ if (!ddc || !*ddc) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++ destruct(*ddc);
++ dc_service_free((*ddc)->ctx, *ddc);
++ *ddc = NULL;
++}
++
++enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc)
++{
++ return DDC_SERVICE_TYPE_CONNECTOR;
++}
++
++void dal_ddc_service_set_transaction_type(
++ struct ddc_service *ddc,
++ enum ddc_transaction_type type)
++{
++ ddc->transaction_type = type;
++}
++
++bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc)
++{
++ switch (ddc->transaction_type) {
++ case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
++ case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
++ case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER:
++ return true;
++ default:
++ break;
++ }
++ return false;
++}
++
++void ddc_service_set_dongle_type(struct ddc_service *ddc,
++ enum display_dongle_type dongle_type)
++{
++ ddc->dongle_type = dongle_type;
++}
++
++static uint32_t defer_delay_converter_wa(
++ struct ddc_service *ddc,
++ uint32_t defer_delay)
++{
++ struct dp_receiver_id_info dp_rec_info = {0};
++
++ if (dal_ddc_service_get_dp_receiver_id_info(ddc, &dp_rec_info) &&
++ (dp_rec_info.branch_id == DP_BRANCH_DEVICE_ID_4) &&
++ !dal_strncmp(dp_rec_info.branch_name,
++ DP_DVI_CONVERTER_ID_4,
++ sizeof(dp_rec_info.branch_name)))
++ return defer_delay > I2C_OVER_AUX_DEFER_WA_DELAY ?
++ defer_delay : I2C_OVER_AUX_DEFER_WA_DELAY;
++
++ return defer_delay;
++
++}
++
++#define DP_TRANSLATOR_DELAY 5
++
++static uint32_t get_defer_delay(struct ddc_service *ddc)
++{
++ uint32_t defer_delay = 0;
++
++ switch (ddc->transaction_type) {
++ case DDC_TRANSACTION_TYPE_I2C_OVER_AUX:
++ if ((DISPLAY_DONGLE_DP_VGA_CONVERTER == ddc->dongle_type) ||
++ (DISPLAY_DONGLE_DP_DVI_CONVERTER == ddc->dongle_type) ||
++ (DISPLAY_DONGLE_DP_HDMI_CONVERTER ==
++ ddc->dongle_type)) {
++
++ defer_delay = DP_TRANSLATOR_DELAY;
++
++ defer_delay =
++ defer_delay_converter_wa(ddc, defer_delay);
++
++ } else /*sink has a delay different from an Active Converter*/
++ defer_delay = 0;
++ break;
++ case DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER:
++ defer_delay = DP_TRANSLATOR_DELAY;
++ break;
++ default:
++ break;
++ }
++ return defer_delay;
++}
++
++static bool i2c_read(
++ struct ddc_service *ddc,
++ uint32_t address,
++ uint8_t *buffer,
++ uint32_t len)
++{
++ uint8_t offs_data = 0;
++ struct i2c_payload payloads[2] = {
++ {
++ .write = true,
++ .address = address,
++ .length = 1,
++ .data = &offs_data },
++ {
++ .write = false,
++ .address = address,
++ .length = len,
++ .data = buffer } };
++
++ struct i2c_command command = {
++ .payloads = payloads,
++ .number_of_payloads = 2,
++ .engine = DDC_I2C_COMMAND_ENGINE,
++ .speed = dal_adapter_service_get_sw_i2c_speed(ddc->as) };
++
++ return dal_i2caux_submit_i2c_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &command);
++}
++
++static uint8_t aux_read_edid_block(
++ struct ddc_service *ddc,
++ uint8_t address,
++ uint8_t index,
++ uint8_t *buf)
++{
++ struct aux_command cmd = {
++ .payloads = NULL,
++ .number_of_payloads = 0,
++ .defer_delay = get_defer_delay(ddc),
++ .max_defer_write_retry = 0 };
++
++ uint8_t retrieved = 0;
++ uint8_t base_offset =
++ (index % DDC_EDID_BLOCKS_PER_SEGMENT) * DDC_EDID_BLOCK_SIZE;
++ uint8_t segment = index / DDC_EDID_BLOCKS_PER_SEGMENT;
++
++ for (retrieved = 0; retrieved < DDC_EDID_BLOCK_SIZE;
++ retrieved += DEFAULT_AUX_MAX_DATA_SIZE) {
++
++ uint8_t offset = base_offset + retrieved;
++
++ struct aux_payload payloads[3] = {
++ {
++ .i2c_over_aux = true,
++ .write = true,
++ .address = DDC_EDID_SEGMENT_ADDRESS,
++ .length = 1,
++ .data = &segment },
++ {
++ .i2c_over_aux = true,
++ .write = true,
++ .address = address,
++ .length = 1,
++ .data = &offset },
++ {
++ .i2c_over_aux = true,
++ .write = false,
++ .address = address,
++ .length = DEFAULT_AUX_MAX_DATA_SIZE,
++ .data = &buf[retrieved] } };
++
++ if (segment == 0) {
++ cmd.payloads = &payloads[1];
++ cmd.number_of_payloads = 2;
++ } else {
++ cmd.payloads = payloads;
++ cmd.number_of_payloads = 3;
++ }
++
++ if (!dal_i2caux_submit_aux_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &cmd))
++ /* cannot read, break*/
++ break;
++ }
++
++ /* Reset segment to 0. Needed by some panels */
++ if (0 != segment) {
++ struct aux_payload payloads[1] = { {
++ .i2c_over_aux = true,
++ .write = true,
++ .address = DDC_EDID_SEGMENT_ADDRESS,
++ .length = 1,
++ .data = &segment } };
++ bool result = false;
++
++ segment = 0;
++
++ cmd.number_of_payloads = ARRAY_SIZE(payloads);
++ cmd.payloads = payloads;
++
++ result = dal_i2caux_submit_aux_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &cmd);
++
++ if (false == result)
++ dal_logger_write(
++ ddc->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_DISPLAY_CAPABILITY_SERVICE,
++ "%s: Writing of EDID Segment (0x30) failed!\n",
++ __func__);
++ }
++
++ return retrieved;
++}
++
++static uint8_t i2c_read_edid_block(
++ struct ddc_service *ddc,
++ uint8_t address,
++ uint8_t index,
++ uint8_t *buf)
++{
++ bool ret = false;
++ uint8_t offset = (index % DDC_EDID_BLOCKS_PER_SEGMENT) *
++ DDC_EDID_BLOCK_SIZE;
++ uint8_t segment = index / DDC_EDID_BLOCKS_PER_SEGMENT;
++
++ struct i2c_command cmd = {
++ .payloads = NULL,
++ .number_of_payloads = 0,
++ .engine = DDC_I2C_COMMAND_ENGINE,
++ .speed = dal_adapter_service_get_sw_i2c_speed(ddc->as) };
++
++ struct i2c_payload payloads[3] = {
++ {
++ .write = true,
++ .address = DDC_EDID_SEGMENT_ADDRESS,
++ .length = 1,
++ .data = &segment },
++ {
++ .write = true,
++ .address = address,
++ .length = 1,
++ .data = &offset },
++ {
++ .write = false,
++ .address = address,
++ .length = DDC_EDID_BLOCK_SIZE,
++ .data = buf } };
++/*
++ * Some I2C engines don't handle stop/start between write-offset and read-data
++ * commands properly. For those displays, we have to force the newer E-DDC
++ * behavior of repeated-start which can be enabled by runtime parameter. */
++/* Originally implemented for OnLive using NXP receiver chip */
++
++ if (index == 0 && !ddc->flags.FORCE_READ_REPEATED_START) {
++ /* base block, use use DDC2B, submit as 2 commands */
++ cmd.payloads = &payloads[1];
++ cmd.number_of_payloads = 1;
++
++ if (dal_i2caux_submit_i2c_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &cmd)) {
++
++ cmd.payloads = &payloads[2];
++ cmd.number_of_payloads = 1;
++
++ ret = dal_i2caux_submit_i2c_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &cmd);
++ }
++
++ } else {
++ /*
++ * extension block use E-DDC, submit as 1 command
++ * or if repeated-start is forced by runtime parameter
++ */
++ if (segment != 0) {
++ /* include segment offset in command*/
++ cmd.payloads = payloads;
++ cmd.number_of_payloads = 3;
++ } else {
++ /* we are reading first segment,
++ * segment offset is not required */
++ cmd.payloads = &payloads[1];
++ cmd.number_of_payloads = 2;
++ }
++
++ ret = dal_i2caux_submit_i2c_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &cmd);
++ }
++
++ return ret ? DDC_EDID_BLOCK_SIZE : 0;
++}
++
++static uint32_t query_edid_block(
++ struct ddc_service *ddc,
++ uint8_t address,
++ uint8_t index,
++ uint8_t *buf,
++ uint32_t size)
++{
++ uint32_t size_retrieved = 0;
++
++ if (size < DDC_EDID_BLOCK_SIZE)
++ return 0;
++
++ if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
++
++ ASSERT(index < 2);
++ size_retrieved =
++ aux_read_edid_block(ddc, address, index, buf);
++ } else {
++ size_retrieved =
++ i2c_read_edid_block(ddc, address, index, buf);
++ }
++
++ return size_retrieved;
++}
++
++#define DDC_DPCD_EDID_CHECKSUM_WRITE_ADDRESS 0x261
++#define DDC_TEST_ACK_ADDRESS 0x260
++#define DDC_DPCD_EDID_TEST_ACK 0x04
++#define DDC_DPCD_EDID_TEST_MASK 0x04
++#define DDC_DPCD_TEST_REQUEST_ADDRESS 0x218
++
++static void write_dp_edid_checksum(
++ struct ddc_service *ddc,
++ uint8_t checksum)
++{
++ uint8_t dpcd_data;
++
++ dal_ddc_service_read_dpcd_data(
++ ddc,
++ DDC_DPCD_TEST_REQUEST_ADDRESS,
++ &dpcd_data,
++ 1);
++
++ if (dpcd_data & DDC_DPCD_EDID_TEST_MASK) {
++
++ dal_ddc_service_write_dpcd_data(
++ ddc,
++ DDC_DPCD_EDID_CHECKSUM_WRITE_ADDRESS,
++ &checksum,
++ 1);
++
++ dpcd_data = DDC_DPCD_EDID_TEST_ACK;
++
++ dal_ddc_service_write_dpcd_data(
++ ddc,
++ DDC_TEST_ACK_ADDRESS,
++ &dpcd_data,
++ 1);
++ }
++}
++
++uint32_t dal_ddc_service_edid_query(struct ddc_service *ddc)
++{
++ uint32_t bytes_read = 0;
++ uint32_t ext_cnt = 0;
++
++ uint8_t address;
++ uint32_t i;
++
++ for (address = DDC_EDID_ADDRESS_START;
++ address <= DDC_EDID_ADDRESS_END; ++address) {
++
++ bytes_read = query_edid_block(
++ ddc,
++ address,
++ 0,
++ ddc->edid_buf,
++ sizeof(ddc->edid_buf) - bytes_read);
++
++ if (bytes_read != DDC_EDID_BLOCK_SIZE)
++ continue;
++
++ /* get the number of ext blocks*/
++ ext_cnt = ddc->edid_buf[DDC_EDID_EXT_COUNT_OFFSET];
++
++ /* EDID 2.0, need to read 1 more block because EDID2.0 is
++ * 256 byte in size*/
++ if (ddc->edid_buf[DDC_EDID_20_SIGNATURE_OFFSET] ==
++ DDC_EDID_20_SIGNATURE)
++ ext_cnt = 1;
++
++ for (i = 0; i < ext_cnt; i++) {
++ /* read additional ext blocks accordingly */
++ bytes_read += query_edid_block(
++ ddc,
++ address,
++ i+1,
++ &ddc->edid_buf[bytes_read],
++ sizeof(ddc->edid_buf) - bytes_read);
++ }
++
++ /*this is special code path for DP compliance*/
++ if (DDC_TRANSACTION_TYPE_I2C_OVER_AUX == ddc->transaction_type)
++ write_dp_edid_checksum(
++ ddc,
++ ddc->edid_buf[(ext_cnt * DDC_EDID_BLOCK_SIZE) +
++ DDC_EDID1X_CHECKSUM_OFFSET]);
++
++ /*remembers the address where we fetch the EDID from
++ * for later signature check use */
++ ddc->address = address;
++
++ break;/* already read edid, done*/
++ }
++
++ ddc->edid_buf_len = bytes_read;
++ return bytes_read;
++}
++
++uint32_t dal_ddc_service_get_edid_buf_len(struct ddc_service *ddc)
++{
++ return ddc->edid_buf_len;
++}
++
++void dal_ddc_service_get_edid_buf(struct ddc_service *ddc, uint8_t *edid_buf)
++{
++ dc_service_memmove(edid_buf,
++ ddc->edid_buf, ddc->edid_buf_len);
++}
++
++void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
++ struct ddc_service *ddc,
++ struct display_sink_capability *sink_cap)
++{
++ uint8_t i;
++ bool is_valid_hdmi_signature;
++ enum display_dongle_type *dongle = &sink_cap->dongle_type;
++ uint8_t type2_dongle_buf[DP_ADAPTOR_TYPE2_SIZE];
++ bool is_type2_dongle = false;
++ struct dp_hdmi_dongle_signature_data *dongle_signature;
++
++ /* Assume we have no valid DP passive dongle connected */
++ *dongle = DISPLAY_DONGLE_NONE;
++ sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_HDMI_SAFE_MAX_TMDS_CLK;
++
++ /* Read DP-HDMI dongle I2c (no response interpreted as DP-DVI dongle)*/
++ if (!i2c_read(
++ ddc,
++ DP_HDMI_DONGLE_ADDRESS,
++ type2_dongle_buf,
++ sizeof(type2_dongle_buf))) {
++ dal_logger_write(ddc->ctx->logger,
++ LOG_MAJOR_DCS,
++ LOG_MINOR_DCS_DONGLE_DETECTION,
++ "Detected DP-DVI dongle.\n");
++ *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
++ sink_cap->max_hdmi_pixel_clock = DP_ADAPTOR_DVI_MAX_TMDS_CLK;
++ return;
++ }
++
++ /* Check if Type 2 dongle.*/
++ if (type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_ID] == DP_ADAPTOR_TYPE2_ID)
++ is_type2_dongle = true;
++
++ dongle_signature =
++ (struct dp_hdmi_dongle_signature_data *)type2_dongle_buf;
++
++ is_valid_hdmi_signature = true;
++
++ /* Check EOT */
++ if (dongle_signature->eot != DP_HDMI_DONGLE_SIGNATURE_EOT) {
++ is_valid_hdmi_signature = false;
++ }
++
++ /* Check signature */
++ for (i = 0; i < sizeof(dongle_signature->id); ++i) {
++ /* If its not the right signature,
++ * skip mismatch in subversion byte.*/
++ if (dongle_signature->id[i] !=
++ dp_hdmi_dongle_signature_str[i] && i != 3) {
++
++ if (is_type2_dongle) {
++ is_valid_hdmi_signature = false;
++ break;
++ }
++
++ }
++ }
++
++ if (is_type2_dongle) {
++ uint32_t max_tmds_clk =
++ type2_dongle_buf[DP_ADAPTOR_TYPE2_REG_MAX_TMDS_CLK];
++
++ max_tmds_clk = max_tmds_clk * 2 + max_tmds_clk / 2;
++
++ if (0 == max_tmds_clk ||
++ max_tmds_clk < DP_ADAPTOR_TYPE2_MIN_TMDS_CLK ||
++ max_tmds_clk > DP_ADAPTOR_TYPE2_MAX_TMDS_CLK) {
++ dal_logger_write(ddc->ctx->logger,
++ LOG_MAJOR_DCS,
++ LOG_MINOR_DCS_DONGLE_DETECTION,
++ "Invalid Maximum TMDS clock");
++ *dongle = DISPLAY_DONGLE_DP_DVI_DONGLE;
++ } else {
++ if (is_valid_hdmi_signature == true) {
++ *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
++ dal_logger_write(ddc->ctx->logger,
++ LOG_MAJOR_DCS,
++ LOG_MINOR_DCS_DONGLE_DETECTION,
++ "Detected Type 2 DP-HDMI Maximum TMDS "
++ "clock, max TMDS clock: %d MHz",
++ max_tmds_clk);
++ } else {
++ *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
++ dal_logger_write(ddc->ctx->logger,
++ LOG_MAJOR_DCS,
++ LOG_MINOR_DCS_DONGLE_DETECTION,
++ "Detected Type 2 DP-HDMI (no valid HDMI"
++ " signature) Maximum TMDS clock, max "
++ "TMDS clock: %d MHz",
++ max_tmds_clk);
++ }
++
++ /* Multiply by 1000 to convert to kHz. */
++ sink_cap->max_hdmi_pixel_clock =
++ max_tmds_clk * 1000;
++ }
++
++ } else {
++ if (is_valid_hdmi_signature == true) {
++ dal_logger_write(ddc->ctx->logger,
++ LOG_MAJOR_DCS,
++ LOG_MINOR_DCS_DONGLE_DETECTION,
++ "Detected Type 1 DP-HDMI dongle.\n");
++ *dongle = DISPLAY_DONGLE_DP_HDMI_DONGLE;
++ }
++ else {
++ dal_logger_write(ddc->ctx->logger,
++ LOG_MAJOR_DCS,
++ LOG_MINOR_DCS_DONGLE_DETECTION,
++ "Detected Type 1 DP-HDMI dongle (no valid HDMI "
++ "signature).\n");
++
++ *dongle = DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE;
++ }
++ }
++
++ return;
++}
++
++enum {
++ DP_SINK_CAP_SIZE =
++ DPCD_ADDRESS_EDP_CONFIG_CAP - DPCD_ADDRESS_DPCD_REV + 1
++};
++
++bool dal_ddc_service_query_ddc_data(
++ struct ddc_service *ddc,
++ uint32_t address,
++ uint8_t *write_buf,
++ uint32_t write_size,
++ uint8_t *read_buf,
++ uint32_t read_size)
++{
++ bool ret;
++ uint32_t payload_size =
++ dal_ddc_service_is_in_aux_transaction_mode(ddc) ?
++ DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE;
++
++ uint32_t write_payloads =
++ (write_size + payload_size - 1) / payload_size;
++
++ uint32_t read_payloads =
++ (read_size + payload_size - 1) / payload_size;
++
++ uint32_t payloads_num = write_payloads + read_payloads;
++
++ if (write_size > EDID_SEGMENT_SIZE || read_size > EDID_SEGMENT_SIZE)
++ return false;
++
++ /*TODO: len of payload data for i2c and aux is uint8!!!!,
++ * but we want to read 256 over i2c!!!!*/
++ if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
++
++ struct aux_payloads *payloads =
++ dal_ddc_aux_payloads_create(ddc->ctx, payloads_num);
++
++ struct aux_command command = {
++ .payloads = dal_ddc_aux_payloads_get(payloads),
++ .number_of_payloads = 0,
++ .defer_delay = get_defer_delay(ddc),
++ .max_defer_write_retry = 0 };
++
++ dal_ddc_aux_payloads_add(
++ payloads, address, write_size, write_buf, true);
++
++ dal_ddc_aux_payloads_add(
++ payloads, address, read_size, read_buf, false);
++
++ command.number_of_payloads =
++ dal_ddc_aux_payloads_get_count(payloads);
++
++ ret = dal_i2caux_submit_aux_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &command);
++
++ dal_ddc_aux_payloads_destroy(&payloads);
++
++ } else {
++ struct i2c_payloads *payloads =
++ dal_ddc_i2c_payloads_create(ddc->ctx, payloads_num);
++
++ struct i2c_command command = {
++ .payloads = dal_ddc_i2c_payloads_get(payloads),
++ .number_of_payloads = 0,
++ .engine = DDC_I2C_COMMAND_ENGINE,
++ .speed =
++ dal_adapter_service_get_sw_i2c_speed(ddc->as) };
++
++ dal_ddc_i2c_payloads_add(
++ payloads, address, write_size, write_buf, true);
++
++ dal_ddc_i2c_payloads_add(
++ payloads, address, read_size, read_buf, false);
++
++ command.number_of_payloads =
++ dal_ddc_i2c_payloads_get_count(payloads);
++
++ ret = dal_i2caux_submit_i2c_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &command);
++
++ dal_ddc_i2c_payloads_destroy(&payloads);
++ }
++
++ return ret;
++}
++
++bool dal_ddc_service_get_dp_receiver_id_info(
++ struct ddc_service *ddc,
++ struct dp_receiver_id_info *info)
++{
++ if (!info)
++ return false;
++
++ *info = ddc->dp_receiver_id_info;
++ return true;
++}
++
++enum ddc_result dal_ddc_service_read_dpcd_data(
++ struct ddc_service *ddc,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t len)
++{
++ struct aux_payload read_payload = {
++ .i2c_over_aux = false,
++ .write = false,
++ .address = address,
++ .length = len,
++ .data = data,
++ };
++ struct aux_command command = {
++ .payloads = &read_payload,
++ .number_of_payloads = 1,
++ .defer_delay = 0,
++ .max_defer_write_retry = 0,
++ };
++
++ if (len > DEFAULT_AUX_MAX_DATA_SIZE) {
++ BREAK_TO_DEBUGGER();
++ return DDC_RESULT_FAILED_INVALID_OPERATION;
++ }
++
++ if (dal_i2caux_submit_aux_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &command))
++ return DDC_RESULT_SUCESSFULL;
++
++ return DDC_RESULT_FAILED_OPERATION;
++}
++
++enum ddc_result dal_ddc_service_write_dpcd_data(
++ struct ddc_service *ddc,
++ uint32_t address,
++ const uint8_t *data,
++ uint32_t len)
++{
++ struct aux_payload write_payload = {
++ .i2c_over_aux = false,
++ .write = true,
++ .address = address,
++ .length = len,
++ .data = (uint8_t *)data,
++ };
++ struct aux_command command = {
++ .payloads = &write_payload,
++ .number_of_payloads = 1,
++ .defer_delay = 0,
++ .max_defer_write_retry = 0,
++ };
++
++ if (len > DEFAULT_AUX_MAX_DATA_SIZE) {
++ BREAK_TO_DEBUGGER();
++ return DDC_RESULT_FAILED_INVALID_OPERATION;
++ }
++
++ if (dal_i2caux_submit_aux_command(
++ dal_adapter_service_get_i2caux(ddc->as),
++ ddc->ddc_pin,
++ &command))
++ return DDC_RESULT_SUCESSFULL;
++
++ return DDC_RESULT_FAILED_OPERATION;
++}
++
++/*test only function*/
++void dal_ddc_service_set_ddc_pin(
++ struct ddc_service *ddc_service,
++ struct ddc *ddc)
++{
++ ddc_service->ddc_pin = ddc;
++}
++
++struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service)
++{
++ return ddc_service->ddc_pin;
++}
++
++
++void dal_ddc_service_reset_dp_receiver_id_info(struct ddc_service *ddc_service)
++{
++ dc_service_memset(&ddc_service->dp_receiver_id_info,
++ 0, sizeof(struct dp_receiver_id_info));
++}
++
++void dal_ddc_service_write_scdc_data(struct ddc_service *ddc_service,
++ uint32_t pix_clk,
++ bool lte_340_scramble)
++{
++ bool over_340_mhz = pix_clk > 340000 ? 1 : 0;
++ uint8_t slave_address = HDMI_SCDC_ADDRESS;
++ uint8_t offset = HDMI_SCDC_SINK_VERSION;
++ uint8_t sink_version = 0;
++ uint8_t write_buffer[2] = {0};
++ /*Lower than 340 Scramble bit from SCDC caps*/
++
++ dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset,
++ sizeof(offset), &sink_version, sizeof(sink_version));
++ if (sink_version == 1) {
++ /*Source Version = 1*/
++ write_buffer[0] = HDMI_SCDC_SOURCE_VERSION;
++ write_buffer[1] = 1;
++ dal_ddc_service_query_ddc_data(ddc_service, slave_address,
++ write_buffer, sizeof(write_buffer), NULL, 0);
++ /*Read Request from SCDC caps*/
++ }
++ write_buffer[0] = HDMI_SCDC_TMDS_CONFIG;
++
++ if (over_340_mhz)
++ {
++ write_buffer[1] = 3;
++ }
++ else if (lte_340_scramble)
++ {
++ write_buffer[1] = 1;
++ }
++ else
++ {
++ write_buffer[1] = 0;
++ }
++ dal_ddc_service_query_ddc_data(ddc_service, slave_address, write_buffer,
++ sizeof(write_buffer), NULL, 0);
++}
++
++void dal_ddc_service_read_scdc_data(struct ddc_service *ddc_service)
++{
++ uint8_t slave_address = HDMI_SCDC_ADDRESS;
++ uint8_t offset = HDMI_SCDC_TMDS_CONFIG;
++ uint8_t tmds_config = 0;
++
++ dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset,
++ sizeof(offset), &tmds_config, sizeof(tmds_config));
++ if (tmds_config & 0x1){
++ union hdmi_scdc_status_flags_data status_data = {{0}};
++ uint8_t scramble_status = 0;
++
++ offset = HDMI_SCDC_SCRAMBLER_STATUS;
++ dal_ddc_service_query_ddc_data(ddc_service, slave_address,
++ &offset, sizeof(offset),&scramble_status,
++ sizeof(scramble_status));
++ offset = HDMI_SCDC_STATUS_FLAGS;
++ dal_ddc_service_query_ddc_data(ddc_service, slave_address,
++ &offset, sizeof(offset),status_data.byte,
++ sizeof(status_data.byte));
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h
+new file mode 100644
+index 0000000..e5217b7
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/dcs/ddc_service.h
+@@ -0,0 +1,38 @@
++/*
++ * 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_DDC_SERVICE_H__
++#define __DAL_DDC_SERVICE_H__
++
++#include "include/ddc_service_types.h"
++
++void dal_ddc_service_set_ddc_pin(
++ struct ddc_service *ddc_service,
++ struct ddc *ddc);
++
++struct ddc *dal_ddc_service_get_ddc_pin(struct ddc_service *ddc_service);
++void dal_ddc_service_reset_dp_receiver_id_info(struct ddc_service *ddc_service);
++
++#endif /* __DAL_DDC_SERVICE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/Makefile b/drivers/gpu/drm/amd/dal/dc/gpio/Makefile
+new file mode 100644
+index 0000000..7380910
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/Makefile
+@@ -0,0 +1,24 @@
++#
++# Makefile for the 'gpio' sub-component of DAL.
++# It provides the control and status of HW GPIO pins.
++
++GPIO = ddc.o dvo.o gpio_base.o gpio_service.o hw_ddc.o hw_dvo.o hw_factory.o \
++ hw_gpio.o hw_gpio_pad.o hw_gpio_pin.o hw_hpd.o hw_translate.o irq.o
++
++AMD_DAL_GPIO = $(addprefix $(AMDDALPATH)/dc/gpio/,$(GPIO))
++
++AMD_DAL_FILES += $(AMD_DAL_GPIO)
++
++
++###############################################################################
++# DCE 11x
++###############################################################################
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++GPIO_DCE110 = hw_translate_dce110.o hw_factory_dce110.o hw_hpd_dce110.o \
++ hw_ddc_dce110.o
++
++AMD_DAL_GPIO_DCE110 = $(addprefix $(AMDDALPATH)/dc/gpio/dce110/,$(GPIO_DCE110))
++
++AMD_DAL_FILES += $(AMD_DAL_GPIO_DCE110)
++endif
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.c
+new file mode 100644
+index 0000000..f026464
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.c
+@@ -0,0 +1,883 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++#include "../hw_gpio_pin.h"
++#include "../hw_gpio.h"
++#include "../hw_ddc.h"
++
++/*
++ * Header of this unit
++ */
++#include "hw_ddc_dce110.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#define ADDR_DDC_SETUP pin->addr.dc_i2c_ddc_setup
++/*
++ * This unit
++ */
++static void destruct(
++ struct hw_ddc_dce110 *pin)
++{
++ dal_hw_ddc_destruct(&pin->base);
++}
++
++static void destroy(
++ struct hw_gpio_pin **ptr)
++{
++ struct hw_ddc_dce110 *pin = DDC_DCE110_FROM_BASE(*ptr);
++
++ destruct(pin);
++
++ dc_service_free((*ptr)->ctx, pin);
++
++ *ptr = NULL;
++}
++
++struct hw_ddc_dce110_init {
++ struct hw_gpio_pin_reg hw_gpio_data_reg;
++ struct hw_ddc_mask hw_ddc_mask;
++ struct hw_ddc_dce110_addr hw_ddc_dce110_addr;
++};
++
++static const struct hw_ddc_dce110_init
++ hw_ddc_dce110_init_data[GPIO_DDC_LINE_COUNT] = {
++ /* GPIO_DDC_LINE_DDC1 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC1_MASK,
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1DATA_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC1_A,
++ DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC1_EN,
++ DC_GPIO_DDC1_EN__DC_GPIO_DDC1DATA_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC1_Y,
++ DC_GPIO_DDC1_Y__DC_GPIO_DDC1DATA_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1DATA_MASK_MASK,
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1DATA_PD_EN_MASK,
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1DATA_RECV_MASK,
++ DC_GPIO_DDC1_MASK__AUX_PAD1_MODE_MASK,
++ DC_GPIO_DDC1_MASK__AUX1_POL_MASK,
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC1_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC2 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC2_MASK,
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2DATA_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC2_A,
++ DC_GPIO_DDC2_A__DC_GPIO_DDC2DATA_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC2_EN,
++ DC_GPIO_DDC2_EN__DC_GPIO_DDC2DATA_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC2_Y,
++ DC_GPIO_DDC2_Y__DC_GPIO_DDC2DATA_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2DATA_MASK_MASK,
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2DATA_PD_EN_MASK,
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2DATA_RECV_MASK,
++ DC_GPIO_DDC2_MASK__AUX_PAD2_MODE_MASK,
++ DC_GPIO_DDC2_MASK__AUX2_POL_MASK,
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC2_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC3 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC3_MASK,
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3DATA_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC3_A,
++ DC_GPIO_DDC3_A__DC_GPIO_DDC3DATA_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC3_EN,
++ DC_GPIO_DDC3_EN__DC_GPIO_DDC3DATA_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC3_Y,
++ DC_GPIO_DDC3_Y__DC_GPIO_DDC3DATA_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3DATA_MASK_MASK,
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3DATA_PD_EN_MASK,
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3DATA_RECV_MASK,
++ DC_GPIO_DDC3_MASK__AUX_PAD3_MODE_MASK,
++ DC_GPIO_DDC3_MASK__AUX3_POL_MASK,
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC3_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC4 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC4_MASK,
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4DATA_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC4_A,
++ DC_GPIO_DDC4_A__DC_GPIO_DDC4DATA_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC4_EN,
++ DC_GPIO_DDC4_EN__DC_GPIO_DDC4DATA_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC4_Y,
++ DC_GPIO_DDC4_Y__DC_GPIO_DDC4DATA_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4DATA_MASK_MASK,
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4DATA_PD_EN_MASK,
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4DATA_RECV_MASK,
++ DC_GPIO_DDC4_MASK__AUX_PAD4_MODE_MASK,
++ DC_GPIO_DDC4_MASK__AUX4_POL_MASK,
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC4_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC5 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC5_MASK,
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5DATA_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC5_A,
++ DC_GPIO_DDC5_A__DC_GPIO_DDC5DATA_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC5_EN,
++ DC_GPIO_DDC5_EN__DC_GPIO_DDC5DATA_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC5_Y,
++ DC_GPIO_DDC5_Y__DC_GPIO_DDC5DATA_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5DATA_MASK_MASK,
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5DATA_PD_EN_MASK,
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5DATA_RECV_MASK,
++ DC_GPIO_DDC5_MASK__AUX_PAD5_MODE_MASK,
++ DC_GPIO_DDC5_MASK__AUX5_POL_MASK,
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC5_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC6 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC6_MASK,
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6DATA_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC6_A,
++ DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC6_EN,
++ DC_GPIO_DDC6_EN__DC_GPIO_DDC6DATA_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC6_Y,
++ DC_GPIO_DDC6_Y__DC_GPIO_DDC6DATA_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6DATA_MASK_MASK,
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6DATA_PD_EN_MASK,
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6DATA_RECV_MASK,
++ DC_GPIO_DDC6_MASK__AUX_PAD6_MODE_MASK,
++ DC_GPIO_DDC6_MASK__AUX6_POL_MASK,
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC6_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC_VGA */
++ {
++ {
++ {
++ mmDC_GPIO_DDCVGA_MASK,
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDCVGA_A,
++ DC_GPIO_DDCVGA_A__DC_GPIO_DDCVGADATA_A_MASK
++ },
++ {
++ mmDC_GPIO_DDCVGA_EN,
++ DC_GPIO_DDCVGA_EN__DC_GPIO_DDCVGADATA_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDCVGA_Y,
++ DC_GPIO_DDCVGA_Y__DC_GPIO_DDCVGADATA_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_MASK_MASK,
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_PD_EN_MASK,
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_RECV_MASK,
++ DC_GPIO_DDCVGA_MASK__AUX_PADVGA_MODE_MASK,
++ DC_GPIO_DDCVGA_MASK__AUXVGA_POL_MASK,
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDCVGA_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_I2CPAD */
++ {
++ {
++ {
++ mmDC_GPIO_I2CPAD_MASK,
++ DC_GPIO_I2CPAD_MASK__DC_GPIO_SDA_MASK_MASK
++ },
++ {
++ mmDC_GPIO_I2CPAD_A,
++ DC_GPIO_I2CPAD_A__DC_GPIO_SDA_A_MASK
++ },
++ {
++ mmDC_GPIO_I2CPAD_EN,
++ DC_GPIO_I2CPAD_EN__DC_GPIO_SDA_EN_MASK
++ },
++ {
++ mmDC_GPIO_I2CPAD_Y,
++ DC_GPIO_I2CPAD_Y__DC_GPIO_SDA_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_I2CPAD_MASK__DC_GPIO_SDA_MASK_MASK,
++ DC_GPIO_I2CPAD_MASK__DC_GPIO_SDA_PD_DIS_MASK,
++ DC_GPIO_I2CPAD_MASK__DC_GPIO_SDA_RECV_MASK,
++ 0,
++ 0,
++ 0
++ },
++ {
++ 0
++ }
++ }
++};
++
++static const struct hw_ddc_dce110_init
++ hw_ddc_dce110_init_clock[GPIO_DDC_LINE_COUNT] = {
++ /* GPIO_DDC_LINE_DDC1 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC1_MASK,
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC1_A,
++ DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC1_EN,
++ DC_GPIO_DDC1_EN__DC_GPIO_DDC1CLK_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC1_Y,
++ DC_GPIO_DDC1_Y__DC_GPIO_DDC1CLK_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_MASK_MASK,
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_PD_EN_MASK,
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_RECV_MASK,
++ DC_GPIO_DDC1_MASK__AUX_PAD1_MODE_MASK,
++ DC_GPIO_DDC1_MASK__AUX1_POL_MASK,
++ DC_GPIO_DDC1_MASK__DC_GPIO_DDC1CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC1_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC2 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC2_MASK,
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC2_A,
++ DC_GPIO_DDC2_A__DC_GPIO_DDC2CLK_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC2_EN,
++ DC_GPIO_DDC2_EN__DC_GPIO_DDC2CLK_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC2_Y,
++ DC_GPIO_DDC2_Y__DC_GPIO_DDC2CLK_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_MASK_MASK,
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_PD_EN_MASK,
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_RECV_MASK,
++ DC_GPIO_DDC2_MASK__AUX_PAD2_MODE_MASK,
++ DC_GPIO_DDC2_MASK__AUX2_POL_MASK,
++ DC_GPIO_DDC2_MASK__DC_GPIO_DDC2CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC2_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC3 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC3_MASK,
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC3_A,
++ DC_GPIO_DDC3_A__DC_GPIO_DDC3CLK_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC3_EN,
++ DC_GPIO_DDC3_EN__DC_GPIO_DDC3CLK_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC3_Y,
++ DC_GPIO_DDC3_Y__DC_GPIO_DDC3CLK_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_MASK_MASK,
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_PD_EN_MASK,
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_RECV_MASK,
++ DC_GPIO_DDC3_MASK__AUX_PAD3_MODE_MASK,
++ DC_GPIO_DDC3_MASK__AUX3_POL_MASK,
++ DC_GPIO_DDC3_MASK__DC_GPIO_DDC3CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC3_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC4 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC4_MASK,
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC4_A,
++ DC_GPIO_DDC4_A__DC_GPIO_DDC4CLK_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC4_EN,
++ DC_GPIO_DDC4_EN__DC_GPIO_DDC4CLK_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC4_Y,
++ DC_GPIO_DDC4_Y__DC_GPIO_DDC4CLK_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_MASK_MASK,
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_PD_EN_MASK,
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_RECV_MASK,
++ DC_GPIO_DDC4_MASK__AUX_PAD4_MODE_MASK,
++ DC_GPIO_DDC4_MASK__AUX4_POL_MASK,
++ DC_GPIO_DDC4_MASK__DC_GPIO_DDC4CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC4_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC5 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC5_MASK,
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC5_A,
++ DC_GPIO_DDC5_A__DC_GPIO_DDC5CLK_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC5_EN,
++ DC_GPIO_DDC5_EN__DC_GPIO_DDC5CLK_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC5_Y,
++ DC_GPIO_DDC5_Y__DC_GPIO_DDC5CLK_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_MASK_MASK,
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_PD_EN_MASK,
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_RECV_MASK,
++ DC_GPIO_DDC5_MASK__AUX_PAD5_MODE_MASK,
++ DC_GPIO_DDC5_MASK__AUX5_POL_MASK,
++ DC_GPIO_DDC5_MASK__DC_GPIO_DDC5CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC5_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC6 */
++ {
++ {
++ {
++ mmDC_GPIO_DDC6_MASK,
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDC6_A,
++ DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK
++ },
++ {
++ mmDC_GPIO_DDC6_EN,
++ DC_GPIO_DDC6_EN__DC_GPIO_DDC6CLK_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDC6_Y,
++ DC_GPIO_DDC6_Y__DC_GPIO_DDC6CLK_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_MASK_MASK,
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_PD_EN_MASK,
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_RECV_MASK,
++ DC_GPIO_DDC6_MASK__AUX_PAD6_MODE_MASK,
++ DC_GPIO_DDC6_MASK__AUX6_POL_MASK,
++ DC_GPIO_DDC6_MASK__DC_GPIO_DDC6CLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDC6_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_DDC_VGA */
++ {
++ {
++ {
++ mmDC_GPIO_DDCVGA_MASK,
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_MASK_MASK
++ },
++ {
++ mmDC_GPIO_DDCVGA_A,
++ DC_GPIO_DDCVGA_A__DC_GPIO_DDCVGACLK_A_MASK
++ },
++ {
++ mmDC_GPIO_DDCVGA_EN,
++ DC_GPIO_DDCVGA_EN__DC_GPIO_DDCVGACLK_EN_MASK
++ },
++ {
++ mmDC_GPIO_DDCVGA_Y,
++ DC_GPIO_DDCVGA_Y__DC_GPIO_DDCVGACLK_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_MASK_MASK,
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGADATA_PD_EN_MASK,
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_RECV_MASK,
++ DC_GPIO_DDCVGA_MASK__AUX_PADVGA_MODE_MASK,
++ DC_GPIO_DDCVGA_MASK__AUXVGA_POL_MASK,
++ DC_GPIO_DDCVGA_MASK__DC_GPIO_DDCVGACLK_STR_MASK
++ },
++ {
++ mmDC_I2C_DDCVGA_SETUP
++ }
++ },
++ /* GPIO_DDC_LINE_I2CPAD */
++ {
++ {
++ {
++ mmDC_GPIO_I2CPAD_MASK,
++ DC_GPIO_I2CPAD_MASK__DC_GPIO_SCL_MASK_MASK
++ },
++ {
++ mmDC_GPIO_I2CPAD_A,
++ DC_GPIO_I2CPAD_A__DC_GPIO_SCL_A_MASK
++ },
++ {
++ mmDC_GPIO_I2CPAD_EN,
++ DC_GPIO_I2CPAD_EN__DC_GPIO_SCL_EN_MASK
++ },
++ {
++ mmDC_GPIO_I2CPAD_Y,
++ DC_GPIO_I2CPAD_Y__DC_GPIO_SCL_Y_MASK
++ }
++ },
++ {
++ DC_GPIO_I2CPAD_MASK__DC_GPIO_SCL_MASK_MASK,
++ DC_GPIO_I2CPAD_MASK__DC_GPIO_SCL_PD_DIS_MASK,
++ DC_GPIO_I2CPAD_MASK__DC_GPIO_SCL_RECV_MASK,
++ 0,
++ 0,
++ 0
++ },
++ {
++ 0
++ }
++ }
++};
++
++static void setup_i2c_polling(
++ struct dc_context *ctx,
++ const uint32_t addr,
++ bool enable_detect,
++ bool detect_mode)
++{
++ uint32_t value;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ enable_detect,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_ENABLE);
++
++ set_reg_field_value(
++ value,
++ enable_detect,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_EDID_DETECT_ENABLE);
++
++ if (enable_detect)
++ set_reg_field_value(
++ value,
++ detect_mode,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_EDID_DETECT_MODE);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static enum gpio_result set_config(
++ struct hw_gpio_pin *ptr,
++ const struct gpio_config_data *config_data)
++{
++ struct hw_ddc_dce110 *pin = DDC_DCE110_FROM_BASE(ptr);
++ struct hw_gpio *hw_gpio = NULL;
++ uint32_t addr;
++ uint32_t regval;
++ uint32_t ddc_data_pd_en = 0;
++ uint32_t ddc_clk_pd_en = 0;
++ uint32_t aux_pad_mode = 0;
++
++ hw_gpio = &pin->base.base;
++
++ if (hw_gpio == NULL) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_NULL_HANDLE;
++ }
++
++ /* switch dual mode GPIO to I2C/AUX mode */
++
++ addr = hw_gpio->pin_reg.DC_GPIO_DATA_MASK.addr;
++
++ regval = dal_read_reg(ptr->ctx, addr);
++
++ ddc_data_pd_en = get_reg_field_value(
++ regval,
++ DC_GPIO_DDC1_MASK,
++ DC_GPIO_DDC1DATA_PD_EN);
++
++ ddc_clk_pd_en = get_reg_field_value(
++ regval,
++ DC_GPIO_DDC1_MASK,
++ DC_GPIO_DDC1CLK_PD_EN);
++
++ aux_pad_mode = get_reg_field_value(
++ regval,
++ DC_GPIO_DDC1_MASK,
++ AUX_PAD1_MODE);
++
++ switch (config_data->config.ddc.type) {
++ case GPIO_DDC_CONFIG_TYPE_MODE_I2C:
++ /* On plug-in, there is a transient level on the pad
++ * which must be discharged through the internal pull-down.
++ * Enable internal pull-down, 2.5msec discharge time
++ * is required for detection of AUX mode */
++ if (hw_gpio->base.en != GPIO_DDC_LINE_VIP_PAD) {
++ if (!ddc_data_pd_en || !ddc_clk_pd_en) {
++ set_reg_field_value(
++ regval,
++ 1,
++ DC_GPIO_DDC1_MASK,
++ DC_GPIO_DDC1DATA_PD_EN);
++
++ set_reg_field_value(
++ regval,
++ 1,
++ DC_GPIO_DDC1_MASK,
++ DC_GPIO_DDC1CLK_PD_EN);
++
++ dal_write_reg(ptr->ctx, addr, regval);
++
++ if (config_data->type ==
++ GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
++ /* should not affect normal I2C R/W */
++ /* [anaumov] in DAL2, there was
++ * dc_service_delay_in_microseconds(2500); */
++ dc_service_sleep_in_milliseconds(ptr->ctx, 3);
++ }
++ } else {
++ uint32_t reg2 = regval;
++ uint32_t sda_pd_dis = 0;
++ uint32_t scl_pd_dis = 0;
++
++ sda_pd_dis = get_reg_field_value(
++ reg2,
++ DC_GPIO_I2CPAD_MASK,
++ DC_GPIO_SDA_PD_DIS);
++
++ scl_pd_dis = get_reg_field_value(
++ reg2,
++ DC_GPIO_I2CPAD_MASK,
++ DC_GPIO_SCL_PD_DIS);
++
++ if (sda_pd_dis) {
++ sda_pd_dis = 0;
++
++ dal_write_reg(ptr->ctx, addr, reg2);
++
++ if (config_data->type ==
++ GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
++ /* should not affect normal I2C R/W */
++ /* [anaumov] in DAL2, there was
++ * dc_service_delay_in_microseconds(2500); */
++ dc_service_sleep_in_milliseconds(ptr->ctx, 3);
++ }
++
++ if (!scl_pd_dis) {
++ scl_pd_dis = 1;
++
++ dal_write_reg(ptr->ctx, addr, reg2);
++
++ if (config_data->type ==
++ GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
++ /* should not affect normal I2C R/W */
++ /* [anaumov] in DAL2, there was
++ * dc_service_delay_in_microseconds(2500); */
++ dc_service_sleep_in_milliseconds(ptr->ctx, 3);
++ }
++ }
++
++ if (aux_pad_mode) {
++ /* let pins to get de-asserted
++ * before setting pad to I2C mode */
++ if (config_data->config.ddc.data_en_bit_present ||
++ config_data->config.ddc.clock_en_bit_present)
++ /* [anaumov] in DAL2, there was
++ * dc_service_delay_in_microseconds(2000); */
++ dc_service_sleep_in_milliseconds(ptr->ctx, 2);
++
++ /* set the I2C pad mode */
++ /* read the register again,
++ * some bits may have been changed */
++ regval = dal_read_reg(ptr->ctx, addr);
++
++ set_reg_field_value(
++ regval,
++ 0,
++ DC_GPIO_DDC1_MASK,
++ AUX_PAD1_MODE);
++
++ dal_write_reg(ptr->ctx, addr, regval);
++ }
++
++ return GPIO_RESULT_OK;
++ case GPIO_DDC_CONFIG_TYPE_MODE_AUX:
++ /* set the AUX pad mode */
++ if (!aux_pad_mode) {
++ set_reg_field_value(
++ regval,
++ 1,
++ DC_GPIO_DDC1_MASK,
++ AUX_PAD1_MODE);
++
++ dal_write_reg(ptr->ctx, addr, regval);
++ }
++
++ return GPIO_RESULT_OK;
++ case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT:
++ if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
++ (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
++ setup_i2c_polling(
++ ptr->ctx, ADDR_DDC_SETUP, 1, 0);
++ return GPIO_RESULT_OK;
++ }
++ break;
++ case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT:
++ if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
++ (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
++ setup_i2c_polling(
++ ptr->ctx, ADDR_DDC_SETUP, 1, 1);
++ return GPIO_RESULT_OK;
++ }
++ break;
++ case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING:
++ if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
++ (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
++ setup_i2c_polling(
++ ptr->ctx, ADDR_DDC_SETUP, 0, 0);
++ return GPIO_RESULT_OK;
++ }
++ break;
++ }
++
++ BREAK_TO_DEBUGGER();
++
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++}
++
++static const struct hw_gpio_pin_funcs funcs = {
++ .destroy = destroy,
++ .open = dal_hw_ddc_open,
++ .get_value = dal_hw_gpio_get_value,
++ .set_value = dal_hw_gpio_set_value,
++ .set_config = set_config,
++ .change_mode = dal_hw_gpio_change_mode,
++ .close = dal_hw_gpio_close,
++};
++
++
++static bool construct(
++ struct hw_ddc_dce110 *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx)
++{
++ const struct hw_ddc_dce110_init *init;
++
++ if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ if (!dal_hw_ddc_construct(&pin->base, id, en, ctx)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ pin->base.base.base.funcs = &funcs;
++
++ switch (id) {
++ case GPIO_ID_DDC_DATA:
++ init = hw_ddc_dce110_init_data + en;
++
++ pin->base.base.pin_reg = init->hw_gpio_data_reg;
++ pin->base.mask = init->hw_ddc_mask;
++ pin->addr = init->hw_ddc_dce110_addr;
++
++ return true;
++ case GPIO_ID_DDC_CLOCK:
++ init = hw_ddc_dce110_init_clock + en;
++
++ pin->base.base.pin_reg = init->hw_gpio_data_reg;
++ pin->base.mask = init->hw_ddc_mask;
++ pin->addr = init->hw_ddc_dce110_addr;
++
++ return true;
++ default:
++ ASSERT_CRITICAL(false);
++ }
++
++ return false;
++}
++
++struct hw_gpio_pin *dal_hw_ddc_dce110_create(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en)
++{
++ struct hw_ddc_dce110 *pin = dc_service_alloc(ctx, sizeof(struct hw_ddc_dce110));
++
++ if (!pin) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (construct(pin, id, en, ctx))
++ return &pin->base.base.base;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(ctx, pin);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.h
+new file mode 100644
+index 0000000..6830369
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_ddc_dce110.h
+@@ -0,0 +1,46 @@
++/*
++ * 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_HW_DDC_DCE110_H__
++#define __DAL_HW_DDC_DCE110_H__
++
++struct hw_ddc_dce110_addr {
++ uint32_t dc_i2c_ddc_setup;
++};
++
++struct hw_ddc_dce110 {
++ struct hw_ddc base;
++ struct hw_ddc_dce110_addr addr;
++};
++
++#define DDC_DCE110_FROM_BASE(ddc_base) \
++ container_of((HW_DDC_FROM_BASE(ddc_base)), struct hw_ddc_dce110, base)
++
++struct hw_gpio_pin *dal_hw_ddc_dce110_create(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.c
+new file mode 100644
+index 0000000..85644c5
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.c
+@@ -0,0 +1,84 @@
++/*
++ * Copyright 2013-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
++ *
++ */
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "dal_services.h"
++#include "include/gpio_types.h"
++#include "../hw_factory.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "../hw_gpio_pin.h"
++#include "../hw_gpio.h"
++#include "../hw_ddc.h"
++#include "../hw_hpd.h"
++
++#include "hw_factory_dce110.h"
++#include "hw_hpd_dce110.h"
++#include "hw_ddc_dce110.h"
++
++/* fucntion table */
++static const struct hw_factory_funcs funcs = {
++ .create_dvo = NULL,
++ .create_ddc_data = dal_hw_ddc_dce110_create,
++ .create_ddc_clock = dal_hw_ddc_dce110_create,
++ .create_generic = NULL,
++ .create_hpd = dal_hw_hpd_dce110_create,
++ .create_gpio_pad = NULL,
++ .create_sync = NULL,
++ .create_gsl = NULL,
++};
++
++/*
++ * dal_hw_factory_dce110_init
++ *
++ * @brief
++ * Initialize HW factory function pointers and pin info
++ *
++ * @param
++ * struct hw_factory *factory - [out] struct of function pointers
++ */
++void dal_hw_factory_dce110_init(struct hw_factory *factory)
++{
++ /*TODO check ASIC CAPs*/
++ factory->number_of_pins[GPIO_ID_DVO1] = 24;
++ factory->number_of_pins[GPIO_ID_DVO12] = 2;
++ factory->number_of_pins[GPIO_ID_DVO24] = 1;
++ factory->number_of_pins[GPIO_ID_DDC_DATA] = 8;
++ factory->number_of_pins[GPIO_ID_DDC_CLOCK] = 8;
++ factory->number_of_pins[GPIO_ID_GENERIC] = 7;
++ factory->number_of_pins[GPIO_ID_HPD] = 6;
++ factory->number_of_pins[GPIO_ID_GPIO_PAD] = 31;
++ factory->number_of_pins[GPIO_ID_VIP_PAD] = 0;
++ factory->number_of_pins[GPIO_ID_SYNC] = 2;
++ factory->number_of_pins[GPIO_ID_GSL] = 4;
++
++ factory->funcs = &funcs;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.h
+new file mode 100644
+index 0000000..ecf06ed
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_factory_dce110.h
+@@ -0,0 +1,32 @@
++/*
++ * Copyright 2013-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_HW_FACTORY_DCE110_H__
++#define __DAL_HW_FACTORY_DCE110_H__
++
++/* Initialize HW factory function pointers and pin info */
++void dal_hw_factory_dce110_init(struct hw_factory *factory);
++
++#endif /* __DAL_HW_FACTORY_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.c
+new file mode 100644
+index 0000000..34405e9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.c
+@@ -0,0 +1,367 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++#include "../hw_gpio_pin.h"
++#include "../hw_gpio.h"
++#include "../hw_hpd.h"
++
++/*
++ * Header of this unit
++ */
++#include "hw_hpd_dce110.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++/*
++ * This unit
++ */
++
++static void destruct(
++ struct hw_hpd_dce110 *pin)
++{
++ dal_hw_hpd_destruct(&pin->base);
++}
++
++static void destroy(
++ struct hw_gpio_pin **ptr)
++{
++ struct hw_hpd_dce110 *pin = HPD_DCE110_FROM_BASE(*ptr);
++
++ destruct(pin);
++
++ dc_service_free((*ptr)->ctx, pin);
++
++ *ptr = NULL;
++}
++
++struct hw_gpio_generic_dce110_init {
++ struct hw_gpio_pin_reg hw_gpio_data_reg;
++ struct hw_hpd_dce110_addr addr;
++};
++
++static const struct hw_gpio_generic_dce110_init
++ hw_gpio_generic_dce110_init[GPIO_HPD_COUNT] = {
++ /* GPIO_HPD_1 */
++ {
++ {
++ {
++ mmDC_GPIO_HPD_MASK,
++ DC_GPIO_HPD_MASK__DC_GPIO_HPD1_MASK_MASK
++ },
++ {
++ mmDC_GPIO_HPD_A,
++ DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK
++ },
++ {
++ mmDC_GPIO_HPD_EN,
++ DC_GPIO_HPD_EN__DC_GPIO_HPD1_EN_MASK
++ },
++ {
++ mmDC_GPIO_HPD_Y,
++ DC_GPIO_HPD_Y__DC_GPIO_HPD1_Y_MASK
++ }
++ },
++ {
++ mmHPD0_DC_HPD_INT_STATUS,
++ mmHPD0_DC_HPD_TOGGLE_FILT_CNTL
++ }
++ },
++ /* GPIO_HPD_2 */
++ {
++ {
++ {
++ mmDC_GPIO_HPD_MASK,
++ DC_GPIO_HPD_MASK__DC_GPIO_HPD2_MASK_MASK
++ },
++ {
++ mmDC_GPIO_HPD_A,
++ DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK
++ },
++ {
++ mmDC_GPIO_HPD_EN,
++ DC_GPIO_HPD_EN__DC_GPIO_HPD2_EN_MASK
++ },
++ {
++ mmDC_GPIO_HPD_Y,
++ DC_GPIO_HPD_Y__DC_GPIO_HPD2_Y_MASK
++ }
++ },
++ {
++ mmHPD1_DC_HPD_INT_STATUS,
++ mmHPD1_DC_HPD_TOGGLE_FILT_CNTL
++ }
++ },
++ /* GPIO_HPD_3 */
++ {
++ {
++ {
++ mmDC_GPIO_HPD_MASK,
++ DC_GPIO_HPD_MASK__DC_GPIO_HPD3_MASK_MASK
++ },
++ {
++ mmDC_GPIO_HPD_A,
++ DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK
++ },
++ {
++ mmDC_GPIO_HPD_EN,
++ DC_GPIO_HPD_EN__DC_GPIO_HPD3_EN_MASK
++ },
++ {
++ mmDC_GPIO_HPD_Y,
++ DC_GPIO_HPD_Y__DC_GPIO_HPD3_Y_MASK
++ }
++ },
++ {
++ mmHPD2_DC_HPD_INT_STATUS,
++ mmHPD2_DC_HPD_TOGGLE_FILT_CNTL
++ }
++ },
++ /* GPIO_HPD_4 */
++ {
++ {
++ {
++ mmDC_GPIO_HPD_MASK,
++ DC_GPIO_HPD_MASK__DC_GPIO_HPD4_MASK_MASK
++ },
++ {
++ mmDC_GPIO_HPD_A,
++ DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK
++ },
++ {
++ mmDC_GPIO_HPD_EN,
++ DC_GPIO_HPD_EN__DC_GPIO_HPD4_EN_MASK
++ },
++ {
++ mmDC_GPIO_HPD_Y,
++ DC_GPIO_HPD_Y__DC_GPIO_HPD4_Y_MASK
++ }
++ },
++ {
++ mmHPD3_DC_HPD_INT_STATUS,
++ mmHPD3_DC_HPD_TOGGLE_FILT_CNTL
++ }
++ },
++ /* GPIO_HPD_5 */
++ {
++ {
++ {
++ mmDC_GPIO_HPD_MASK,
++ DC_GPIO_HPD_MASK__DC_GPIO_HPD5_MASK_MASK
++ },
++ {
++ mmDC_GPIO_HPD_A,
++ DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK
++ },
++ {
++ mmDC_GPIO_HPD_EN,
++ DC_GPIO_HPD_EN__DC_GPIO_HPD5_EN_MASK
++ },
++ {
++ mmDC_GPIO_HPD_Y,
++ DC_GPIO_HPD_Y__DC_GPIO_HPD5_Y_MASK
++ }
++ },
++ {
++ mmHPD4_DC_HPD_INT_STATUS,
++ mmHPD4_DC_HPD_TOGGLE_FILT_CNTL
++ }
++ },
++ /* GPIO_HPD_6 */
++ {
++ {
++ {
++ mmDC_GPIO_HPD_MASK,
++ DC_GPIO_HPD_MASK__DC_GPIO_HPD6_MASK_MASK
++ },
++ {
++ mmDC_GPIO_HPD_A,
++ DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK
++ },
++ {
++ mmDC_GPIO_HPD_EN,
++ DC_GPIO_HPD_EN__DC_GPIO_HPD6_EN_MASK
++ },
++ {
++ mmDC_GPIO_HPD_Y,
++ DC_GPIO_HPD_Y__DC_GPIO_HPD6_Y_MASK
++ }
++ },
++ {
++ mmHPD5_DC_HPD_INT_STATUS,
++ mmHPD5_DC_HPD_TOGGLE_FILT_CNTL
++ }
++ }
++};
++
++static enum gpio_result get_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t *value)
++{
++ struct hw_hpd_dce110 *pin = HPD_DCE110_FROM_BASE(ptr);
++
++ /* in Interrupt mode we ask for SENSE bit */
++
++ if (ptr->mode == GPIO_MODE_INTERRUPT) {
++ uint32_t regval;
++ uint32_t hpd_delayed = 0;
++ uint32_t hpd_sense = 0;
++
++ regval = dal_read_reg(
++ ptr->ctx,
++ pin->addr.DC_HPD_INT_STATUS);
++
++ hpd_delayed = get_reg_field_value(
++ regval,
++ DC_HPD_INT_STATUS,
++ DC_HPD_SENSE_DELAYED);
++
++ hpd_sense = get_reg_field_value(
++ regval,
++ DC_HPD_INT_STATUS,
++ DC_HPD_SENSE);
++
++ *value = hpd_delayed;
++ return GPIO_RESULT_OK;
++ }
++
++ /* in any other modes, operate as normal GPIO */
++
++ return dal_hw_gpio_get_value(ptr, value);
++}
++
++static enum gpio_result set_config(
++ struct hw_gpio_pin *ptr,
++ const struct gpio_config_data *config_data)
++{
++ struct hw_hpd_dce110 *pin = HPD_DCE110_FROM_BASE(ptr);
++
++ if (!config_data)
++ return GPIO_RESULT_INVALID_DATA;
++
++ {
++ uint32_t value;
++
++ value = dal_read_reg(
++ ptr->ctx,
++ pin->addr.DC_HPD_TOGGLE_FILT_CNTL);
++
++ set_reg_field_value(
++ value,
++ config_data->config.hpd.delay_on_connect / 10,
++ DC_HPD_TOGGLE_FILT_CNTL,
++ DC_HPD_CONNECT_INT_DELAY);
++
++ set_reg_field_value(
++ value,
++ config_data->config.hpd.delay_on_disconnect / 10,
++ DC_HPD_TOGGLE_FILT_CNTL,
++ DC_HPD_DISCONNECT_INT_DELAY);
++
++ dal_write_reg(
++ ptr->ctx,
++ pin->addr.DC_HPD_TOGGLE_FILT_CNTL,
++ value);
++
++ }
++
++ return GPIO_RESULT_OK;
++}
++
++static const struct hw_gpio_pin_funcs funcs = {
++ .destroy = destroy,
++ .open = dal_hw_gpio_open,
++ .get_value = get_value,
++ .set_value = dal_hw_gpio_set_value,
++ .set_config = set_config,
++ .change_mode = dal_hw_gpio_change_mode,
++ .close = dal_hw_gpio_close,
++};
++
++static bool construct(
++ struct hw_hpd_dce110 *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx)
++{
++ const struct hw_gpio_generic_dce110_init *init;
++
++ if (id != GPIO_ID_HPD) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ if ((en < GPIO_HPD_MIN) || (en > GPIO_HPD_MAX)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ if (!dal_hw_hpd_construct(&pin->base, id, en, ctx)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ pin->base.base.base.funcs = &funcs;
++
++ init = hw_gpio_generic_dce110_init + en;
++
++ pin->base.base.pin_reg = init->hw_gpio_data_reg;
++
++ pin->addr = init->addr;
++
++ return true;
++}
++
++struct hw_gpio_pin *dal_hw_hpd_dce110_create(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en)
++{
++ struct hw_hpd_dce110 *pin = dc_service_alloc(ctx, sizeof(struct hw_hpd_dce110));
++
++ if (!pin) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (construct(pin, id, en, ctx))
++ return &pin->base.base.base;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(ctx, pin);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.h
+new file mode 100644
+index 0000000..d032f4b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_hpd_dce110.h
+@@ -0,0 +1,47 @@
++/*
++ * 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_HW_HPD_DCE110_H__
++#define __DAL_HW_HPD_DCE110_H__
++
++struct hw_hpd_dce110_addr {
++ uint32_t DC_HPD_INT_STATUS;
++ uint32_t DC_HPD_TOGGLE_FILT_CNTL;
++};
++
++struct hw_hpd_dce110 {
++ struct hw_hpd base;
++ struct hw_hpd_dce110_addr addr;
++};
++
++#define HPD_DCE110_FROM_BASE(hpd_base) \
++ container_of((HW_HPD_FROM_BASE(hpd_base)), struct hw_hpd_dce110, base)
++
++struct hw_gpio_pin *dal_hw_hpd_dce110_create(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++
++#endif /*__DAL_HW_HPD_DCE110_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_translate_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_translate_dce110.c
+new file mode 100644
+index 0000000..05ac0b2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_translate_dce110.c
+@@ -0,0 +1,440 @@
++/*
++ * Copyright 2013-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
++ *
++ */
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "dal_services.h"
++#include "include/gpio_types.h"
++#include "../hw_translate.h"
++
++/*
++ * Header of this unit
++ */
++#include "hw_translate_dce110.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++#include "../hw_gpio_pin.h"
++#include "../hw_dvo.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++static bool offset_to_id(
++ uint32_t offset,
++ uint32_t mask,
++ enum gpio_id *id,
++ uint32_t *en)
++{
++ switch (offset) {
++ /* DVO */
++ case mmDC_GPIO_DVODATA_A:
++ switch (mask) {
++ case BUNDLE_A_MASK:
++ *id = GPIO_ID_DVO12;
++ *en = GPIO_DVO12_A;
++ return true;
++ case BUNDLE_B_MASK:
++ *id = GPIO_ID_DVO12;
++ *en = GPIO_DVO12_B;
++ return true;
++ case DC_GPIO_DVODATA_A__DC_GPIO_DVODATA_A_MASK:
++ *id = GPIO_ID_DVO24;
++ *en = 0;
++ return true;
++ default:
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++ break;
++ /* GENERIC */
++ case mmDC_GPIO_GENERIC_A:
++ *id = GPIO_ID_GENERIC;
++ switch (mask) {
++ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK:
++ *en = GPIO_GENERIC_A;
++ return true;
++ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK:
++ *en = GPIO_GENERIC_B;
++ return true;
++ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK:
++ *en = GPIO_GENERIC_C;
++ return true;
++ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK:
++ *en = GPIO_GENERIC_D;
++ return true;
++ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK:
++ *en = GPIO_GENERIC_E;
++ return true;
++ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK:
++ *en = GPIO_GENERIC_F;
++ return true;
++ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK:
++ *en = GPIO_GENERIC_G;
++ return true;
++ default:
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++ break;
++ /* HPD */
++ case mmDC_GPIO_HPD_A:
++ *id = GPIO_ID_HPD;
++ switch (mask) {
++ case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK:
++ *en = GPIO_HPD_1;
++ return true;
++ case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK:
++ *en = GPIO_HPD_2;
++ return true;
++ case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK:
++ *en = GPIO_HPD_3;
++ return true;
++ case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK:
++ *en = GPIO_HPD_4;
++ return true;
++ case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK:
++ *en = GPIO_HPD_5;
++ return true;
++ case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK:
++ *en = GPIO_HPD_6;
++ return true;
++ default:
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++ break;
++ /* SYNCA */
++ case mmDC_GPIO_SYNCA_A:
++ *id = GPIO_ID_SYNC;
++ switch (mask) {
++ case DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK:
++ *en = GPIO_SYNC_HSYNC_A;
++ return true;
++ case DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK:
++ *en = GPIO_SYNC_VSYNC_A;
++ return true;
++ default:
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++ break;
++ /* mmDC_GPIO_GENLK_MASK */
++ case mmDC_GPIO_GENLK_A:
++ *id = GPIO_ID_GSL;
++ switch (mask) {
++ case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK:
++ *en = GPIO_GSL_GENLOCK_CLOCK;
++ return true;
++ case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK:
++ *en = GPIO_GSL_GENLOCK_VSYNC;
++ return true;
++ case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK:
++ *en = GPIO_GSL_SWAPLOCK_A;
++ return true;
++ case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK:
++ *en = GPIO_GSL_SWAPLOCK_B;
++ return true;
++ default:
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++ break;
++ /* DDC */
++ /* we don't care about the GPIO_ID for DDC
++ * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK
++ * directly in the create method */
++ case mmDC_GPIO_DDC1_A:
++ *en = GPIO_DDC_LINE_DDC1;
++ return true;
++ case mmDC_GPIO_DDC2_A:
++ *en = GPIO_DDC_LINE_DDC2;
++ return true;
++ case mmDC_GPIO_DDC3_A:
++ *en = GPIO_DDC_LINE_DDC3;
++ return true;
++ case mmDC_GPIO_DDC4_A:
++ *en = GPIO_DDC_LINE_DDC4;
++ return true;
++ case mmDC_GPIO_DDC5_A:
++ *en = GPIO_DDC_LINE_DDC5;
++ return true;
++ case mmDC_GPIO_DDC6_A:
++ *en = GPIO_DDC_LINE_DDC6;
++ return true;
++ case mmDC_GPIO_DDCVGA_A:
++ *en = GPIO_DDC_LINE_DDC_VGA;
++ return true;
++ /* GPIO_I2CPAD */
++ case mmDC_GPIO_I2CPAD_A:
++ *en = GPIO_DDC_LINE_I2C_PAD;
++ return true;
++ /* Not implemented */
++ case mmDC_GPIO_PWRSEQ_A:
++ case mmDC_GPIO_PAD_STRENGTH_1:
++ case mmDC_GPIO_PAD_STRENGTH_2:
++ case mmDC_GPIO_DEBUG:
++ return false;
++ /* UNEXPECTED */
++ default:
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++}
++
++static bool id_to_offset(
++ enum gpio_id id,
++ uint32_t en,
++ struct gpio_pin_info *info)
++{
++ bool result = true;
++
++ switch (id) {
++ case GPIO_ID_DVO12:
++ info->offset = mmDC_GPIO_DVODATA_A;
++ switch (en) {
++ case GPIO_DVO12_A:
++ info->mask = BUNDLE_A_MASK;
++ break;
++ case GPIO_DVO12_B:
++ info->mask = BUNDLE_B_MASK;
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ result = false;
++ }
++ break;
++ case GPIO_ID_DDC_DATA:
++ info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6DATA_A_MASK;
++ switch (en) {
++ case GPIO_DDC_LINE_DDC1:
++ info->offset = mmDC_GPIO_DDC1_A;
++ break;
++ case GPIO_DDC_LINE_DDC2:
++ info->offset = mmDC_GPIO_DDC2_A;
++ break;
++ case GPIO_DDC_LINE_DDC3:
++ info->offset = mmDC_GPIO_DDC3_A;
++ break;
++ case GPIO_DDC_LINE_DDC4:
++ info->offset = mmDC_GPIO_DDC4_A;
++ break;
++ case GPIO_DDC_LINE_DDC5:
++ info->offset = mmDC_GPIO_DDC5_A;
++ break;
++ case GPIO_DDC_LINE_DDC6:
++ info->offset = mmDC_GPIO_DDC6_A;
++ break;
++ case GPIO_DDC_LINE_DDC_VGA:
++ info->offset = mmDC_GPIO_DDCVGA_A;
++ break;
++ case GPIO_DDC_LINE_I2C_PAD:
++ info->offset = mmDC_GPIO_I2CPAD_A;
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ result = false;
++ }
++ break;
++ case GPIO_ID_DDC_CLOCK:
++ info->mask = DC_GPIO_DDC6_A__DC_GPIO_DDC6CLK_A_MASK;
++ switch (en) {
++ case GPIO_DDC_LINE_DDC1:
++ info->offset = mmDC_GPIO_DDC1_A;
++ break;
++ case GPIO_DDC_LINE_DDC2:
++ info->offset = mmDC_GPIO_DDC2_A;
++ break;
++ case GPIO_DDC_LINE_DDC3:
++ info->offset = mmDC_GPIO_DDC3_A;
++ break;
++ case GPIO_DDC_LINE_DDC4:
++ info->offset = mmDC_GPIO_DDC4_A;
++ break;
++ case GPIO_DDC_LINE_DDC5:
++ info->offset = mmDC_GPIO_DDC5_A;
++ break;
++ case GPIO_DDC_LINE_DDC6:
++ info->offset = mmDC_GPIO_DDC6_A;
++ break;
++ case GPIO_DDC_LINE_DDC_VGA:
++ info->offset = mmDC_GPIO_DDCVGA_A;
++ break;
++ case GPIO_DDC_LINE_I2C_PAD:
++ info->offset = mmDC_GPIO_I2CPAD_A;
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ result = false;
++ }
++ break;
++ case GPIO_ID_GENERIC:
++ info->offset = mmDC_GPIO_GENERIC_A;
++ switch (en) {
++ case GPIO_GENERIC_A:
++ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK;
++ break;
++ case GPIO_GENERIC_B:
++ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK;
++ break;
++ case GPIO_GENERIC_C:
++ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK;
++ break;
++ case GPIO_GENERIC_D:
++ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK;
++ break;
++ case GPIO_GENERIC_E:
++ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK;
++ break;
++ case GPIO_GENERIC_F:
++ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK;
++ break;
++ case GPIO_GENERIC_G:
++ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK;
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ result = false;
++ }
++ break;
++ case GPIO_ID_HPD:
++ info->offset = mmDC_GPIO_HPD_A;
++ switch (en) {
++ case GPIO_HPD_1:
++ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK;
++ break;
++ case GPIO_HPD_2:
++ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK;
++ break;
++ case GPIO_HPD_3:
++ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK;
++ break;
++ case GPIO_HPD_4:
++ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK;
++ break;
++ case GPIO_HPD_5:
++ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK;
++ break;
++ case GPIO_HPD_6:
++ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK;
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ result = false;
++ }
++ break;
++ case GPIO_ID_SYNC:
++ switch (en) {
++ case GPIO_SYNC_HSYNC_A:
++ info->offset = mmDC_GPIO_SYNCA_A;
++ info->mask = DC_GPIO_SYNCA_A__DC_GPIO_HSYNCA_A_MASK;
++ break;
++ case GPIO_SYNC_VSYNC_A:
++ info->offset = mmDC_GPIO_SYNCA_A;
++ info->mask = DC_GPIO_SYNCA_A__DC_GPIO_VSYNCA_A_MASK;
++ break;
++ case GPIO_SYNC_HSYNC_B:
++ case GPIO_SYNC_VSYNC_B:
++ default:
++ ASSERT_CRITICAL(false);
++ result = false;
++ }
++ break;
++ case GPIO_ID_GSL:
++ switch (en) {
++ case GPIO_GSL_GENLOCK_CLOCK:
++ info->offset = mmDC_GPIO_GENLK_A;
++ info->mask = DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK;
++ break;
++ case GPIO_GSL_GENLOCK_VSYNC:
++ info->offset = mmDC_GPIO_GENLK_A;
++ info->mask =
++ DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK;
++ break;
++ case GPIO_GSL_SWAPLOCK_A:
++ info->offset = mmDC_GPIO_GENLK_A;
++ info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK;
++ break;
++ case GPIO_GSL_SWAPLOCK_B:
++ info->offset = mmDC_GPIO_GENLK_A;
++ info->mask = DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK;
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ result = false;
++ }
++ break;
++ case GPIO_ID_DVO24:
++ info->offset = mmDC_GPIO_DVODATA_A;
++ info->mask = DC_GPIO_DVODATA_A__DC_GPIO_DVODATA_A_MASK;
++ break;
++ case GPIO_ID_DVO1:
++ case GPIO_ID_VIP_PAD:
++ default:
++ ASSERT_CRITICAL(false);
++ result = false;
++ }
++
++ if (result) {
++ info->offset_y = info->offset + 2;
++ info->offset_en = info->offset + 1;
++ info->offset_mask = info->offset - 1;
++
++ info->mask_y = info->mask;
++ info->mask_en = info->mask;
++ info->mask_mask = info->mask;
++ }
++
++ return result;
++}
++
++/* function table */
++static const struct hw_translate_funcs funcs = {
++ .offset_to_id = offset_to_id,
++ .id_to_offset = id_to_offset,
++};
++
++/*
++ * dal_hw_translate_dce110_init
++ *
++ * @brief
++ * Initialize Hw translate function pointers.
++ *
++ * @param
++ * struct hw_translate *tr - [out] struct of function pointers
++ *
++ */
++void dal_hw_translate_dce110_init(struct hw_translate *tr)
++{
++ tr->funcs = &funcs;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_translate_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_translate_dce110.h
+new file mode 100644
+index 0000000..4d16e09
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dce110/hw_translate_dce110.h
+@@ -0,0 +1,34 @@
++/*
++ * Copyright 2013-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_HW_TRANSLATE_DCE110_H__
++#define __DAL_HW_TRANSLATE_DCE110_H__
++
++struct hw_translate;
++
++/* Initialize Hw translate function pointers */
++void dal_hw_translate_dce110_init(struct hw_translate *tr);
++
++#endif /* __DAL_HW_TRANSLATE_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/ddc.c b/drivers/gpu/drm/amd/dal/dc/gpio/ddc.c
+new file mode 100644
+index 0000000..548b1cf
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/ddc.c
+@@ -0,0 +1,290 @@
++/*
++ * 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
++ *
++ */
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "dal_services.h"
++
++#include "include/gpio_interface.h"
++#include "include/ddc_interface.h"
++#include "include/gpio_service_interface.h"
++#include "hw_gpio_pin.h"
++#include "hw_translate.h"
++#include "hw_factory.h"
++#include "gpio_service.h"
++#include "gpio.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "ddc.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++enum gpio_result dal_ddc_open(
++ struct ddc *ddc,
++ enum gpio_mode mode,
++ enum gpio_ddc_config_type config_type)
++{
++ enum gpio_result result;
++
++ struct gpio_ddc_open_options data_options;
++ struct gpio_ddc_open_options clock_options;
++ struct gpio_config_data config_data;
++
++ result = dal_gpio_open_ex(ddc->pin_data, mode, &data_options);
++
++ if (result != GPIO_RESULT_OK) {
++ BREAK_TO_DEBUGGER();
++ return result;
++ }
++
++ result = dal_gpio_open_ex(ddc->pin_clock, mode, &clock_options);
++
++ if (result != GPIO_RESULT_OK) {
++ BREAK_TO_DEBUGGER();
++ goto failure;
++ }
++
++ /* DDC clock and data pins should belong
++ * to the same DDC block id,
++ * we use the data pin to set the pad mode. */
++
++ if (mode == GPIO_MODE_INPUT)
++ /* this is from detect_sink_type,
++ * we need extra delay there */
++ config_data.type = GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE;
++ else
++ config_data.type = GPIO_CONFIG_TYPE_DDC;
++
++ config_data.config.ddc.type = config_type;
++ config_data.config.ddc.data_en_bit_present =
++ data_options.en_bit_present;
++ config_data.config.ddc.clock_en_bit_present =
++ clock_options.en_bit_present;
++
++ result = dal_gpio_set_config(ddc->pin_data, &config_data);
++
++ if (result == GPIO_RESULT_OK)
++ return result;
++
++ BREAK_TO_DEBUGGER();
++
++ dal_gpio_close(ddc->pin_clock);
++
++failure:
++ dal_gpio_close(ddc->pin_data);
++
++ return result;
++}
++
++enum gpio_result dal_ddc_get_clock(
++ const struct ddc *ddc,
++ uint32_t *value)
++{
++ return dal_gpio_get_value(ddc->pin_clock, value);
++}
++
++enum gpio_result dal_ddc_set_clock(
++ const struct ddc *ddc,
++ uint32_t value)
++{
++ return dal_gpio_set_value(ddc->pin_clock, value);
++}
++
++enum gpio_result dal_ddc_get_data(
++ const struct ddc *ddc,
++ uint32_t *value)
++{
++ return dal_gpio_get_value(ddc->pin_data, value);
++}
++
++enum gpio_result dal_ddc_set_data(
++ const struct ddc *ddc,
++ uint32_t value)
++{
++ return dal_gpio_set_value(ddc->pin_data, value);
++}
++
++enum gpio_result dal_ddc_change_mode(
++ struct ddc *ddc,
++ enum gpio_mode mode)
++{
++ enum gpio_result result;
++
++ enum gpio_mode original_mode =
++ dal_gpio_get_mode(ddc->pin_data);
++
++ result = dal_gpio_change_mode(ddc->pin_data, mode);
++
++ /* [anaumov] DAL2 code returns GPIO_RESULT_NON_SPECIFIC_ERROR
++ * in case of failures;
++ * set_mode() is so that, in case of failure,
++ * we must explicitly set original mode */
++
++ if (result != GPIO_RESULT_OK)
++ goto failure;
++
++ result = dal_gpio_change_mode(ddc->pin_clock, mode);
++
++ if (result == GPIO_RESULT_OK)
++ return result;
++
++ dal_gpio_change_mode(ddc->pin_clock, original_mode);
++
++failure:
++ dal_gpio_change_mode(ddc->pin_data, original_mode);
++
++ return result;
++}
++
++bool dal_ddc_is_hw_supported(
++ const struct ddc *ddc)
++{
++ return ddc->hw_info.hw_supported;
++}
++
++enum gpio_ddc_line dal_ddc_get_line(
++ const struct ddc *ddc)
++{
++ return (enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data);
++}
++
++bool dal_ddc_check_line_aborted(
++ const struct ddc *self)
++{
++ /* No arbitration with VBIOS is performed since DCE 6.0 */
++
++ return false;
++}
++
++enum gpio_result dal_ddc_set_config(
++ struct ddc *ddc,
++ enum gpio_ddc_config_type config_type)
++{
++ struct gpio_config_data config_data;
++
++ config_data.type = GPIO_CONFIG_TYPE_DDC;
++
++ config_data.config.ddc.type = config_type;
++ config_data.config.ddc.data_en_bit_present = false;
++ config_data.config.ddc.clock_en_bit_present = false;
++
++ return dal_gpio_set_config(ddc->pin_data, &config_data);
++}
++
++void dal_ddc_close(
++ struct ddc *ddc)
++{
++ dal_gpio_close(ddc->pin_clock);
++ dal_gpio_close(ddc->pin_data);
++}
++
++/*
++ * @brief
++ * Creation and destruction
++ */
++
++struct ddc *dal_gpio_create_ddc(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask,
++ struct gpio_ddc_hw_info *info)
++{
++ enum gpio_id id;
++ uint32_t en;
++ struct ddc *ddc;
++
++ if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en))
++ return NULL;
++
++ ddc = dc_service_alloc(service->ctx, sizeof(struct ddc));
++
++ if (!ddc) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ ddc->pin_data = dal_gpio_service_create_gpio_ex(
++ service, GPIO_ID_DDC_DATA, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
++
++ if (!ddc->pin_data) {
++ BREAK_TO_DEBUGGER();
++ goto failure_1;
++ }
++
++ ddc->pin_clock = dal_gpio_service_create_gpio_ex(
++ service, GPIO_ID_DDC_CLOCK, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
++
++ if (!ddc->pin_clock) {
++ BREAK_TO_DEBUGGER();
++ goto failure_2;
++ }
++
++ ddc->hw_info = *info;
++
++ ddc->ctx = service->ctx;
++
++ return ddc;
++
++failure_2:
++ dal_gpio_service_destroy_gpio(&ddc->pin_data);
++
++failure_1:
++ dc_service_free(service->ctx, ddc);
++
++ return NULL;
++}
++
++static void destruct(struct ddc *ddc)
++{
++ dal_ddc_close(ddc);
++ dal_gpio_service_destroy_gpio(&ddc->pin_data);
++ dal_gpio_service_destroy_gpio(&ddc->pin_clock);
++
++}
++
++void dal_gpio_destroy_ddc(
++ struct ddc **ddc)
++{
++ if (!ddc || !*ddc) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ destruct(*ddc);
++ dc_service_free((*ddc)->ctx, *ddc);
++
++ *ddc = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/ddc.h b/drivers/gpu/drm/amd/dal/dc/gpio/ddc.h
+new file mode 100644
+index 0000000..2631571
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/ddc.h
+@@ -0,0 +1,45 @@
++/*
++ * 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_DDC_H__
++#define __DAL_DDC_H__
++
++struct ddc {
++ struct gpio *pin_data;
++ struct gpio *pin_clock;
++ struct gpio_ddc_hw_info hw_info;
++ struct dc_context *ctx;
++};
++
++struct ddc *dal_gpio_create_ddc(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask,
++ struct gpio_ddc_hw_info *info);
++
++void dal_gpio_destroy_ddc(
++ struct ddc **ddc);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dvo.c b/drivers/gpu/drm/amd/dal/dc/gpio/dvo.c
+new file mode 100644
+index 0000000..a237d25
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dvo.c
+@@ -0,0 +1,138 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_interface.h"
++#include "include/dvo_interface.h"
++#include "include/gpio_service_interface.h"
++#include "hw_gpio_pin.h"
++#include "hw_translate.h"
++#include "hw_factory.h"
++#include "gpio_service.h"
++#include "gpio.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "dvo.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++enum gpio_result dal_dvo_open(
++ struct dvo *dvo,
++ enum gpio_mode mode)
++{
++ return dal_gpio_open(dvo->pin, mode);
++}
++
++enum gpio_result dal_dvo_get_value(
++ const struct dvo *dvo,
++ uint32_t *value)
++{
++ return dal_gpio_get_value(dvo->pin, value);
++}
++
++enum gpio_result dal_dvo_set_value(
++ const struct dvo *dvo,
++ uint32_t value)
++{
++ return dal_gpio_set_value(dvo->pin, value);
++}
++
++void dal_dvo_close(
++ struct dvo *dvo)
++{
++ dal_gpio_close(dvo->pin);
++}
++
++/*
++ * @brief
++ * Creation and destruction
++ */
++
++struct dvo *dal_dvo_create(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en)
++{
++ struct dvo *dvo;
++
++ switch (id) {
++ case GPIO_ID_DVO12:
++ if ((en < GPIO_DVO12_MIN) || (en > GPIO_DVO12_MAX)) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++ break;
++ case GPIO_ID_DVO24:
++ if ((en < GPIO_DVO24_MIN) || (en > GPIO_DVO24_MAX)) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++ break;
++ default:
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ dvo = dc_service_alloc(service->ctx, sizeof(struct dvo));
++
++ if (!dvo) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ dvo->pin = NULL;
++ dvo->ctx = service->ctx;
++
++ return dvo;
++}
++
++void dal_dvo_destroy(
++ struct dvo **dvo)
++{
++ if (!dvo || !*dvo) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ dal_dvo_close(*dvo);
++
++ dc_service_free((*dvo)->ctx, *dvo);
++
++ *dvo = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/dvo.h b/drivers/gpu/drm/amd/dal/dc/gpio/dvo.h
+new file mode 100644
+index 0000000..0d98b51
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/dvo.h
+@@ -0,0 +1,42 @@
++/*
++ * 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_DVO_H__
++#define __DAL_DVO_H__
++
++struct dvo {
++ struct gpio *pin;
++ struct dc_context *ctx;
++};
++
++struct dvo *dal_dvo_create(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en);
++
++void dal_dvo_destroy(
++ struct dvo **dvo);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/gpio.h b/drivers/gpu/drm/amd/dal/dc/gpio/gpio.h
+new file mode 100644
+index 0000000..7fcbb69
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/gpio.h
+@@ -0,0 +1,48 @@
++/*
++ * 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_GPIO_H__
++#define __DAL_GPIO_H__
++
++struct gpio {
++ struct gpio_service *service;
++ struct hw_gpio_pin *pin;
++ enum gpio_id id;
++ uint32_t en;
++ enum gpio_mode mode;
++ /* when GPIO comes from VBIOS, it has defined output state */
++ enum gpio_pin_output_state output_state;
++};
++
++struct gpio *dal_gpio_create(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en,
++ enum gpio_pin_output_state output_state);
++
++void dal_gpio_destroy(
++ struct gpio **ptr);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/gpio_base.c b/drivers/gpu/drm/amd/dal/dc/gpio/gpio_base.c
+new file mode 100644
+index 0000000..6115f59
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/gpio_base.c
+@@ -0,0 +1,279 @@
++/*
++ * 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
++ *
++ */
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "dal_services.h"
++
++#include "include/gpio_interface.h"
++#include "include/gpio_service_interface.h"
++#include "hw_gpio_pin.h"
++#include "hw_translate.h"
++#include "hw_factory.h"
++#include "gpio_service.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "gpio.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++/*
++ * @brief
++ * Public API
++ */
++
++enum gpio_result dal_gpio_open(
++ struct gpio *gpio,
++ enum gpio_mode mode)
++{
++ return dal_gpio_open_ex(gpio, mode, NULL);
++}
++
++enum gpio_result dal_gpio_open_ex(
++ struct gpio *gpio,
++ enum gpio_mode mode,
++ void *options)
++{
++ if (gpio->pin) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_ALREADY_OPENED;
++ }
++
++ gpio->mode = mode;
++
++ return dal_gpio_service_open(
++ gpio->service, gpio->id, gpio->en, mode, options, &gpio->pin);
++}
++
++enum gpio_result dal_gpio_get_value(
++ const struct gpio *gpio,
++ uint32_t *value)
++{
++ if (!gpio->pin) {
++ BREAK_TO_DEBUGGER();
++ return GPIO_RESULT_NULL_HANDLE;
++ }
++
++ return gpio->pin->funcs->get_value(gpio->pin, value);
++}
++
++enum gpio_result dal_gpio_set_value(
++ const struct gpio *gpio,
++ uint32_t value)
++{
++ if (!gpio->pin) {
++ BREAK_TO_DEBUGGER();
++ return GPIO_RESULT_NULL_HANDLE;
++ }
++
++ return gpio->pin->funcs->set_value(gpio->pin, value);
++}
++
++enum gpio_mode dal_gpio_get_mode(
++ const struct gpio *gpio)
++{
++ return gpio->mode;
++}
++
++enum gpio_result dal_gpio_change_mode(
++ struct gpio *gpio,
++ enum gpio_mode mode)
++{
++ if (!gpio->pin) {
++ BREAK_TO_DEBUGGER();
++ return GPIO_RESULT_NULL_HANDLE;
++ }
++
++ return gpio->pin->funcs->change_mode(gpio->pin, mode);
++}
++
++enum gpio_id dal_gpio_get_id(
++ const struct gpio *gpio)
++{
++ return gpio->id;
++}
++
++uint32_t dal_gpio_get_enum(
++ const struct gpio *gpio)
++{
++ return gpio->en;
++}
++
++enum gpio_result dal_gpio_set_config(
++ struct gpio *gpio,
++ const struct gpio_config_data *config_data)
++{
++ if (!gpio->pin) {
++ BREAK_TO_DEBUGGER();
++ return GPIO_RESULT_NULL_HANDLE;
++ }
++
++ return gpio->pin->funcs->set_config(gpio->pin, config_data);
++}
++
++enum gpio_result dal_gpio_get_pin_info(
++ const struct gpio *gpio,
++ struct gpio_pin_info *pin_info)
++{
++ return gpio->service->translate.funcs->id_to_offset(
++ gpio->id, gpio->en, pin_info) ?
++ GPIO_RESULT_OK : GPIO_RESULT_INVALID_DATA;
++}
++
++enum sync_source dal_gpio_get_sync_source(
++ const struct gpio *gpio)
++{
++ switch (gpio->id) {
++ case GPIO_ID_GENERIC:
++ switch (gpio->en) {
++ case GPIO_GENERIC_A:
++ return SYNC_SOURCE_IO_GENERIC_A;
++ case GPIO_GENERIC_B:
++ return SYNC_SOURCE_IO_GENERIC_B;
++ case GPIO_GENERIC_C:
++ return SYNC_SOURCE_IO_GENERIC_C;
++ case GPIO_GENERIC_D:
++ return SYNC_SOURCE_IO_GENERIC_D;
++ case GPIO_GENERIC_E:
++ return SYNC_SOURCE_IO_GENERIC_E;
++ case GPIO_GENERIC_F:
++ return SYNC_SOURCE_IO_GENERIC_F;
++ default:
++ return SYNC_SOURCE_NONE;
++ }
++ break;
++ case GPIO_ID_SYNC:
++ switch (gpio->en) {
++ case GPIO_SYNC_HSYNC_A:
++ return SYNC_SOURCE_IO_HSYNC_A;
++ case GPIO_SYNC_VSYNC_A:
++ return SYNC_SOURCE_IO_VSYNC_A;
++ case GPIO_SYNC_HSYNC_B:
++ return SYNC_SOURCE_IO_HSYNC_B;
++ case GPIO_SYNC_VSYNC_B:
++ return SYNC_SOURCE_IO_VSYNC_B;
++ default:
++ return SYNC_SOURCE_NONE;
++ }
++ break;
++ case GPIO_ID_HPD:
++ switch (gpio->en) {
++ case GPIO_HPD_1:
++ return SYNC_SOURCE_IO_HPD1;
++ case GPIO_HPD_2:
++ return SYNC_SOURCE_IO_HPD2;
++ default:
++ return SYNC_SOURCE_NONE;
++ }
++ break;
++ case GPIO_ID_GSL:
++ switch (gpio->en) {
++ case GPIO_GSL_GENLOCK_CLOCK:
++ return SYNC_SOURCE_GSL_IO_GENLOCK_CLOCK;
++ case GPIO_GSL_GENLOCK_VSYNC:
++ return SYNC_SOURCE_GSL_IO_GENLOCK_VSYNC;
++ case GPIO_GSL_SWAPLOCK_A:
++ return SYNC_SOURCE_GSL_IO_SWAPLOCK_A;
++ case GPIO_GSL_SWAPLOCK_B:
++ return SYNC_SOURCE_GSL_IO_SWAPLOCK_B;
++ default:
++ return SYNC_SOURCE_NONE;
++ }
++ break;
++ default:
++ return SYNC_SOURCE_NONE;
++ }
++}
++
++enum gpio_pin_output_state dal_gpio_get_output_state(
++ const struct gpio *gpio)
++{
++ return gpio->output_state;
++}
++
++void dal_gpio_close(
++ struct gpio *gpio)
++{
++ if (!gpio)
++ return;
++
++ dal_gpio_service_close(gpio->service, &gpio->pin);
++
++ gpio->mode = GPIO_MODE_UNKNOWN;
++}
++
++/*
++ * @brief
++ * Creation and destruction
++ */
++
++struct gpio *dal_gpio_create(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en,
++ enum gpio_pin_output_state output_state)
++{
++ struct gpio *gpio = dc_service_alloc(service->ctx, sizeof(struct gpio));
++
++ if (!gpio) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ gpio->service = service;
++ gpio->pin = NULL;
++ gpio->id = id;
++ gpio->en = en;
++ gpio->mode = GPIO_MODE_UNKNOWN;
++ gpio->output_state = output_state;
++
++ return gpio;
++}
++
++void dal_gpio_destroy(
++ struct gpio **gpio)
++{
++ if (!gpio || !*gpio) {
++ ASSERT_CRITICAL(false);
++ return;
++ }
++
++ dal_gpio_close(*gpio);
++
++ dc_service_free((*gpio)->service->ctx, *gpio);
++
++ *gpio = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.c
+new file mode 100644
+index 0000000..08e046b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.c
+@@ -0,0 +1,470 @@
++/*
++ * 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
++ *
++ */
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "dal_services.h"
++#include "include/gpio_interface.h"
++#include "include/ddc_interface.h"
++#include "include/dvo_interface.h"
++#include "include/irq_interface.h"
++#include "include/gpio_service_interface.h"
++#include "hw_translate.h"
++#include "hw_factory.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "gpio_service.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++#include "hw_gpio_pin.h"
++#include "gpio.h"
++#include "dvo.h"
++#include "ddc.h"
++#include "irq.h"
++
++/*
++ * This unit
++ */
++
++/*
++ * @brief
++ * Public API.
++ */
++
++struct gpio_service *dal_gpio_service_create(
++ enum dce_version dce_version,
++ struct dc_context *ctx)
++{
++ struct gpio_service *service;
++
++ uint32_t index_of_id;
++
++ service = dc_service_alloc(ctx, sizeof(struct gpio_service));
++
++ if (!service) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ if (!dal_hw_translate_init(&service->translate, dce_version)) {
++ BREAK_TO_DEBUGGER();
++ goto failure_1;
++ }
++
++ if (!dal_hw_factory_init(&service->factory, dce_version)) {
++ BREAK_TO_DEBUGGER();
++ goto failure_1;
++ }
++
++ /* allocate and initialize business storage */
++ {
++ const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
++
++ index_of_id = 0;
++ service->ctx = ctx;
++
++ do {
++ uint32_t number_of_bits =
++ service->factory.number_of_pins[index_of_id];
++
++ uint32_t number_of_uints =
++ (number_of_bits + bits_per_uint - 1) /
++ bits_per_uint;
++
++ uint32_t *slot;
++
++ if (number_of_bits) {
++ uint32_t index_of_uint = 0;
++
++ slot = dc_service_alloc(
++ ctx,
++ number_of_uints * sizeof(uint32_t));
++
++ if (!slot) {
++ BREAK_TO_DEBUGGER();
++ goto failure_2;
++ }
++
++ do {
++ slot[index_of_uint] = 0;
++
++ ++index_of_uint;
++ } while (index_of_uint < number_of_uints);
++ } else
++ slot = NULL;
++
++ service->busyness[index_of_id] = slot;
++
++ ++index_of_id;
++ } while (index_of_id < GPIO_ID_COUNT);
++ }
++
++ return service;
++
++failure_2:
++ while (index_of_id) {
++ uint32_t *slot;
++
++ --index_of_id;
++
++ slot = service->busyness[index_of_id];
++
++ if (slot)
++ dc_service_free(ctx, slot);
++ };
++
++failure_1:
++ dc_service_free(ctx, service);
++
++ return NULL;
++}
++
++struct gpio *dal_gpio_service_create_gpio(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask,
++ enum gpio_pin_output_state output_state)
++{
++ enum gpio_id id;
++ uint32_t en;
++
++ if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ return dal_gpio_create(service, id, en, output_state);
++}
++
++struct gpio *dal_gpio_service_create_gpio_ex(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en,
++ enum gpio_pin_output_state output_state)
++{
++ return dal_gpio_create(service, id, en, output_state);
++}
++
++void dal_gpio_service_destroy_gpio(
++ struct gpio **gpio)
++{
++ dal_gpio_destroy(gpio);
++}
++
++struct ddc *dal_gpio_service_create_ddc(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask,
++ struct gpio_ddc_hw_info *info)
++{
++ return dal_gpio_create_ddc(service, offset, mask, info);
++}
++
++void dal_gpio_service_destroy_ddc(
++ struct ddc **ddc)
++{
++ dal_gpio_destroy_ddc(ddc);
++}
++
++struct dvo *dal_gpio_service_create_dvo(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask)
++{
++ enum gpio_id id;
++ uint32_t en;
++
++ if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ return dal_dvo_create(service, id, en);
++}
++
++struct dvo *dal_gpio_service_create_dvo_ex(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en)
++{
++ return dal_dvo_create(service, id, en);
++}
++
++void dal_gpio_service_destroy_dvo(
++ struct dvo **dvo)
++{
++ dal_dvo_destroy(dvo);
++}
++
++struct irq *dal_gpio_service_create_irq(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask)
++{
++ enum gpio_id id;
++ uint32_t en;
++
++ if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ return dal_gpio_create_irq(service, id, en);
++}
++
++struct irq *dal_gpio_service_create_irq_ex(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en)
++{
++ return dal_gpio_create_irq(service, id, en);
++}
++
++void dal_gpio_service_destroy_irq(
++ struct irq **irq)
++{
++ dal_gpio_destroy_irq(irq);
++}
++
++void dal_gpio_service_destroy(
++ struct gpio_service **ptr)
++{
++ if (!ptr || !*ptr) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ /* free business storage */
++ {
++ uint32_t index_of_id = 0;
++
++ do {
++ uint32_t *slot = (*ptr)->busyness[index_of_id];
++
++ if (slot)
++ dc_service_free((*ptr)->ctx, slot);
++
++ ++index_of_id;
++ } while (index_of_id < GPIO_ID_COUNT);
++ }
++
++ dc_service_free((*ptr)->ctx, *ptr);
++
++ *ptr = NULL;
++}
++
++/*
++ * @brief
++ * Private API.
++ */
++
++static bool is_pin_busy(
++ const struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en)
++{
++ const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
++
++ const uint32_t *slot = service->busyness[id] + (en / bits_per_uint);
++
++ return 0 != (*slot & (1 << (en % bits_per_uint)));
++}
++
++static bool is_some_pin_busy(
++ const struct gpio_service *service,
++ enum gpio_id id)
++{
++ const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
++
++ uint32_t index_of_uint = 0;
++
++ uint32_t number_of_uints =
++ service->factory.number_of_pins[id];
++
++ number_of_uints = (number_of_uints + bits_per_uint - 1) / bits_per_uint;
++
++ while (index_of_uint < number_of_uints) {
++ if (service->busyness[id][index_of_uint])
++ return true;
++
++ ++index_of_uint;
++ };
++
++ return false;
++}
++
++static void set_pin_busy(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en)
++{
++ const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
++
++ service->busyness[id][en / bits_per_uint] |=
++ (1 << (en % bits_per_uint));
++}
++
++static void set_pin_free(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en)
++{
++ const uint32_t bits_per_uint = sizeof(uint32_t) << 3;
++
++ service->busyness[id][en / bits_per_uint] &=
++ ~(1 << (en % bits_per_uint));
++}
++
++enum gpio_result dal_gpio_service_open(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en,
++ enum gpio_mode mode,
++ void *options,
++ struct hw_gpio_pin **ptr)
++{
++ struct hw_gpio_pin *pin;
++
++ if (!service->busyness[id]) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_OPEN_FAILED;
++ }
++
++ if (is_pin_busy(service, id, en)) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_DEVICE_BUSY;
++ }
++
++ switch (id) {
++ case GPIO_ID_DVO1:
++ /* [anaumov] not implemented, commented with "to do" */
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++ case GPIO_ID_DVO12:
++ if (!service->busyness[GPIO_ID_DVO24]) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_OPEN_FAILED;
++ }
++
++ if (is_some_pin_busy(service, GPIO_ID_DVO24)) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_DEVICE_BUSY;
++ }
++
++ pin = service->factory.funcs->create_dvo(
++ service->ctx, id, en);
++ break;
++ case GPIO_ID_DVO24:
++ if (!service->busyness[GPIO_ID_DVO12]) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_OPEN_FAILED;
++ }
++
++ if (is_some_pin_busy(service, GPIO_ID_DVO12)) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_DEVICE_BUSY;
++ }
++
++ pin = service->factory.funcs->create_dvo(
++ service->ctx, id, en);
++ break;
++ case GPIO_ID_DDC_DATA:
++ pin = service->factory.funcs->create_ddc_data(
++ service->ctx, id, en);
++ break;
++ case GPIO_ID_DDC_CLOCK:
++ pin = service->factory.funcs->create_ddc_clock(
++ service->ctx, id, en);
++ break;
++ case GPIO_ID_GENERIC:
++ pin = service->factory.funcs->create_generic(
++ service->ctx, id, en);
++ break;
++ case GPIO_ID_HPD:
++ pin = service->factory.funcs->create_hpd(
++ service->ctx, id, en);
++ break;
++ case GPIO_ID_GPIO_PAD:
++ pin = service->factory.funcs->create_gpio_pad(
++ service->ctx, id, en);
++ break;
++ case GPIO_ID_SYNC:
++ pin = service->factory.funcs->create_sync(
++ service->ctx, id, en);
++ break;
++ case GPIO_ID_GSL:
++ pin = service->factory.funcs->create_gsl(
++ service->ctx, id, en);
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++ }
++
++ if (!pin) {
++ ASSERT_CRITICAL(false);
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++ }
++
++ if (!pin->funcs->open(pin, mode, options)) {
++ ASSERT_CRITICAL(false);
++ dal_gpio_service_close(service, &pin);
++ return GPIO_RESULT_OPEN_FAILED;
++ }
++
++ set_pin_busy(service, id, en);
++ *ptr = pin;
++ return GPIO_RESULT_OK;
++}
++
++void dal_gpio_service_close(
++ struct gpio_service *service,
++ struct hw_gpio_pin **ptr)
++{
++ struct hw_gpio_pin *pin;
++
++ if (!ptr) {
++ ASSERT_CRITICAL(false);
++ return;
++ }
++
++ pin = *ptr;
++
++ if (pin) {
++ set_pin_free(service, pin->id, pin->en);
++
++ pin->funcs->close(pin);
++
++ pin->funcs->destroy(ptr);
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.h b/drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.h
+new file mode 100644
+index 0000000..a17c438
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/gpio_service.h
+@@ -0,0 +1,57 @@
++/*
++ * 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_GPIO_SERVICE_H__
++#define __DAL_GPIO_SERVICE_H__
++
++struct hw_translate;
++struct hw_factory;
++
++struct gpio_service {
++ struct dc_context *ctx;
++ struct hw_translate translate;
++ struct hw_factory factory;
++ /*
++ * @brief
++ * Business storage.
++ * For each member of 'enum gpio_id',
++ * store array of bits (packed into uint32_t slots),
++ * index individual bit by 'en' value */
++ uint32_t *busyness[GPIO_ID_COUNT];
++};
++
++enum gpio_result dal_gpio_service_open(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en,
++ enum gpio_mode mode,
++ void *options,
++ struct hw_gpio_pin **ptr);
++
++void dal_gpio_service_close(
++ struct gpio_service *service,
++ struct hw_gpio_pin **ptr);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.c
+new file mode 100644
+index 0000000..0608f16
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.c
+@@ -0,0 +1,105 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++#include "hw_gpio_pin.h"
++#include "hw_gpio.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "hw_ddc.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++#define FROM_HW_GPIO(ptr) \
++ container_of((ptr), struct hw_ddc, base)
++
++#define FROM_HW_GPIO_PIN(ptr) \
++ FROM_HW_GPIO(container_of((ptr), struct hw_gpio, base))
++
++bool dal_hw_ddc_open(
++ struct hw_gpio_pin *ptr,
++ enum gpio_mode mode,
++ void *options)
++{
++ struct hw_ddc *pin = FROM_HW_GPIO_PIN(ptr);
++
++ uint32_t en;
++
++ if (!options) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ /* get the EN bit before overwriting it */
++
++ dal_hw_gpio_get_reg_value(
++ ptr->ctx,
++ &pin->base.pin_reg.DC_GPIO_DATA_EN,
++ &en);
++
++ ((struct gpio_ddc_open_options *)options)->en_bit_present = (en != 0);
++
++ return dal_hw_gpio_open(ptr, mode, options);
++}
++
++bool dal_hw_ddc_construct(
++ struct hw_ddc *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx)
++{
++ if (!dal_hw_gpio_construct(&pin->base, id, en, ctx))
++ return false;
++
++ pin->mask.DC_GPIO_DDC_MASK_MASK = 0;
++ pin->mask.DC_GPIO_DDC_PD_EN_MASK = 0;
++ pin->mask.DC_GPIO_DDC_RECV_MASK = 0;
++ pin->mask.AUX_PAD_MODE_MASK = 0;
++ pin->mask.AUX_POL_MASK = 0;
++ pin->mask.DC_GPIO_DDCCLK_STR_MASK = 0;
++
++ return true;
++}
++
++void dal_hw_ddc_destruct(
++ struct hw_ddc *pin)
++{
++ dal_hw_gpio_destruct(&pin->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.h b/drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.h
+new file mode 100644
+index 0000000..a3a727c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_ddc.h
+@@ -0,0 +1,60 @@
++/*
++ * 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_HW_DDC_H__
++#define __DAL_HW_DDC_H__
++
++struct hw_ddc_mask {
++ uint32_t DC_GPIO_DDC_MASK_MASK;
++ uint32_t DC_GPIO_DDC_PD_EN_MASK;
++ uint32_t DC_GPIO_DDC_RECV_MASK;
++ uint32_t AUX_PAD_MODE_MASK;
++ uint32_t AUX_POL_MASK;
++ uint32_t DC_GPIO_DDCCLK_STR_MASK;
++};
++
++struct hw_ddc {
++ struct hw_gpio base;
++ struct hw_ddc_mask mask;
++};
++
++#define HW_DDC_FROM_BASE(hw_gpio) \
++ container_of((HW_GPIO_FROM_BASE(hw_gpio)), struct hw_ddc, base)
++
++bool dal_hw_ddc_construct(
++ struct hw_ddc *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx);
++
++void dal_hw_ddc_destruct(
++ struct hw_ddc *pin);
++
++bool dal_hw_ddc_open(
++ struct hw_gpio_pin *ptr,
++ enum gpio_mode mode,
++ void *options);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.c
+new file mode 100644
+index 0000000..a5a07f0
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.c
+@@ -0,0 +1,318 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++#include "hw_gpio_pin.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "hw_dvo.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++#define FROM_HW_GPIO_PIN(ptr) \
++ container_of((ptr), struct hw_dvo, base)
++
++static void store_dvo_registers(
++ struct hw_dvo *pin)
++{
++ pin->store.dvo_mask = dal_read_reg(
++ pin->base.ctx, pin->addr.DC_GPIO_DVODATA_MASK);
++ pin->store.dvo_en = dal_read_reg(
++ pin->base.ctx, pin->addr.DC_GPIO_DVODATA_EN);
++ pin->store.dvo_data_a = dal_read_reg(
++ pin->base.ctx, pin->addr.DC_GPIO_DVODATA_A);
++}
++
++static void restore_dvo_registers(
++ struct hw_dvo *pin)
++{
++ {
++ const uint32_t addr = pin->addr.DC_GPIO_DVODATA_MASK;
++
++ uint32_t data = dal_read_reg(pin->base.ctx, addr);
++
++ data &= ~pin->dvo_mask;
++ data |= pin->store.dvo_mask & pin->dvo_mask;
++
++ dal_write_reg(pin->base.ctx, addr, data);
++ }
++
++ {
++ const uint32_t addr = pin->addr.DC_GPIO_DVODATA_EN;
++
++ uint32_t data = dal_read_reg(pin->base.ctx, addr);
++
++ data &= ~pin->dvo_mask;
++ data |= pin->store.dvo_en & pin->dvo_mask;
++
++ dal_write_reg(pin->base.ctx, addr, data);
++ }
++
++ {
++ const uint32_t addr = pin->addr.DC_GPIO_DVODATA_A;
++
++ uint32_t data = dal_read_reg(pin->base.ctx, addr);
++
++ data &= ~pin->dvo_mask;
++ data |= pin->store.dvo_data_a & pin->dvo_mask;
++
++ dal_write_reg(pin->base.ctx, addr, data);
++ }
++}
++
++static void program_dvo(
++ struct hw_dvo *pin,
++ bool output)
++{
++ /* Turn on Mask bits for the requested channel,
++ * this will enable the channel for software control. */
++ {
++ const uint32_t addr = pin->addr.DC_GPIO_DVODATA_MASK;
++
++ uint32_t mask = dal_read_reg(pin->base.ctx, addr);
++
++ uint32_t data = pin->dvo_mask | mask;
++
++ dal_write_reg(pin->base.ctx, addr, data);
++ }
++
++ /* Turn off/on the Enable bits on the requested channel,
++ * this will set it to Input/Output mode. */
++ {
++ const uint32_t addr = pin->addr.DC_GPIO_DVODATA_EN;
++
++ uint32_t enable = dal_read_reg(pin->base.ctx, addr);
++
++ uint32_t data = output ?
++ (pin->dvo_mask | enable) :
++ (~pin->dvo_mask & enable);
++
++ dal_write_reg(pin->base.ctx, addr, data);
++ }
++}
++
++static void program_dvo_strength(
++ struct hw_dvo *pin)
++{
++ const uint32_t addr = pin->addr.DVO_STRENGTH_CONTROL;
++
++ uint32_t data = dal_read_reg(pin->base.ctx, addr);
++
++ data &= ~pin->dvo_strength_mask;
++ data |= pin->dvo_strength & pin->dvo_strength_mask;
++
++ dal_write_reg(pin->base.ctx, addr, data);
++}
++
++static void disable_on_chip_terminators(
++ struct hw_dvo *pin)
++{
++ const uint32_t addr = pin->addr.D1CRTC_MVP_CONTROL1;
++
++ uint32_t data = dal_read_reg(pin->base.ctx, addr);
++
++ pin->store.mvp_terminator_state = (data & pin->mvp_termination_mask);
++
++ data &= ~pin->mvp_termination_mask;
++
++ dal_write_reg(pin->base.ctx, addr, data);
++}
++
++static void restore_on_chip_terminators(
++ struct hw_dvo *pin)
++{
++ const uint32_t addr = pin->addr.D1CRTC_MVP_CONTROL1;
++
++ uint32_t data = dal_read_reg(pin->base.ctx, addr);
++
++ data &= ~pin->mvp_termination_mask;
++
++ if (pin->store.mvp_terminator_state)
++ data |= pin->mvp_termination_mask;
++
++ dal_write_reg(pin->base.ctx, addr, data);
++}
++
++bool dal_hw_dvo_open(
++ struct hw_gpio_pin *ptr,
++ enum gpio_mode mode,
++ void *options)
++{
++ struct hw_dvo *pin = FROM_HW_GPIO_PIN(ptr);
++
++ store_dvo_registers(pin);
++
++ ptr->mode = mode;
++
++ switch (mode) {
++ case GPIO_MODE_INPUT:
++ program_dvo_strength(pin);
++ disable_on_chip_terminators(pin);
++ program_dvo(pin, false);
++
++ ptr->opened = true;
++ break;
++ case GPIO_MODE_OUTPUT:
++ program_dvo_strength(pin);
++ disable_on_chip_terminators(pin);
++ program_dvo(pin, true);
++
++ ptr->opened = true;
++ break;
++ default:
++ /* unsupported mode */
++ BREAK_TO_DEBUGGER();
++
++ ptr->opened = false;
++ }
++
++ return ptr->opened;
++}
++
++enum gpio_result dal_hw_dvo_get_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t *value)
++{
++ const struct hw_dvo *pin = FROM_HW_GPIO_PIN(ptr);
++
++ if (ptr->mode != GPIO_MODE_INPUT)
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++
++ *value = dal_read_reg(ptr->ctx, pin->addr.DC_GPIO_DVODATA_Y);
++
++ *value &= pin->dvo_mask;
++ *value >>= pin->dvo_shift;
++
++ return GPIO_RESULT_OK;
++}
++
++enum gpio_result dal_hw_dvo_set_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t value)
++{
++ const struct hw_dvo *pin = FROM_HW_GPIO_PIN(ptr);
++
++ uint32_t masked_value;
++
++ if (ptr->mode != GPIO_MODE_OUTPUT) {
++ BREAK_TO_DEBUGGER();
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++ }
++
++ /* Ensure there is no overflow of the value written.
++ * Value cannot be more than 12 bits for a 12-bit channel. */
++
++ masked_value = value << pin->dvo_shift;
++
++ if (masked_value != (masked_value & pin->dvo_mask)) {
++ BREAK_TO_DEBUGGER();
++ return GPIO_RESULT_INVALID_DATA;
++ }
++
++ masked_value &= pin->dvo_mask;
++
++ /* read the DataA register
++ * mask off the Bundle that we want to write to
++ * or the data into the register */
++ {
++ const uint32_t addr = pin->addr.DC_GPIO_DVODATA_A;
++
++ uint32_t data = dal_read_reg(ptr->ctx, addr);
++
++ data &= ~pin->dvo_mask;
++ data |= masked_value;
++
++ dal_write_reg(ptr->ctx, addr, data);
++ }
++
++ return GPIO_RESULT_OK;
++}
++
++void dal_hw_dvo_close(
++ struct hw_gpio_pin *ptr)
++{
++ struct hw_dvo *pin = FROM_HW_GPIO_PIN(ptr);
++
++ restore_dvo_registers(pin);
++ restore_on_chip_terminators(pin);
++
++ ptr->mode = GPIO_MODE_UNKNOWN;
++
++ ptr->opened = false;
++}
++
++bool dal_hw_dvo_construct(
++ struct hw_dvo *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx)
++{
++ struct hw_gpio_pin *base = &pin->base;
++
++ if (!dal_hw_gpio_pin_construct(base, id, en, ctx))
++ return false;
++
++ pin->addr.DC_GPIO_DVODATA_MASK = 0;
++ pin->addr.DC_GPIO_DVODATA_EN = 0;
++ pin->addr.DC_GPIO_DVODATA_A = 0;
++ pin->addr.DC_GPIO_DVODATA_Y = 0;
++ pin->addr.DVO_STRENGTH_CONTROL = 0;
++ pin->addr.D1CRTC_MVP_CONTROL1 = 0;
++
++ pin->dvo_mask = 0;
++ pin->dvo_shift = 0;
++ pin->dvo_strength_mask = 0;
++ pin->mvp_termination_mask = 0;
++
++ pin->dvo_strength = 0;
++
++ pin->store.dvo_mask = 0;
++ pin->store.dvo_en = 0;
++ pin->store.dvo_data_a = 0;
++ pin->store.mvp_terminator_state = false;
++
++ return true;
++}
++
++void dal_hw_dvo_destruct(
++ struct hw_dvo *pin)
++{
++ dal_hw_gpio_pin_destruct(&pin->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.h b/drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.h
+new file mode 100644
+index 0000000..5a120c2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_dvo.h
+@@ -0,0 +1,89 @@
++/*
++ * 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_HW_DVO_H__
++#define __DAL_HW_DVO_H__
++
++#define BUNDLE_A_SHIFT 12L
++#define BUNDLE_B_SHIFT 0L
++
++struct hw_dvo {
++ struct hw_gpio_pin base;
++ /* Register indices are represented by member variables,
++ * are to be filled in by derived classes.
++ * These members permit the use of common code
++ * for programming registers where the sequence is the same
++ * but the register sets are different */
++ struct {
++ uint32_t DC_GPIO_DVODATA_MASK;
++ uint32_t DC_GPIO_DVODATA_EN;
++ uint32_t DC_GPIO_DVODATA_A;
++ uint32_t DC_GPIO_DVODATA_Y;
++ uint32_t DVO_STRENGTH_CONTROL;
++ uint32_t D1CRTC_MVP_CONTROL1;
++ } addr;
++
++ /* Mask and shift differentiates between Bundle A and Bundle B */
++ uint32_t dvo_mask;
++ uint32_t dvo_shift;
++ uint32_t dvo_strength_mask;
++ uint32_t mvp_termination_mask;
++
++ uint32_t dvo_strength;
++
++ struct {
++ uint32_t dvo_mask;
++ uint32_t dvo_en;
++ uint32_t dvo_data_a;
++ bool mvp_terminator_state;
++ } store;
++};
++
++bool dal_hw_dvo_construct(
++ struct hw_dvo *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx);
++
++void dal_hw_dvo_destruct(
++ struct hw_dvo *pin);
++
++bool dal_hw_dvo_open(
++ struct hw_gpio_pin *ptr,
++ enum gpio_mode mode,
++ void *options);
++
++enum gpio_result dal_hw_dvo_get_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t *value);
++
++enum gpio_result dal_hw_dvo_set_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t value);
++
++void dal_hw_dvo_close(
++ struct hw_gpio_pin *ptr);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
+new file mode 100644
+index 0000000..d1b6b7e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.c
+@@ -0,0 +1,80 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "hw_factory.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/hw_factory_dce110.h"
++#endif
++/*
++ * This unit
++ */
++
++bool dal_hw_factory_init(
++ struct hw_factory *factory,
++ enum dce_version dce_version)
++{
++ switch (dce_version) {
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ dal_hw_factory_dce110_init(factory);
++ return true;
++#endif
++ default:
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++}
++
++void dal_hw_factory_destroy(
++ struct dc_context *ctx,
++ struct hw_factory **factory)
++{
++ if (!factory || !*factory) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ dc_service_free(ctx, *factory);
++
++ *factory = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.h b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.h
+new file mode 100644
+index 0000000..f16678c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_factory.h
+@@ -0,0 +1,74 @@
++/*
++ * 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_HW_FACTORY_H__
++#define __DAL_HW_FACTORY_H__
++
++struct hw_gpio_pin;
++
++struct hw_factory {
++ uint32_t number_of_pins[GPIO_ID_COUNT];
++
++ const struct hw_factory_funcs {
++ struct hw_gpio_pin *(*create_dvo)(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ struct hw_gpio_pin *(*create_ddc_data)(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ struct hw_gpio_pin *(*create_ddc_clock)(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ struct hw_gpio_pin *(*create_generic)(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ struct hw_gpio_pin *(*create_hpd)(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ struct hw_gpio_pin *(*create_gpio_pad)(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ struct hw_gpio_pin *(*create_sync)(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ struct hw_gpio_pin *(*create_gsl)(
++ struct dc_context *ctx,
++ enum gpio_id id,
++ uint32_t en);
++ } *funcs;
++};
++
++bool dal_hw_factory_init(
++ struct hw_factory *factory,
++ enum dce_version dce_version);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.c
+new file mode 100644
+index 0000000..2964d5d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.c
+@@ -0,0 +1,408 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++#include "hw_gpio_pin.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "hw_gpio.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++enum gpio_result dal_hw_gpio_get_reg_value(
++ struct dc_context *ctx,
++ const struct addr_mask *reg,
++ uint32_t *value)
++{
++ *value = dal_read_reg(ctx, reg->addr);
++
++ *value &= reg->mask;
++
++ return GPIO_RESULT_OK;
++}
++
++enum gpio_result dal_hw_gpio_set_reg_value(
++ struct dc_context *ctx,
++ const struct addr_mask *reg,
++ uint32_t value)
++{
++ uint32_t prev_value;
++
++ if ((value & reg->mask) != value) {
++ BREAK_TO_DEBUGGER();
++ return GPIO_RESULT_INVALID_DATA;
++ }
++
++ prev_value = dal_read_reg(ctx, reg->addr);
++
++ prev_value &= ~reg->mask;
++ prev_value |= (value & reg->mask);
++
++ dal_write_reg(ctx, reg->addr, prev_value);
++
++ return GPIO_RESULT_OK;
++}
++
++uint32_t dal_hw_gpio_get_shift_from_mask(
++ uint32_t mask)
++{
++ uint32_t result = 0;
++
++ if (!mask)
++ return 32;
++
++ do {
++ if ((1 << result) & mask)
++ break;
++
++ ++result;
++ } while (result < 32);
++
++ return result;
++}
++
++#define FROM_HW_GPIO_PIN(ptr) \
++ container_of((ptr), struct hw_gpio, base)
++
++static void store_registers(
++ struct hw_gpio *pin)
++{
++ dal_hw_gpio_get_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_MASK,
++ &pin->store.mask);
++ dal_hw_gpio_get_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_A,
++ &pin->store.a);
++ dal_hw_gpio_get_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_EN,
++ &pin->store.en);
++
++ if (pin->mux_supported)
++ dal_hw_gpio_get_reg_value(
++ pin->base.ctx,
++ &pin->mux_reg.GPIO_MUX_CONTROL,
++ &pin->store.mux);
++}
++
++static void restore_registers(
++ struct hw_gpio *pin)
++{
++ dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_MASK,
++ pin->store.mask);
++ dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_A,
++ pin->store.a);
++ dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_EN,
++ pin->store.en);
++
++ if (pin->mux_supported)
++ dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->mux_reg.GPIO_MUX_CONTROL,
++ pin->store.mux);
++}
++
++bool dal_hw_gpio_open(
++ struct hw_gpio_pin *ptr,
++ enum gpio_mode mode,
++ void *options)
++{
++ struct hw_gpio *pin = FROM_HW_GPIO_PIN(ptr);
++
++ store_registers(pin);
++
++ ptr->opened = (pin->funcs->config_mode(pin, mode) == GPIO_RESULT_OK);
++
++ return ptr->opened;
++}
++
++enum gpio_result dal_hw_gpio_get_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t *value)
++{
++ const struct hw_gpio *pin = FROM_HW_GPIO_PIN(ptr);
++
++ enum gpio_result result;
++
++ switch (ptr->mode) {
++ case GPIO_MODE_INPUT:
++ case GPIO_MODE_OUTPUT:
++ case GPIO_MODE_HARDWARE:
++ case GPIO_MODE_FAST_OUTPUT:
++ result = dal_hw_gpio_get_reg_value(
++ ptr->ctx,
++ &pin->pin_reg.DC_GPIO_DATA_Y,
++ value);
++ /* Clients does not know that the value
++ * comes from register and is shifted. */
++ if (result == GPIO_RESULT_OK)
++ *value >>= dal_hw_gpio_get_shift_from_mask(
++ pin->pin_reg.DC_GPIO_DATA_Y.mask);
++ break;
++ default:
++ result = GPIO_RESULT_NON_SPECIFIC_ERROR;
++ }
++
++ return result;
++}
++
++enum gpio_result dal_hw_gpio_set_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t value)
++{
++ struct hw_gpio *pin = FROM_HW_GPIO_PIN(ptr);
++
++ /* This is the public interface
++ * where the input comes from client, not shifted yet
++ * (because client does not know the shifts). */
++
++ switch (ptr->mode) {
++ case GPIO_MODE_OUTPUT:
++ return dal_hw_gpio_set_reg_value(
++ ptr->ctx,
++ &pin->pin_reg.DC_GPIO_DATA_A,
++ value << dal_hw_gpio_get_shift_from_mask(
++ pin->pin_reg.DC_GPIO_DATA_A.mask));
++ case GPIO_MODE_FAST_OUTPUT:
++ /* We use (EN) to faster switch (used in DDC GPIO).
++ * So (A) is grounded, output is driven by (EN = 0)
++ * to pull the line down (output == 0) and (EN=1)
++ * then output is tri-state */
++ return dal_hw_gpio_set_reg_value(
++ ptr->ctx,
++ &pin->pin_reg.DC_GPIO_DATA_EN,
++ pin->pin_reg.DC_GPIO_DATA_EN.mask &
++ ~(value << dal_hw_gpio_get_shift_from_mask(
++ pin->pin_reg.DC_GPIO_DATA_EN.mask)));
++ default:
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++ }
++}
++
++enum gpio_result dal_hw_gpio_change_mode(
++ struct hw_gpio_pin *ptr,
++ enum gpio_mode mode)
++{
++ struct hw_gpio *pin = FROM_HW_GPIO_PIN(ptr);
++
++ return pin->funcs->config_mode(pin, mode);
++}
++
++void dal_hw_gpio_close(
++ struct hw_gpio_pin *ptr)
++{
++ struct hw_gpio *pin = FROM_HW_GPIO_PIN(ptr);
++
++ restore_registers(pin);
++
++ ptr->mode = GPIO_MODE_UNKNOWN;
++ ptr->opened = false;
++}
++
++static enum gpio_result config_mode_input(
++ struct hw_gpio *pin)
++{
++ enum gpio_result result;
++
++ /* turn off output enable, act as input pin;
++ * program the pin as GPIO, mask out signal driven by HW */
++
++ result = dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_EN,
++ 0);
++
++ if (result != GPIO_RESULT_OK)
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++
++ result = dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_MASK,
++ pin->pin_reg.DC_GPIO_DATA_MASK.mask);
++
++ if (result != GPIO_RESULT_OK)
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++
++ return GPIO_RESULT_OK;
++}
++
++static enum gpio_result config_mode_output(
++ struct hw_gpio *pin)
++{
++ enum gpio_result result;
++
++ /* turn on output enable, act as output pin;
++ * program the pin as GPIO, mask out signal driven by HW */
++
++ result = dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_EN,
++ pin->pin_reg.DC_GPIO_DATA_EN.mask);
++
++ if (result != GPIO_RESULT_OK)
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++
++ result = dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_MASK,
++ pin->pin_reg.DC_GPIO_DATA_MASK.mask);
++
++ if (result != GPIO_RESULT_OK)
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++
++ return GPIO_RESULT_OK;
++}
++
++static enum gpio_result config_mode_fast_output(
++ struct hw_gpio *pin)
++{
++ enum gpio_result result;
++
++ /* grounding the A register then use the EN register bit
++ * will have faster effect on the rise time */
++
++ result = dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_A, 0);
++
++ if (result != GPIO_RESULT_OK)
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++
++ result = dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_MASK,
++ pin->pin_reg.DC_GPIO_DATA_MASK.mask);
++
++ if (result != GPIO_RESULT_OK)
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++
++ return GPIO_RESULT_OK;
++}
++
++static enum gpio_result config_mode_hardware(
++ struct hw_gpio *pin)
++{
++ /* program the pin as tri-state, pin is driven by HW */
++
++ enum gpio_result result =
++ dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_MASK,
++ 0);
++
++ if (result != GPIO_RESULT_OK)
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++
++ return GPIO_RESULT_OK;
++}
++
++enum gpio_result dal_hw_gpio_config_mode(
++ struct hw_gpio *pin,
++ enum gpio_mode mode)
++{
++ pin->base.mode = mode;
++
++ switch (mode) {
++ case GPIO_MODE_INPUT:
++ return config_mode_input(pin);
++ case GPIO_MODE_OUTPUT:
++ return config_mode_output(pin);
++ case GPIO_MODE_FAST_OUTPUT:
++ return config_mode_fast_output(pin);
++ case GPIO_MODE_HARDWARE:
++ return config_mode_hardware(pin);
++ default:
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++ }
++}
++
++const struct hw_gpio_funcs func = {
++ .config_mode = dal_hw_gpio_config_mode,
++};
++
++bool dal_hw_gpio_construct(
++ struct hw_gpio *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx)
++{
++ struct hw_gpio_pin *base = &pin->base;
++
++ if (!dal_hw_gpio_pin_construct(base, id, en, ctx))
++ return false;
++
++ pin->funcs = &func;
++
++ pin->pin_reg.DC_GPIO_DATA_MASK.addr = 0;
++ pin->pin_reg.DC_GPIO_DATA_MASK.mask = 0;
++ pin->pin_reg.DC_GPIO_DATA_A.addr = 0;
++ pin->pin_reg.DC_GPIO_DATA_A.mask = 0;
++ pin->pin_reg.DC_GPIO_DATA_EN.addr = 0;
++ pin->pin_reg.DC_GPIO_DATA_EN.mask = 0;
++ pin->pin_reg.DC_GPIO_DATA_Y.addr = 0;
++ pin->pin_reg.DC_GPIO_DATA_Y.mask = 0;
++ pin->mux_reg.GPIO_MUX_CONTROL.addr = 0;
++ pin->mux_reg.GPIO_MUX_CONTROL.mask = 0;
++ pin->mux_reg.GPIO_MUX_STEREO_SEL.addr = 0;
++ pin->mux_reg.GPIO_MUX_STEREO_SEL.mask = 0;
++
++ pin->store.mask = 0;
++ pin->store.a = 0;
++ pin->store.en = 0;
++ pin->store.mux = 0;
++
++ pin->mux_supported = false;
++
++ return true;
++}
++
++void dal_hw_gpio_destruct(
++ struct hw_gpio *pin)
++{
++ dal_hw_gpio_pin_destruct(&pin->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.h b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.h
+new file mode 100644
+index 0000000..44eb86e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio.h
+@@ -0,0 +1,129 @@
++/*
++ * 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_HW_GPIO_H__
++#define __DAL_HW_GPIO_H__
++
++struct addr_mask {
++ uint32_t addr;
++ uint32_t mask;
++};
++
++enum gpio_result dal_hw_gpio_get_reg_value(
++ struct dc_context *ctx,
++ const struct addr_mask *reg,
++ uint32_t *value);
++
++enum gpio_result dal_hw_gpio_set_reg_value(
++ struct dc_context *ctx,
++ const struct addr_mask *reg,
++ uint32_t value);
++
++uint32_t dal_hw_gpio_get_shift_from_mask(
++ uint32_t mask);
++
++struct hw_gpio;
++
++struct hw_gpio_funcs {
++ enum gpio_result (*config_mode)(
++ struct hw_gpio *pin,
++ enum gpio_mode mode);
++};
++
++/* Register indices are represented by member variables
++ * and are to be filled in by constructors of derived classes.
++ * These members permit the use of common code
++ * for programming registers, where the sequence is the same
++ * but register sets are different.
++ * Some GPIOs have HW mux which allows to choose
++ * what is the source of the signal in HW mode */
++
++struct hw_gpio_pin_reg {
++ struct addr_mask DC_GPIO_DATA_MASK;
++ struct addr_mask DC_GPIO_DATA_A;
++ struct addr_mask DC_GPIO_DATA_EN;
++ struct addr_mask DC_GPIO_DATA_Y;
++};
++
++struct hw_gpio_mux_reg {
++ struct addr_mask GPIO_MUX_CONTROL;
++ struct addr_mask GPIO_MUX_STEREO_SEL;
++};
++
++struct hw_gpio {
++ struct hw_gpio_pin base;
++ const struct hw_gpio_funcs *funcs;
++ struct hw_gpio_pin_reg pin_reg;
++ struct hw_gpio_mux_reg mux_reg;
++
++ /* variables to save register value */
++ struct {
++ uint32_t mask;
++ uint32_t a;
++ uint32_t en;
++ uint32_t mux;
++ } store;
++
++ /* GPIO MUX support */
++ bool mux_supported;
++};
++
++#define HW_GPIO_FROM_BASE(hw_gpio_pin) \
++ container_of((hw_gpio_pin), struct hw_gpio, base)
++
++bool dal_hw_gpio_construct(
++ struct hw_gpio *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx);
++
++bool dal_hw_gpio_open(
++ struct hw_gpio_pin *pin,
++ enum gpio_mode mode,
++ void *options);
++
++enum gpio_result dal_hw_gpio_get_value(
++ const struct hw_gpio_pin *pin,
++ uint32_t *value);
++
++enum gpio_result dal_hw_gpio_config_mode(
++ struct hw_gpio *pin,
++ enum gpio_mode mode);
++
++void dal_hw_gpio_destruct(
++ struct hw_gpio *pin);
++
++enum gpio_result dal_hw_gpio_set_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t value);
++
++enum gpio_result dal_hw_gpio_change_mode(
++ struct hw_gpio_pin *ptr,
++ enum gpio_mode mode);
++
++void dal_hw_gpio_close(
++ struct hw_gpio_pin *ptr);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.c
+new file mode 100644
+index 0000000..057c439
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.c
+@@ -0,0 +1,93 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++#include "hw_gpio_pin.h"
++#include "hw_gpio.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "hw_gpio_pad.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++#define FROM_HW_GPIO(ptr) \
++ container_of((ptr), struct hw_gpio_pad, base)
++
++#define FROM_HW_GPIO_PIN(ptr) \
++ FROM_HW_GPIO(container_of((ptr), struct hw_gpio, base))
++
++enum gpio_result dal_hw_gpio_pad_get_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t *value)
++{
++ const struct hw_gpio_pad *pin = FROM_HW_GPIO_PIN(ptr);
++
++ if (ptr->mode == GPIO_MODE_INTERRUPT)
++ /* in Interrupt mode, ask for interrupt status bit */
++ return dal_hw_gpio_get_reg_value(
++ ptr->ctx,
++ &pin->gpiopad_int_status,
++ value);
++ else
++ /* for any mode other than Interrupt,
++ * gpio_pad operates as normal GPIO */
++ return dal_hw_gpio_get_value(ptr, value);
++}
++
++bool dal_hw_gpio_pad_construct(
++ struct hw_gpio_pad *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx)
++{
++ if (!dal_hw_gpio_construct(&pin->base, id, en, ctx))
++ return false;
++
++ pin->gpiopad_int_status.addr = 0;
++ pin->gpiopad_int_status.mask = 0;
++
++ return true;
++}
++
++void dal_hw_gpio_pad_destruct(
++ struct hw_gpio_pad *pin)
++{
++ dal_hw_gpio_destruct(&pin->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.h b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.h
+new file mode 100644
+index 0000000..34b470a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pad.h
+@@ -0,0 +1,47 @@
++/*
++ * 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_HW_GPIO_PAD_H__
++#define __DAL_HW_GPIO_PAD_H__
++
++struct hw_gpio_pad {
++ struct hw_gpio base;
++ struct addr_mask gpiopad_int_status;
++};
++
++bool dal_hw_gpio_pad_construct(
++ struct hw_gpio_pad *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx);
++
++void dal_hw_gpio_pad_destruct(
++ struct hw_gpio_pad *pin);
++
++enum gpio_result dal_hw_gpio_pad_get_value(
++ const struct hw_gpio_pin *ptr,
++ uint32_t *value);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.c
+new file mode 100644
+index 0000000..4ab1848
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.c
+@@ -0,0 +1,86 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "hw_gpio_pin.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++enum gpio_result dal_hw_gpio_pin_set_config(
++ struct hw_gpio_pin *pin,
++ const struct gpio_config_data *config_data)
++{
++ /* Attention!
++ * You must override this method in derived class */
++
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++}
++
++enum gpio_result dal_hw_gpio_pin_change_mode(
++ struct hw_gpio_pin *pin,
++ enum gpio_mode mode)
++{
++ /* Attention!
++ * You must override this method in derived class */
++
++ return GPIO_RESULT_NON_SPECIFIC_ERROR;
++}
++
++bool dal_hw_gpio_pin_construct(
++ struct hw_gpio_pin *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx)
++{
++ pin->ctx = ctx;
++ pin->id = id;
++ pin->en = en;
++ pin->mode = GPIO_MODE_UNKNOWN;
++ pin->opened = false;
++
++ return true;
++}
++
++void dal_hw_gpio_pin_destruct(
++ struct hw_gpio_pin *pin)
++{
++ ASSERT(!pin->opened);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.h b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.h
+new file mode 100644
+index 0000000..d1f2f27
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_gpio_pin.h
+@@ -0,0 +1,79 @@
++/*
++ * 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_HW_GPIO_PIN_H__
++#define __DAL_HW_GPIO_PIN_H__
++
++struct hw_gpio_pin;
++
++struct hw_gpio_pin_funcs {
++ void (*destroy)(
++ struct hw_gpio_pin **ptr);
++ bool (*open)(
++ struct hw_gpio_pin *pin,
++ enum gpio_mode mode,
++ void *options);
++ enum gpio_result (*get_value)(
++ const struct hw_gpio_pin *pin,
++ uint32_t *value);
++ enum gpio_result (*set_value)(
++ const struct hw_gpio_pin *pin,
++ uint32_t value);
++ enum gpio_result (*set_config)(
++ struct hw_gpio_pin *pin,
++ const struct gpio_config_data *config_data);
++ enum gpio_result (*change_mode)(
++ struct hw_gpio_pin *pin,
++ enum gpio_mode mode);
++ void (*close)(
++ struct hw_gpio_pin *pin);
++};
++
++struct hw_gpio_pin {
++ const struct hw_gpio_pin_funcs *funcs;
++ enum gpio_id id;
++ uint32_t en;
++ enum gpio_mode mode;
++ bool opened;
++ struct dc_context *ctx;
++};
++
++bool dal_hw_gpio_pin_construct(
++ struct hw_gpio_pin *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx);
++
++void dal_hw_gpio_pin_destruct(
++ struct hw_gpio_pin *pin);
++
++enum gpio_result dal_hw_gpio_pin_change_mode(
++ struct hw_gpio_pin *pin,
++ enum gpio_mode mode);
++
++enum gpio_result dal_hw_gpio_pin_set_config(
++ struct hw_gpio_pin *pin,
++ const struct gpio_config_data *config_data);
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.c
+new file mode 100644
+index 0000000..c09d74c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.c
+@@ -0,0 +1,88 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++#include "hw_gpio_pin.h"
++#include "hw_gpio.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "hw_hpd.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++static enum gpio_result config_mode(
++ struct hw_gpio *pin,
++ enum gpio_mode mode)
++{
++ if (mode == GPIO_MODE_INTERRUPT) {
++ /* Interrupt mode supported only by HPD (IrqGpio) pins. */
++ pin->base.mode = mode;
++
++ return dal_hw_gpio_set_reg_value(
++ pin->base.ctx,
++ &pin->pin_reg.DC_GPIO_DATA_MASK,
++ 0);
++ } else
++ /* For any mode other than Interrupt,
++ * act as normal GPIO. */
++ return dal_hw_gpio_config_mode(pin, mode);
++}
++
++const struct hw_gpio_funcs hw_hpd_func = {
++ .config_mode = config_mode,
++};
++
++bool dal_hw_hpd_construct(
++ struct hw_hpd *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx)
++{
++ if (!dal_hw_gpio_construct(&pin->base, id, en, ctx))
++ return false;
++ pin->base.funcs = &hw_hpd_func;
++ return true;
++}
++
++void dal_hw_hpd_destruct(
++ struct hw_hpd *pin)
++{
++ dal_hw_gpio_destruct(&pin->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.h b/drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.h
+new file mode 100644
+index 0000000..3fb82df
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_hpd.h
+@@ -0,0 +1,45 @@
++/*
++ * 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_HW_HPD_H__
++#define __DAL_HW_HPD_H__
++
++struct hw_hpd {
++ struct hw_gpio base;
++};
++
++#define HW_HPD_FROM_BASE(hw_gpio) \
++ container_of((HW_GPIO_FROM_BASE(hw_gpio)), struct hw_hpd, base)
++
++bool dal_hw_hpd_construct(
++ struct hw_hpd *pin,
++ enum gpio_id id,
++ uint32_t en,
++ struct dc_context *ctx);
++
++void dal_hw_hpd_destruct(
++ struct hw_hpd *pin);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
+new file mode 100644
+index 0000000..96e135f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.c
+@@ -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
++ *
++ */
++
++#include "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_types.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "hw_translate.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/hw_translate_dce110.h"
++#endif
++
++/*
++ * This unit
++ */
++
++bool dal_hw_translate_init(
++ struct hw_translate *translate,
++ enum dce_version dce_version)
++{
++ switch (dce_version) {
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ dal_hw_translate_dce110_init(translate);
++ return true;
++#endif
++ default:
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.h b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.h
+new file mode 100644
+index 0000000..d5740ac
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/hw_translate.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_HW_TRANSLATE_H__
++#define __DAL_HW_TRANSLATE_H__
++
++struct hw_translate_funcs {
++ bool (*offset_to_id)(
++ uint32_t offset,
++ uint32_t mask,
++ enum gpio_id *id,
++ uint32_t *en);
++ bool (*id_to_offset)(
++ enum gpio_id id,
++ uint32_t en,
++ struct gpio_pin_info *info);
++};
++
++struct hw_translate {
++ const struct hw_translate_funcs *funcs;
++};
++
++bool dal_hw_translate_init(
++ struct hw_translate *translate,
++ enum dce_version dce_version);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/irq.c b/drivers/gpu/drm/amd/dal/dc/gpio/irq.c
+new file mode 100644
+index 0000000..382b89f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/irq.c
+@@ -0,0 +1,181 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#include "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/gpio_interface.h"
++#include "include/irq_interface.h"
++#include "include/gpio_service_interface.h"
++#include "hw_gpio_pin.h"
++#include "hw_translate.h"
++#include "hw_factory.h"
++#include "gpio_service.h"
++#include "gpio.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "irq.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++enum gpio_result dal_irq_open(
++ struct irq *irq)
++{
++ return dal_gpio_open(irq->pin, GPIO_MODE_INTERRUPT);
++}
++
++enum gpio_result dal_irq_get_value(
++ const struct irq *irq,
++ uint32_t *value)
++{
++ return dal_gpio_get_value(irq->pin, value);
++}
++
++enum dc_irq_source dal_irq_get_source(
++ const struct irq *irq)
++{
++ enum gpio_id id = dal_gpio_get_id(irq->pin);
++
++ switch (id) {
++ case GPIO_ID_HPD:
++ return (enum dc_irq_source)(DC_IRQ_SOURCE_HPD1 +
++ dal_gpio_get_enum(irq->pin));
++ case GPIO_ID_GPIO_PAD:
++ return (enum dc_irq_source)(DC_IRQ_SOURCE_GPIOPAD0 +
++ dal_gpio_get_enum(irq->pin));
++ default:
++ return DC_IRQ_SOURCE_INVALID;
++ }
++}
++
++enum dc_irq_source dal_irq_get_rx_source(
++ const struct irq *irq)
++{
++ enum gpio_id id = dal_gpio_get_id(irq->pin);
++
++ switch (id) {
++ case GPIO_ID_HPD:
++ return (enum dc_irq_source)(DC_IRQ_SOURCE_HPD1RX +
++ dal_gpio_get_enum(irq->pin));
++ default:
++ return DC_IRQ_SOURCE_INVALID;
++ }
++}
++
++enum gpio_result dal_irq_setup_hpd_filter(
++ struct irq *irq,
++ struct gpio_hpd_config *config)
++{
++ struct gpio_config_data config_data;
++
++ if (!config)
++ return GPIO_RESULT_INVALID_DATA;
++
++ config_data.type = GPIO_CONFIG_TYPE_HPD;
++ config_data.config.hpd = *config;
++
++ return dal_gpio_set_config(irq->pin, &config_data);
++}
++
++void dal_irq_close(
++ struct irq *irq)
++{
++ dal_gpio_close(irq->pin);
++}
++
++/*
++ * @brief
++ * Creation and destruction
++ */
++
++struct irq *dal_gpio_create_irq(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en)
++{
++ struct irq *irq;
++
++ switch (id) {
++ case GPIO_ID_HPD:
++ case GPIO_ID_GPIO_PAD:
++ break;
++ default:
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ irq = dc_service_alloc(service->ctx, sizeof(struct irq));
++
++ if (!irq) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ irq->pin = dal_gpio_service_create_gpio_ex(
++ service, id, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
++ irq->ctx = service->ctx;
++
++ if (irq->pin)
++ return irq;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(service->ctx, irq);
++
++ return NULL;
++}
++
++static void destruct(struct irq *irq)
++{
++ dal_irq_close(irq);
++ dal_gpio_service_destroy_gpio(&irq->pin);
++
++}
++
++void dal_gpio_destroy_irq(
++ struct irq **irq)
++{
++ if (!irq || !*irq) {
++ ASSERT_CRITICAL(false);
++ return;
++ }
++
++ destruct(*irq);
++ dc_service_free((*irq)->ctx, *irq);
++
++ *irq = NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpio/irq.h b/drivers/gpu/drm/amd/dal/dc/gpio/irq.h
+new file mode 100644
+index 0000000..b69375c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpio/irq.h
+@@ -0,0 +1,42 @@
++/*
++ * 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_IRQ_H__
++#define __DAL_IRQ_H__
++
++struct irq {
++ struct gpio *pin;
++ struct dc_context *ctx;
++};
++
++struct irq *dal_gpio_create_irq(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en);
++
++void dal_gpio_destroy_irq(
++ struct irq **ptr);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/Makefile b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
+new file mode 100644
+index 0000000..d3d6faf
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/Makefile
+@@ -0,0 +1,26 @@
++#
++# Makefile for the 'gpu' sub-component of DAL.
++# It provides the control and status of HW adapter resources,
++# that are global for the ASIC and sharable between pipes.
++
++GPU = calc_pll_clock_source.o clock_source.o \
++dc_clock_generator.o display_clock.o divider_range.o \
++ext_clock_source.o pll_clock_source.o
++
++AMD_DAL_GPU = $(addprefix $(AMDDALPATH)/dc/gpu/,$(GPU))
++
++AMD_DAL_FILES += $(AMD_DAL_GPU)
++
++
++###############################################################################
++# DCE 110 family
++###############################################################################
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++GPU_DCE110 = display_clock_dce110.o \
++ pll_clock_source_dce110.o ext_clock_source_dce110.o \
++ vce_clock_source_dce110.o dc_clock_gating_dce110.o
++
++AMD_DAL_GPU_DCE110 = $(addprefix $(AMDDALPATH)/dc/gpu/dce110/,$(GPU_DCE110))
++
++AMD_DAL_FILES += $(AMD_DAL_GPU_DCE110)
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.c b/drivers/gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.c
+new file mode 100644
+index 0000000..7c94733
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.c
+@@ -0,0 +1,407 @@
++/* 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 "dal_services.h"
++
++#include "calc_pll_clock_source.h"
++#include "include/bios_parser_interface.h"
++#include "include/logger_interface.h"
++
++/**
++* Function: calculate_fb_and_fractional_fb_divider
++*
++* * DESCRIPTION: Calculates feedback and fractional feedback dividers values
++*
++*PARAMETERS:
++* targetPixelClock Desired frequency in 10 KHz
++* ref_divider Reference divider (already known)
++* postDivider Post Divider (already known)
++* feedback_divider_param Pointer where to store
++* calculated feedback divider value
++* fract_feedback_divider_param Pointer where to store
++* calculated fract feedback divider value
++*
++*RETURNS:
++* It fills the locations pointed by feedback_divider_param
++* and fract_feedback_divider_param
++* It returns - true if feedback divider not 0
++* - false should never happen)
++*/
++static bool calculate_fb_and_fractional_fb_divider(
++ struct calc_pll_clock_source *calc_pll_cs,
++ uint32_t target_pix_clk_khz,
++ uint32_t ref_divider,
++ uint32_t post_divider,
++ uint32_t *feedback_divider_param,
++ uint32_t *fract_feedback_divider_param)
++{
++ uint64_t feedback_divider;
++
++ feedback_divider =
++ (uint64_t)(target_pix_clk_khz * ref_divider * post_divider);
++ feedback_divider *= 10;
++ /* additional factor, since we divide by 10 afterwards */
++ feedback_divider *= (uint64_t)(calc_pll_cs->fract_fb_divider_factor);
++ feedback_divider = div_u64(feedback_divider, calc_pll_cs->ref_freq_khz);
++
++/*Round to the number of precision
++ * The following code replace the old code (ullfeedbackDivider + 5)/10
++ * for example if the difference between the number
++ * of fractional feedback decimal point and the fractional FB Divider precision
++ * is 2 then the equation becomes (ullfeedbackDivider + 5*100) / (10*100))*/
++
++ feedback_divider += (uint64_t)
++ (5 * calc_pll_cs->fract_fb_divider_precision_factor);
++ feedback_divider =
++ div_u64(feedback_divider,
++ calc_pll_cs->fract_fb_divider_precision_factor * 10);
++ feedback_divider *= (uint64_t)
++ (calc_pll_cs->fract_fb_divider_precision_factor);
++
++ *feedback_divider_param =
++ div_u64_rem(
++ feedback_divider,
++ calc_pll_cs->fract_fb_divider_factor,
++ fract_feedback_divider_param);
++
++ if (*feedback_divider_param != 0)
++ return true;
++ return false;
++}
++
++/**
++*calc_fb_divider_checking_tolerance
++*
++*DESCRIPTION: Calculates Feedback and Fractional Feedback divider values
++* for passed Reference and Post divider, checking for tolerance.
++*PARAMETERS:
++* pll_settings Pointer to structure
++* ref_divider Reference divider (already known)
++* postDivider Post Divider (already known)
++* tolerance Tolerance for Calculated Pixel Clock to be within
++*
++*RETURNS:
++* It fills the PLLSettings structure with PLL Dividers values
++* if calculated values are within required tolerance
++* It returns - true if eror is within tolerance
++* - false if eror is not within tolerance
++*/
++static bool calc_fb_divider_checking_tolerance(
++ struct calc_pll_clock_source *calc_pll_cs,
++ struct pll_settings *pll_settings,
++ uint32_t ref_divider,
++ uint32_t post_divider,
++ uint32_t tolerance)
++{
++ uint32_t feedback_divider;
++ uint32_t fract_feedback_divider;
++ uint32_t actual_calculated_clock_khz;
++ uint32_t abs_err;
++ uint64_t actual_calc_clk_khz;
++
++ calculate_fb_and_fractional_fb_divider(
++ calc_pll_cs,
++ pll_settings->adjusted_pix_clk,
++ ref_divider,
++ post_divider,
++ &feedback_divider,
++ &fract_feedback_divider);
++
++ /*Actual calculated value*/
++ actual_calc_clk_khz = (uint64_t)(feedback_divider *
++ calc_pll_cs->fract_fb_divider_factor) +
++ fract_feedback_divider;
++ actual_calc_clk_khz *= calc_pll_cs->ref_freq_khz;
++ actual_calc_clk_khz =
++ div_u64(actual_calc_clk_khz,
++ ref_divider * post_divider *
++ calc_pll_cs->fract_fb_divider_factor);
++
++ actual_calculated_clock_khz = (uint32_t)(actual_calc_clk_khz);
++
++ abs_err = (actual_calculated_clock_khz >
++ pll_settings->adjusted_pix_clk)
++ ? actual_calculated_clock_khz -
++ pll_settings->adjusted_pix_clk
++ : pll_settings->adjusted_pix_clk -
++ actual_calculated_clock_khz;
++
++ if (abs_err <= tolerance) {
++ /*found good values*/
++ pll_settings->reference_freq = calc_pll_cs->ref_freq_khz;
++ pll_settings->reference_divider = ref_divider;
++ pll_settings->feedback_divider = feedback_divider;
++ pll_settings->fract_feedback_divider = fract_feedback_divider;
++ pll_settings->pix_clk_post_divider = post_divider;
++ pll_settings->calculated_pix_clk =
++ actual_calculated_clock_khz;
++ pll_settings->vco_freq =
++ actual_calculated_clock_khz * post_divider;
++ return true;
++ }
++ return false;
++}
++
++static bool calc_pll_dividers_in_range(
++ struct calc_pll_clock_source *calc_pll_cs,
++ struct pll_settings *pll_settings,
++ uint32_t min_ref_divider,
++ uint32_t max_ref_divider,
++ uint32_t min_post_divider,
++ uint32_t max_post_divider,
++ uint32_t err_tolerance)
++{
++ uint32_t ref_divider;
++ uint32_t post_divider;
++ uint32_t tolerance;
++
++/* This is err_tolerance / 10000 = 0.0025 - acceptable error of 0.25%
++ * This is errorTolerance / 10000 = 0.0001 - acceptable error of 0.01%*/
++ tolerance = (pll_settings->adjusted_pix_clk * err_tolerance) /
++ 10000;
++ if (tolerance < CALC_PLL_CLK_SRC_ERR_TOLERANCE)
++ tolerance = CALC_PLL_CLK_SRC_ERR_TOLERANCE;
++
++ for (
++ post_divider = max_post_divider;
++ post_divider >= min_post_divider;
++ --post_divider) {
++ for (
++ ref_divider = min_ref_divider;
++ ref_divider <= max_ref_divider;
++ ++ref_divider) {
++ if (calc_fb_divider_checking_tolerance(
++ calc_pll_cs,
++ pll_settings,
++ ref_divider,
++ post_divider,
++ tolerance)) {
++ return true;
++ }
++ }
++ }
++
++ return false;
++}
++
++uint32_t dal_clock_source_calculate_pixel_clock_pll_dividers(
++ struct calc_pll_clock_source *calc_pll_cs,
++ struct pll_settings *pll_settings)
++{
++ uint32_t err_tolerance;
++ uint32_t min_post_divider;
++ uint32_t max_post_divider;
++ uint32_t min_ref_divider;
++ uint32_t max_ref_divider;
++
++ if (pll_settings->adjusted_pix_clk == 0) {
++ dal_logger_write(calc_pll_cs->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s Bad requested pixel clock", __func__);
++ return MAX_PLL_CALC_ERROR;
++ }
++
++/* 1) Find Post divider ranges */
++ if (pll_settings->pix_clk_post_divider) {
++ min_post_divider = pll_settings->pix_clk_post_divider;
++ max_post_divider = pll_settings->pix_clk_post_divider;
++ } else {
++ min_post_divider = calc_pll_cs->min_pix_clock_pll_post_divider;
++ if (min_post_divider * pll_settings->adjusted_pix_clk <
++ calc_pll_cs->min_vco_khz) {
++ min_post_divider = calc_pll_cs->min_vco_khz /
++ pll_settings->adjusted_pix_clk;
++ if ((min_post_divider *
++ pll_settings->adjusted_pix_clk) <
++ calc_pll_cs->min_vco_khz)
++ min_post_divider++;
++ }
++
++ max_post_divider = calc_pll_cs->max_pix_clock_pll_post_divider;
++ if (max_post_divider * pll_settings->adjusted_pix_clk
++ > calc_pll_cs->max_vco_khz)
++ max_post_divider = calc_pll_cs->max_vco_khz /
++ pll_settings->adjusted_pix_clk;
++ }
++
++/* 2) Find Reference divider ranges
++ * When SS is enabled, or for Display Port even without SS,
++ * pll_settings->referenceDivider is not zero.
++ * So calculate PPLL FB and fractional FB divider
++ * using the passed reference divider*/
++
++ if (pll_settings->reference_divider) {
++ min_ref_divider = pll_settings->reference_divider;
++ max_ref_divider = pll_settings->reference_divider;
++ } else {
++ min_ref_divider = ((calc_pll_cs->ref_freq_khz
++ / calc_pll_cs->max_pll_input_freq_khz)
++ > calc_pll_cs->min_pll_ref_divider)
++ ? calc_pll_cs->ref_freq_khz
++ / calc_pll_cs->max_pll_input_freq_khz
++ : calc_pll_cs->min_pll_ref_divider;
++
++ max_ref_divider = ((calc_pll_cs->ref_freq_khz
++ / calc_pll_cs->min_pll_input_freq_khz)
++ < calc_pll_cs->max_pll_ref_divider)
++ ? calc_pll_cs->ref_freq_khz /
++ calc_pll_cs->min_pll_input_freq_khz
++ : calc_pll_cs->max_pll_ref_divider;
++ }
++
++/* If some parameters are invalid we could have scenario when "min">"max"
++ * which produced endless loop later.
++ * We should investigate why we get the wrong parameters.
++ * But to follow the similar logic when "adjustedPixelClock" is set to be 0
++ * it is better to return here than cause system hang/watchdog timeout later.
++ * ## SVS Wed 15 Jul 2009 */
++
++ if (min_post_divider > max_post_divider) {
++ dal_logger_write(calc_pll_cs->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s Post divider range is invalid", __func__);
++ return MAX_PLL_CALC_ERROR;
++ }
++
++ if (min_ref_divider > max_ref_divider) {
++ dal_logger_write(calc_pll_cs->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s Reference divider range is invalid", __func__);
++ return MAX_PLL_CALC_ERROR;
++ }
++
++/* 3) Try to find PLL dividers given ranges
++ * starting with minimal error tolerance.
++ * Increase error tolerance until PLL dividers found*/
++ err_tolerance = MAX_PLL_CALC_ERROR;
++
++ while (!calc_pll_dividers_in_range(
++ calc_pll_cs,
++ pll_settings,
++ min_ref_divider,
++ max_ref_divider,
++ min_post_divider,
++ max_post_divider,
++ err_tolerance))
++ err_tolerance += (err_tolerance > 10)
++ ? (err_tolerance / 10)
++ : 1;
++
++ return err_tolerance;
++}
++
++static bool calc_pll_clock_source_max_vco_construct(
++ struct calc_pll_clock_source *calc_pll_cs,
++ struct calc_pll_clock_source_init_data *init_data)
++{
++
++ uint32_t i;
++ struct firmware_info fw_info = { { 0 } };
++ if (calc_pll_cs == NULL ||
++ init_data == NULL ||
++ init_data->bp == NULL)
++ return false;
++
++ if (dal_bios_parser_get_firmware_info(
++ init_data->bp,
++ &fw_info) != BP_RESULT_OK)
++ return false;
++
++ calc_pll_cs->ctx = init_data->ctx;
++ calc_pll_cs->ref_freq_khz = fw_info.pll_info.crystal_frequency;
++ calc_pll_cs->min_vco_khz =
++ fw_info.pll_info.min_output_pxl_clk_pll_frequency;
++ calc_pll_cs->max_vco_khz =
++ fw_info.pll_info.max_output_pxl_clk_pll_frequency;
++
++ if (init_data->max_override_input_pxl_clk_pll_freq_khz != 0)
++ calc_pll_cs->max_pll_input_freq_khz =
++ init_data->max_override_input_pxl_clk_pll_freq_khz;
++ else
++ calc_pll_cs->max_pll_input_freq_khz =
++ fw_info.pll_info.max_input_pxl_clk_pll_frequency;
++
++ if (init_data->min_override_input_pxl_clk_pll_freq_khz != 0)
++ calc_pll_cs->min_pll_input_freq_khz =
++ init_data->min_override_input_pxl_clk_pll_freq_khz;
++ else
++ calc_pll_cs->min_pll_input_freq_khz =
++ fw_info.pll_info.min_input_pxl_clk_pll_frequency;
++
++ calc_pll_cs->min_pix_clock_pll_post_divider =
++ init_data->min_pix_clk_pll_post_divider;
++ calc_pll_cs->max_pix_clock_pll_post_divider =
++ init_data->max_pix_clk_pll_post_divider;
++ calc_pll_cs->min_pll_ref_divider =
++ init_data->min_pll_ref_divider;
++ calc_pll_cs->max_pll_ref_divider =
++ init_data->max_pll_ref_divider;
++
++ if (init_data->num_fract_fb_divider_decimal_point == 0 ||
++ init_data->num_fract_fb_divider_decimal_point_precision >
++ init_data->num_fract_fb_divider_decimal_point) {
++ dal_logger_write(calc_pll_cs->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "The dec point num or precision is incorrect!");
++ return false;
++ }
++ if (init_data->num_fract_fb_divider_decimal_point_precision == 0) {
++ dal_logger_write(calc_pll_cs->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "Incorrect fract feedback divider precision num!");
++ return false;
++ }
++
++ calc_pll_cs->fract_fb_divider_decimal_points_num =
++ init_data->num_fract_fb_divider_decimal_point;
++ calc_pll_cs->fract_fb_divider_precision =
++ init_data->num_fract_fb_divider_decimal_point_precision;
++ calc_pll_cs->fract_fb_divider_factor = 1;
++ for (i = 0; i < calc_pll_cs->fract_fb_divider_decimal_points_num; ++i)
++ calc_pll_cs->fract_fb_divider_factor *= 10;
++
++ calc_pll_cs->fract_fb_divider_precision_factor = 1;
++ for (
++ i = 0;
++ i < (calc_pll_cs->fract_fb_divider_decimal_points_num -
++ calc_pll_cs->fract_fb_divider_precision);
++ ++i)
++ calc_pll_cs->fract_fb_divider_precision_factor *= 10;
++
++ return true;
++}
++
++bool dal_calc_pll_clock_source_max_vco_init(
++ struct calc_pll_clock_source *calc_pll_cs,
++ struct calc_pll_clock_source_init_data *init_data)
++{
++ return calc_pll_clock_source_max_vco_construct(
++ calc_pll_cs, init_data);
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.h b/drivers/gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.h
+new file mode 100644
+index 0000000..be44d06
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/calc_pll_clock_source.h
+@@ -0,0 +1,79 @@
++/* 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_CALC_PLL_CLOCK_SOURCE_H__
++#define __DAL_CALC_PLL_CLOCK_SOURCE_H__
++
++#include "include/clock_source_types.h"
++
++struct calc_pll_clock_source_init_data {
++ struct bios_parser *bp;
++ uint32_t min_pix_clk_pll_post_divider;
++ uint32_t max_pix_clk_pll_post_divider;
++ uint32_t min_pll_ref_divider;
++ uint32_t max_pll_ref_divider;
++ uint32_t min_override_input_pxl_clk_pll_freq_khz;
++/* if not 0, override the firmware info */
++
++ uint32_t max_override_input_pxl_clk_pll_freq_khz;
++/* if not 0, override the firmware info */
++
++ uint32_t num_fract_fb_divider_decimal_point;
++/* number of decimal point for fractional feedback divider value */
++
++ uint32_t num_fract_fb_divider_decimal_point_precision;
++/* number of decimal point to round off for fractional feedback divider value*/
++ struct dc_context *ctx;
++
++};
++#define CALC_PLL_CLK_SRC_ERR_TOLERANCE 1
++struct calc_pll_clock_source {
++ uint32_t ref_freq_khz;
++ uint32_t min_pix_clock_pll_post_divider;
++ uint32_t max_pix_clock_pll_post_divider;
++ uint32_t min_pll_ref_divider;
++ uint32_t max_pll_ref_divider;
++
++ uint32_t max_vco_khz;
++ uint32_t min_vco_khz;
++ uint32_t min_pll_input_freq_khz;
++ uint32_t max_pll_input_freq_khz;
++
++ uint32_t fract_fb_divider_decimal_points_num;
++ uint32_t fract_fb_divider_factor;
++ uint32_t fract_fb_divider_precision;
++ uint32_t fract_fb_divider_precision_factor;
++ struct dc_context *ctx;
++};
++
++
++bool dal_calc_pll_clock_source_max_vco_init(
++ struct calc_pll_clock_source *calc_pll_cs,
++ struct calc_pll_clock_source_init_data *init_data);
++
++uint32_t dal_clock_source_calculate_pixel_clock_pll_dividers(
++ struct calc_pll_clock_source *calc_pll_cs,
++ struct pll_settings *pll_settings);
++
++
++#endif /*__DAL_CALC_PLL_CLOCK_SOURCE_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/clock_source.c b/drivers/gpu/drm/amd/dal/dc/gpu/clock_source.c
+new file mode 100644
+index 0000000..8e700ea
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/clock_source.c
+@@ -0,0 +1,649 @@
++/*
++ * 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 "dal_services.h"
++
++#include "include/adapter_service_interface.h"
++#include "include/bios_parser_interface.h"
++#include "include/grph_object_id.h"
++#include "include/clock_source_interface.h"
++#include "include/logger_interface.h"
++
++#include "clock_source.h"
++#include "pll_clock_source.h"
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/ext_clock_source_dce110.h"
++#include "dce110/pll_clock_source_dce110.h"
++#include "dce110/vce_clock_source_dce110.h"
++#endif
++
++
++struct clock_source *dal_clock_source_create(
++ struct clock_source_init_data *clk_src_init_data)
++{
++ enum dce_version dce_ver =
++ dal_adapter_service_get_dce_version(clk_src_init_data->as);
++ enum clock_source_id clk_src_id =
++ dal_graphics_object_id_get_clock_source_id(
++ clk_src_init_data->clk_src_id);
++ switch (dce_ver) {
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ break;
++ case DCE_VERSION_11_0:
++ {
++ switch (clk_src_id) {
++ case CLOCK_SOURCE_ID_PLL0:
++ /* fall through */
++ case CLOCK_SOURCE_ID_PLL1:
++ /* fall through */
++ case CLOCK_SOURCE_ID_PLL2:
++ return dal_pll_clock_source_dce110_create(
++ clk_src_init_data);
++ case CLOCK_SOURCE_ID_EXTERNAL:
++ return dal_ext_clock_source_dce110_create(
++ clk_src_init_data);
++ case CLOCK_SOURCE_ID_VCE:
++ return dal_vce_clock_source_dce110_create(
++ clk_src_init_data);
++ default:
++ return NULL;
++ }
++ }
++ break;
++#endif
++ default:
++ dal_logger_write(clk_src_init_data->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "Clock Source (id %d): not supported DCE version %d",
++ clk_src_id,
++ dce_ver);
++ ASSERT_CRITICAL(false);
++ break;
++ }
++ return NULL;
++}
++
++const struct spread_spectrum_data *dal_clock_source_get_ss_data_entry(
++ struct clock_source *clk_src,
++ enum signal_type signal,
++ uint32_t pix_clk_khz)
++{
++
++ uint32_t entrys_num;
++ uint32_t i;
++ struct spread_spectrum_data *ss_parm = NULL;
++ struct spread_spectrum_data *ret = NULL;
++
++ switch (signal) {
++ case SIGNAL_TYPE_DVI_SINGLE_LINK:
++ case SIGNAL_TYPE_DVI_DUAL_LINK:
++ ss_parm = clk_src->dvi_ss_params;
++ entrys_num = clk_src->dvi_ss_params_cnt;
++ break;
++
++ case SIGNAL_TYPE_HDMI_TYPE_A:
++ ss_parm = clk_src->hdmi_ss_params;
++ entrys_num = clk_src->hdmi_ss_params_cnt;
++ break;
++
++ case SIGNAL_TYPE_LVDS:
++ ss_parm = clk_src->ep_ss_params;
++ entrys_num = clk_src->ep_ss_params_cnt;
++ break;
++
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ ss_parm = clk_src->dp_ss_params;
++ entrys_num = clk_src->dp_ss_params_cnt;
++ break;
++
++ default:
++ ss_parm = NULL;
++ entrys_num = 0;
++ break;
++ }
++
++ if (ss_parm == NULL)
++ return ret;
++
++ for (i = 0; i < entrys_num; ++i, ++ss_parm) {
++ if (ss_parm->freq_range_khz >= pix_clk_khz) {
++ ret = ss_parm;
++ break;
++ }
++ }
++
++ return ret;
++}
++
++bool dal_clock_source_base_adjust_dto_pix_rate(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t requested_pix_clk_hz)
++{
++ return false;
++}
++
++/* Adjust clock to match given pixel rate (SS/DeepColor compensated)*/
++bool dal_clock_source_base_adjust_pll_pixel_rate(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t requestedPixelClockInHz)
++{
++ return false;
++}
++
++static uint32_t retrieve_raw_pix_rate_hz(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params)
++{
++ if (dc_is_dp_signal(pix_clk_params->signal_type))
++ return clk_src->funcs->retrieve_dto_pix_rate_hz(
++ clk_src,
++ pix_clk_params);
++ else
++ return clk_src->funcs->retrieve_pll_pix_rate_hz(
++ clk_src,
++ pix_clk_params);
++}
++
++
++
++bool dal_clock_source_adjust_pxl_clk_by_pxl_amount(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ int32_t pix_num)
++{
++
++ uint32_t cur_pix_rate_hz;
++ uint32_t reqested_pix_rate_hz;
++ bool success = false;
++
++ if (pix_clk_params == NULL)
++ return false;
++
++ cur_pix_rate_hz = retrieve_raw_pix_rate_hz(clk_src, pix_clk_params);
++ reqested_pix_rate_hz = cur_pix_rate_hz + pix_num;
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "%s[start]: Current(Raw): %u,%03u,%03uHz, Requested(Raw): %u,%03u,%03uHz\n",
++ __func__,
++ (cur_pix_rate_hz / 1000000),
++ (cur_pix_rate_hz / 1000) % 1000,
++ (cur_pix_rate_hz % 1000),
++ (reqested_pix_rate_hz / 1000000),
++ (reqested_pix_rate_hz / 1000) % 1000,
++ (reqested_pix_rate_hz % 1000));
++
++ if (dc_is_dp_signal(pix_clk_params->signal_type))
++ success = clk_src->funcs->adjust_dto_pixel_rate(clk_src,
++ pix_clk_params,
++ reqested_pix_rate_hz);
++ else
++ success = clk_src->funcs->adjust_pll_pixel_rate(
++ clk_src,
++ pix_clk_params,
++ reqested_pix_rate_hz);
++
++ cur_pix_rate_hz = retrieve_raw_pix_rate_hz(clk_src, pix_clk_params);
++
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "%s[end]: Current(Raw): %u,%03u,%03uHz, Requested(Raw): %u,%03u,%03uHz\n\n",
++ __func__,
++ (cur_pix_rate_hz / 1000000),
++ (cur_pix_rate_hz / 1000) % 1000,
++ (cur_pix_rate_hz % 1000),
++ (reqested_pix_rate_hz / 1000000),
++ (reqested_pix_rate_hz / 1000) % 1000,
++ (reqested_pix_rate_hz % 1000));
++
++ return success;
++}
++
++/***************************/
++/* private methods section */
++/***************************/
++
++void dal_clock_source_get_ss_info_from_atombios(
++ struct clock_source *clk_src,
++ enum as_signal_type as_signal,
++ struct spread_spectrum_data *spread_spectrum_data[],
++ uint32_t *ss_entries_num)
++{
++ enum bp_result bp_result = BP_RESULT_FAILURE;
++ struct spread_spectrum_info *ss_info;
++ struct spread_spectrum_data *ss_data;
++ struct spread_spectrum_info *ss_info_cur;
++ struct spread_spectrum_data *ss_data_cur;
++ uint32_t i;
++
++ if (ss_entries_num == NULL) {
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "Invalid entry !!!\n");
++ return;
++ }
++ if (spread_spectrum_data == NULL) {
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "Invalid array pointer!!!\n");
++ return;
++ }
++
++ spread_spectrum_data[0] = NULL;
++ *ss_entries_num = 0;
++
++ *ss_entries_num = dal_bios_parser_get_ss_entry_number(
++ clk_src->bios_parser,
++ as_signal);
++ if (*ss_entries_num == 0)
++ return;
++
++ ss_info = dc_service_alloc(clk_src->ctx, sizeof(struct spread_spectrum_info)
++ * (*ss_entries_num));
++ ss_info_cur = ss_info;
++ if (ss_info == NULL)
++ return;
++
++ ss_data = dc_service_alloc(clk_src->ctx, sizeof(struct spread_spectrum_data) *
++ (*ss_entries_num));
++ if (ss_data == NULL)
++ goto out_free_info;
++
++ for (i = 0, ss_info_cur = ss_info;
++ i < (*ss_entries_num);
++ ++i, ++ss_info_cur) {
++ bp_result = dal_bios_parser_get_spread_spectrum_info(
++ clk_src->bios_parser,
++ as_signal,
++ i,
++ ss_info_cur);
++ if (bp_result != BP_RESULT_OK)
++ goto out_free_data;
++ }
++
++ for (i = 0, ss_info_cur = ss_info, ss_data_cur = ss_data;
++ i < (*ss_entries_num);
++ ++i, ++ss_info_cur, ++ss_data_cur) {
++
++ if (ss_info_cur->type.STEP_AND_DELAY_INFO != false) {
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "Invalid ATOMBIOS SS Table!!!\n");
++ goto out_free_data;
++ }
++
++ /* for HDMI check SS percentage,
++ * if it is > 6 (0.06%), the ATOMBIOS table info is invalid*/
++ if (as_signal == AS_SIGNAL_TYPE_HDMI
++ && ss_info_cur->spread_spectrum_percentage > 6){
++ /* invalid input, do nothing */
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "Invalid SS percentage ");
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "for HDMI in ATOMBIOS info Table!!!\n");
++ continue;
++ }
++ if (ss_info_cur->spread_percentage_divider == 1000) {
++ /* Keep previous precision from ATOMBIOS for these
++ * in case new precision set by ATOMBIOS for these
++ * (otherwise all code in DCE specific classes
++ * for all previous ASICs would need
++ * to be updated for SS calculations,
++ * Audio SS compensation and DP DTO SS compensation
++ * which assumes fixed SS percentage Divider = 100)*/
++ ss_info_cur->spread_spectrum_percentage /= 10;
++ ss_info_cur->spread_percentage_divider = 100;
++ }
++
++ ss_data_cur->freq_range_khz = ss_info_cur->target_clock_range;
++ ss_data_cur->percentage =
++ ss_info_cur->spread_spectrum_percentage;
++ ss_data_cur->percentage_divider =
++ ss_info_cur->spread_percentage_divider;
++ ss_data_cur->modulation_freq_hz =
++ ss_info_cur->spread_spectrum_range;
++
++ if (ss_info_cur->type.CENTER_MODE)
++ ss_data_cur->flags.CENTER_SPREAD = 1;
++
++ if (ss_info_cur->type.EXTERNAL)
++ ss_data_cur->flags.EXTERNAL_SS = 1;
++
++ }
++
++ *spread_spectrum_data = ss_data;
++ dc_service_free(clk_src->ctx, ss_info);
++ return;
++
++out_free_data:
++ dc_service_free(clk_src->ctx, ss_data);
++ *ss_entries_num = 0;
++out_free_info:
++ dc_service_free(clk_src->ctx, ss_info);
++}
++
++uint32_t dal_clock_source_base_retrieve_dto_pix_rate_hz(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params)
++{
++ return 0;
++}
++
++
++uint32_t dal_clock_source_base_retrieve_pll_pix_rate_hz(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params)
++{
++ return 0;
++}
++
++/*****************************/
++/* interface methods section */
++/*****************************/
++
++enum clock_source_id dal_clock_source_get_id(
++ const struct clock_source *clk_src)
++{
++ return clk_src->clk_src_id;
++}
++
++bool dal_clock_source_is_clk_src_with_fixed_freq(
++ const struct clock_source *clk_src)
++{
++ return clk_src->is_clock_source_with_fixed_freq;
++}
++
++const struct graphics_object_id dal_clock_source_get_graphics_object_id(
++ const struct clock_source *clk_src)
++{
++ return clk_src->id;
++}
++
++enum clock_sharing_level dal_clock_souce_get_clk_sharing_lvl(
++ const struct clock_source *clk_src)
++{
++ return clk_src->clk_sharing_lvl;
++}
++
++uint32_t dal_clock_source_get_pix_clk_dividers(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ return clk_src->funcs->
++ get_pix_clk_dividers(clk_src, pix_clk_params, pll_settings);
++}
++
++bool dal_clock_source_program_pix_clk(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ return clk_src->funcs->
++ program_pix_clk(clk_src, pix_clk_params, pll_settings);
++}
++
++/* TODO save/restore FP was here */
++bool dal_clock_source_adjust_pxl_clk_by_ref_pixel_rate(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t pix_rate_hz)
++{
++ uint32_t current_pix_rate_hz = 0;
++ uint32_t raw_cur_pix_rate_hz = 0;
++ uint32_t raw_pix_rate_hz = pix_rate_hz;
++ bool success = false;
++
++ if (pix_clk_params == NULL || pix_rate_hz == 0)
++ return false;
++
++ current_pix_rate_hz = retrieve_raw_pix_rate_hz(
++ clk_src,
++ pix_clk_params);
++ raw_cur_pix_rate_hz = current_pix_rate_hz;
++
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "%s[start]: Current: %u,%03u,%03uHz, Requested: %u,%03u,%03uHz\n",
++ __func__,
++ (current_pix_rate_hz / 1000000),
++ (current_pix_rate_hz / 1000) % 1000,
++ (current_pix_rate_hz % 1000),
++ (pix_rate_hz / 1000000),
++ (pix_rate_hz / 1000) % 1000,
++ (pix_rate_hz % 1000));
++
++ if (dc_is_dp_signal(pix_clk_params->signal_type))
++ success = clk_src->funcs->adjust_dto_pixel_rate(
++ clk_src,
++ pix_clk_params,
++ raw_pix_rate_hz);
++ else
++ success = clk_src->funcs->adjust_pll_pixel_rate(
++ clk_src,
++ pix_clk_params,
++ raw_pix_rate_hz);
++
++ if (dc_is_dp_signal(pix_clk_params->signal_type))
++ raw_cur_pix_rate_hz = clk_src->funcs->
++ retrieve_dto_pix_rate_hz(
++ clk_src,
++ pix_clk_params);
++ else
++ raw_cur_pix_rate_hz = clk_src->funcs->
++ retrieve_pll_pix_rate_hz(
++ clk_src,
++ pix_clk_params);
++
++ current_pix_rate_hz = raw_cur_pix_rate_hz;
++
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "%s[end]: Current: %u,%03u,%03uHz, Requested: %u,%03u,%03uHz\n",
++ __func__,
++ (current_pix_rate_hz / 1000000),
++ (current_pix_rate_hz / 1000) % 1000,
++ (current_pix_rate_hz % 1000),
++ (pix_rate_hz / 1000000),
++ (pix_rate_hz / 1000) % 1000,
++ (pix_rate_hz % 1000));
++
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "%s[end]: Current(Raw): %u,%03u,%03uHz, Requested(Raw): %u,%03u,%03uHz\n\n",
++ __func__,
++ (raw_cur_pix_rate_hz / 1000000),
++ (raw_cur_pix_rate_hz / 1000) % 1000,
++ (raw_cur_pix_rate_hz % 1000),
++ (raw_pix_rate_hz / 1000000),
++ (raw_pix_rate_hz / 1000) % 1000,
++ (raw_pix_rate_hz % 1000));
++
++ return success;
++}
++
++/* TODO store/restore FP was here*/
++bool dal_clock_source_adjust_pxl_clk_by_pix_amount(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ int32_t pix_num)
++{
++ bool success = false;
++ uint32_t requested_pix_rate_hz;
++ uint32_t cur_pix_rate_hz = retrieve_raw_pix_rate_hz(
++ clk_src,
++ pix_clk_params);
++ requested_pix_rate_hz = cur_pix_rate_hz + pix_num;
++
++ if (pix_clk_params == NULL)
++ return false;
++
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "%s[start]: Current(Raw): %u,%03u,%03uHz, Requested(Raw): %u,%03u,%03uHz\n",
++ __func__,
++ (cur_pix_rate_hz / 1000000),
++ (cur_pix_rate_hz / 1000) % 1000,
++ (cur_pix_rate_hz % 1000),
++ (requested_pix_rate_hz / 1000000),
++ (requested_pix_rate_hz / 1000) % 1000,
++ (requested_pix_rate_hz % 1000));
++
++ if (dc_is_dp_signal(pix_clk_params->signal_type))
++ success = clk_src->funcs->adjust_dto_pixel_rate(
++ clk_src,
++ pix_clk_params,
++ requested_pix_rate_hz);
++ else
++ success = clk_src->funcs->adjust_pll_pixel_rate(
++ clk_src,
++ pix_clk_params,
++ requested_pix_rate_hz);
++
++ cur_pix_rate_hz = retrieve_raw_pix_rate_hz(clk_src, pix_clk_params);
++
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_SYNC,
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST,
++ "%s[end]: Current(Raw): %u,%03u,%03uHz,Requested(Raw): %u,%03u,%03uHz\n\n",
++ __func__,
++ (cur_pix_rate_hz / 1000000),
++ (cur_pix_rate_hz / 1000) % 1000,
++ (cur_pix_rate_hz % 1000),
++ (requested_pix_rate_hz / 1000000),
++ (requested_pix_rate_hz / 1000) % 1000,
++ (requested_pix_rate_hz % 1000));
++
++ return success;
++}
++
++/* TODO save/restore FP was here*/
++uint32_t dal_clock_source_retrieve_pix_rate_hz(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params)
++{
++ uint32_t pixel_rate_hz = 0;
++
++ if (pix_clk_params == NULL)
++ return pixel_rate_hz;
++
++ if (dc_is_dp_signal(pix_clk_params->signal_type))
++ pixel_rate_hz = clk_src->funcs->retrieve_dto_pix_rate_hz(
++ clk_src,
++ pix_clk_params);
++ else
++ pixel_rate_hz = clk_src->funcs->retrieve_pll_pix_rate_hz(
++ clk_src,
++ pix_clk_params);
++
++
++ return pixel_rate_hz;
++}
++
++bool dal_clock_source_construct(
++ struct clock_source *clk_src,
++ struct clock_source_init_data *clk_src_init_data)
++{
++ if (clk_src_init_data == NULL || clk_src_init_data->as == NULL)
++ return false;
++ clk_src->ctx = clk_src_init_data->ctx;
++ clk_src->id = clk_src_init_data->clk_src_id;
++ clk_src->adapter_service = clk_src_init_data->as;
++ clk_src->bios_parser = dal_adapter_service_get_bios_parser(
++ clk_src_init_data->as);
++ clk_src->turn_off_ds = false;
++ clk_src->clk_src_id = dal_graphics_object_id_get_clock_source_id(
++ clk_src_init_data->clk_src_id);
++ clk_src->is_gen_lock_capable = true;
++/*NOTE is_gen_lock_capable is false only for ext clock source dce80 */
++
++ clk_src->ep_ss_params = NULL;
++ clk_src->dp_ss_params = NULL;
++ clk_src->hdmi_ss_params = NULL;
++ clk_src->hdmi_ss_params = NULL;
++ clk_src->ep_ss_params_cnt = 0;
++ clk_src->dp_ss_params_cnt = 0;
++ clk_src->hdmi_ss_params_cnt = 0;
++ clk_src->dvi_ss_params_cnt = 0;
++ clk_src->output_signals = SIGNAL_TYPE_ALL;
++ clk_src->input_signals = SIGNAL_TYPE_ALL;
++
++ return true;
++}
++
++void dal_clock_source_destroy(struct clock_source **clk_src)
++{
++ if (!clk_src || !(*clk_src))
++ return;
++
++ (*clk_src)->funcs->destroy(clk_src);
++
++ *clk_src = NULL;
++}
++
++bool dal_clock_source_is_input_signal_supported(
++ struct clock_source *clk_src,
++ enum signal_type signal_type)
++{
++ /* TODO do we need this in clock_source ?? */
++ return (clk_src->input_signals & signal_type) != 0;
++}
++
++bool dal_clock_source_is_output_signal_supported(
++ const struct clock_source *clk_src,
++ enum signal_type signal_type)
++{
++ return (clk_src->output_signals & signal_type) != 0;
++}
++
++bool dal_clock_source_is_gen_lock_capable(struct clock_source *clk_src)
++{
++ return clk_src->is_gen_lock_capable;
++}
++
++bool dal_clock_source_power_down_pll(struct clock_source *clk_src,
++ enum controller_id controller_id)
++{
++ return clk_src->funcs->power_down_pll(clk_src, controller_id);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/clock_source.h b/drivers/gpu/drm/amd/dal/dc/gpu/clock_source.h
+new file mode 100644
+index 0000000..0a83874
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/clock_source.h
+@@ -0,0 +1,136 @@
++/*
++ * 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_CLOCK_SOURCE_H__
++#define __DAL_CLOCK_SOURCE_H__
++
++#include "include/adapter_service_types.h"
++#include "include/bios_parser_types.h"
++#include "include/clock_source_interface.h"
++#include "include/clock_source_types.h"
++
++struct spread_spectrum_data {
++ uint32_t percentage; /*> In unit of 0.01% or 0.001%*/
++ uint32_t percentage_divider; /*> 100 or 1000 */
++ uint32_t freq_range_khz;
++ uint32_t modulation_freq_hz;
++
++ struct spread_spectrum_flags flags;
++};
++
++struct clock_source_impl {
++ bool (*switch_dp_clock_source)(
++ struct clock_source *clk_src,
++ enum controller_id,
++ enum clock_source_id);
++ bool (*adjust_pll_pixel_rate)(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t requested_pix_clk_hz);
++ bool (*adjust_dto_pixel_rate)(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t requested_clk_freq_hz);
++ uint32_t (*retrieve_dto_pix_rate_hz)(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params);
++ uint32_t (*retrieve_pll_pix_rate_hz)(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params);
++
++ uint32_t (*get_pix_clk_dividers)(struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings);
++ bool (*program_pix_clk)(struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings);
++ bool (*power_down_pll)(struct clock_source *clk_src,
++ enum controller_id);
++ void (*destroy)(struct clock_source **clk_src);
++};
++
++void dal_clock_source_get_ss_info_from_atombios(
++ struct clock_source *clk_src,
++ enum as_signal_type as_signal,
++ struct spread_spectrum_data *ss_data[],
++ uint32_t *ss_entries_num);
++uint32_t dal_clock_source_base_retrieve_dto_pix_rate_hz(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params);
++const struct spread_spectrum_data *dal_clock_source_get_ss_data_entry(
++ struct clock_source *clk_src,
++ enum signal_type signal,
++ uint32_t pix_clk_khz);
++/* for PLL and EXT clock sources */
++struct registers {
++ uint32_t dp_dtox_phase;
++ uint32_t dp_dtox_modulo;
++ uint32_t crtcx_pixel_rate_cntl;
++};
++
++struct clock_source {
++ const struct clock_source_impl *funcs;
++ struct graphics_object_id id;
++ enum clock_source_id clk_src_id;
++ struct adapter_service *adapter_service;
++ struct bios_parser *bios_parser;
++
++ struct spread_spectrum_data *ep_ss_params;
++ uint32_t ep_ss_params_cnt;
++ struct spread_spectrum_data *dp_ss_params;
++ uint32_t dp_ss_params_cnt;
++
++ struct spread_spectrum_data *hdmi_ss_params;
++ uint32_t hdmi_ss_params_cnt;
++
++ struct spread_spectrum_data *dvi_ss_params;
++ uint32_t dvi_ss_params_cnt;
++
++ uint32_t output_signals;
++ uint32_t input_signals;
++
++ bool turn_off_ds;
++ bool is_gen_lock_capable; /*replacement for virtual method*/
++ bool is_clock_source_with_fixed_freq; /*replacement for virtual method*/
++ enum clock_sharing_level clk_sharing_lvl;
++ struct dc_context *ctx;
++};
++
++bool dal_clock_source_construct(
++ struct clock_source *clk_src,
++ struct clock_source_init_data *clk_src_init_data);
++bool dal_clock_source_base_adjust_pll_pixel_rate(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t requested_pix_clk_hz);
++bool dal_clock_source_base_adjust_dto_pix_rate(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t requested_pix_clk_hz);
++uint32_t dal_clock_source_base_retrieve_pll_pix_rate_hz(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c b/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c
+new file mode 100644
+index 0000000..f124dba
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.c
+@@ -0,0 +1,92 @@
++/*
++ * 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 "dal_services.h"
++
++#include "dc_clock_generator.h"
++
++void dal_dc_clock_generator_destroy(struct dc_clock_generator **dc)
++{
++ if (dc == NULL || *dc == NULL) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ (*dc)->funcs->destroy(dc);
++
++ *dc = NULL;
++}
++
++void dal_dc_clock_generator_set_display_pipe_mapping(
++ struct dc_clock_generator *dc_clk_gen,
++ struct dccg_mapping_params *params)
++{
++ dc_clk_gen->funcs->set_display_pipe_mapping(dc_clk_gen, params);
++}
++
++bool dal_dc_clock_generator_get_dp_ref_clk_ds_params(
++ struct dc_clock_generator *dc_clk_gen,
++ struct dccg_dp_ref_clk_ds_params *params)
++{
++ return dc_clk_gen->funcs->get_dp_ref_clk_ds_params(dc_clk_gen, params);
++}
++
++bool dal_dc_clock_generator_enable_gtc_counter(
++ struct dc_clock_generator *dc_clk_gen,
++ uint32_t dprefclk)
++{
++ return dc_clk_gen->funcs->enable_gtc_counter(dc_clk_gen, dprefclk);
++}
++
++void dal_dc_clock_generator_disable_gtc_counter(
++ struct dc_clock_generator *dc_clk_gen)
++{
++ dc_clk_gen->funcs->disable_gtc_counter(dc_clk_gen);
++}
++
++void dal_dc_clock_generator_set_gtc_group_offset(
++ struct dc_clock_generator *dc_clk_gen,
++ enum gtc_group group_num,
++ uint32_t offset)
++{
++ dc_clk_gen->funcs->set_gtc_group_offset(dc_clk_gen, group_num, offset);
++}
++
++void dal_dc_clock_generator_base_set_display_pipe_mapping(
++ struct dc_clock_generator *base,
++ struct dccg_mapping_params *params)
++{
++
++}
++
++bool dal_dc_clock_generator_construct_base(
++ struct dc_clock_generator *base,
++ struct dc_context *ctx
++)
++{
++ base->ctx = ctx;
++ return true;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h b/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h
+new file mode 100644
+index 0000000..d1bf1af
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dc_clock_generator.h
+@@ -0,0 +1,63 @@
++/*
++ * 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_DC_CLOCK_GENERATOR_H__
++#define __DAL_DC_CLOCK_GENERATOR_H__
++
++#include "include/dc_clock_generator_interface.h"
++
++struct dc_clock_generator_funcs {
++ void (*destroy)(struct dc_clock_generator **to_destroy);
++
++ void (*set_display_pipe_mapping)(
++ struct dc_clock_generator *dc_clk_gen,
++ struct dccg_mapping_params *params);
++
++ bool (*get_dp_ref_clk_ds_params)(
++ struct dc_clock_generator *dc_clk_gen,
++ struct dccg_dp_ref_clk_ds_params *params);
++ bool (*enable_gtc_counter)(
++ struct dc_clock_generator *dc_clk_gen,
++ uint32_t dprefclk);
++ void (*disable_gtc_counter)(
++ struct dc_clock_generator *dc_clk_gen);
++ void (*set_gtc_group_offset)(
++ struct dc_clock_generator *dc_clk_gen,
++ enum gtc_group group_num,
++ uint32_t offset);
++};
++struct dc_clock_generator {
++ const struct dc_clock_generator_funcs *funcs;
++ struct dc_context *ctx;
++};
++bool dal_dc_clock_generator_construct_base(
++ struct dc_clock_generator *base,
++ struct dc_context *ctx
++);
++void dal_dc_clock_generator_base_set_display_pipe_mapping(
++ struct dc_clock_generator *base,
++ struct dccg_mapping_params *params);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c
+new file mode 100644
+index 0000000..e2d4228
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.c
+@@ -0,0 +1,90 @@
++/*
++ * 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 "dal_services.h"
++
++#include "include/logger_interface.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++#include "dc_clock_gating_dce110.h"
++
++/******************************************************************************
++ * Macro definitions
++ *****************************************************************************/
++
++#define NOT_IMPLEMENTED() DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_GPU, \
++ "%s:%s()\n", __FILE__, __func__)
++
++/******************************************************************************
++ * static functions
++ *****************************************************************************/
++static void force_hw_base_light_sleep(struct dc_context *ctx)
++{
++ uint32_t addr = 0;
++ uint32_t value = 0;
++
++
++ addr = mmDC_MEM_GLOBAL_PWR_REQ_CNTL;
++ /* Read the mmDC_MEM_GLOBAL_PWR_REQ_CNTL to get the currently
++ * programmed DC_MEM_GLOBAL_PWR_REQ_DIS*/
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_MEM_GLOBAL_PWR_REQ_CNTL,
++ DC_MEM_GLOBAL_PWR_REQ_DIS);
++
++ dal_write_reg(ctx, addr, value);
++
++}
++
++static void enable_hw_base_light_sleep(struct dc_context *ctx)
++{
++ NOT_IMPLEMENTED();
++}
++
++static void disable_sw_manual_control_light_sleep(
++ struct dc_context *ctx)
++{
++ NOT_IMPLEMENTED();
++}
++
++/******************************************************************************
++ * public functions
++ *****************************************************************************/
++
++void dal_dc_clock_gating_dce110_power_up(
++ struct dc_context *ctx,
++ bool enable)
++{
++ if (enable) {
++ enable_hw_base_light_sleep(ctx);
++ disable_sw_manual_control_light_sleep(ctx);
++ } else {
++ force_hw_base_light_sleep(ctx);
++ }
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h
+new file mode 100644
+index 0000000..1bfd75a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/dc_clock_gating_dce110.h
+@@ -0,0 +1,33 @@
++/*
++ * 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_DC_CLOCK_GATING_DCE110_H__
++#define __DAL_DC_CLOCK_GATING_DCE110_H__
++
++void dal_dc_clock_gating_dce110_power_up(
++ struct dc_context *ctx,
++ bool enable);
++
++#endif /* __DAL_DC_CLOCK_GATING_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.c
+new file mode 100644
+index 0000000..e582ba0
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.c
+@@ -0,0 +1,958 @@
++/*
++ * 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 "dal_services.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "include/adapter_service_interface.h"
++#include "include/bios_parser_interface.h"
++#include "include/fixed32_32.h"
++#include "include/logger_interface.h"
++
++#include "../divider_range.h"
++
++#include "display_clock_dce110.h"
++
++#define FROM_DISPLAY_CLOCK(base) \
++ container_of(base, struct display_clock_dce110, disp_clk_base)
++
++static struct state_dependent_clocks max_clks_by_state[] = {
++/*( dvo not exist in KV)*/
++/*ClocksStateInvalid - should not be used*/
++{ .display_clk_khz = 0, .pixel_clk_khz = 0, .dvo_clk_khz = 0 },
++/*ClocksStateUltraLow - currently by HW design team not supposed to be used*/
++{ .display_clk_khz = 352000, .pixel_clk_khz = 330000, .dvo_clk_khz = 0 },
++/*ClocksStateLow*/
++{ .display_clk_khz = 352000, .pixel_clk_khz = 330000, .dvo_clk_khz = 0 },
++/*ClocksStateNominal*/
++{ .display_clk_khz = 467000, .pixel_clk_khz = 400000, .dvo_clk_khz = 0 },
++/*ClocksStatePerformance*/
++{ .display_clk_khz = 643000, .pixel_clk_khz = 400000, .dvo_clk_khz = 0 } };
++
++
++/* Starting point for each divider range.*/
++enum divider_range_start {
++ DIVIDER_RANGE_01_START = 200, /* 2.00*/
++ DIVIDER_RANGE_02_START = 1600, /* 16.00*/
++ DIVIDER_RANGE_03_START = 3200, /* 32.00*/
++ DIVIDER_RANGE_SCALE_FACTOR = 100 /* Results are scaled up by 100.*/
++};
++
++/* Array identifiers and count for the divider ranges.*/
++enum divider_range_count {
++ DIVIDER_RANGE_01 = 0,
++ DIVIDER_RANGE_02,
++ DIVIDER_RANGE_03,
++ DIVIDER_RANGE_MAX /* == 3*/
++};
++
++/* Ranges for divider identifiers (Divider ID or DID)
++ mmDENTIST_DISPCLK_CNTL.DENTIST_DISPCLK_WDIVIDER*/
++enum divider_id_register_setting {
++ DIVIDER_RANGE_01_BASE_DIVIDER_ID = 0X08,
++ DIVIDER_RANGE_02_BASE_DIVIDER_ID = 0X40,
++ DIVIDER_RANGE_03_BASE_DIVIDER_ID = 0X60,
++ DIVIDER_RANGE_MAX_DIVIDER_ID = 0X80
++};
++
++/* Step size between each divider within a range.
++ Incrementing the DENTIST_DISPCLK_WDIVIDER by one
++ will increment the divider by this much.*/
++enum divider_range_step_size {
++ DIVIDER_RANGE_01_STEP_SIZE = 25, /* 0.25*/
++ DIVIDER_RANGE_02_STEP_SIZE = 50, /* 0.50*/
++ DIVIDER_RANGE_03_STEP_SIZE = 100 /* 1.00 */
++};
++
++static struct divider_range divider_ranges[DIVIDER_RANGE_MAX];
++
++#define DCE110_DFS_BYPASS_THRESHOLD_KHZ 400000
++/*****************************************************************************
++ * static functions
++ *****************************************************************************/
++
++/*
++ * store_max_clocks_state
++ *
++ * @brief
++ * Cache the clock state
++ *
++ * @param
++ * struct display_clock *base - [out] cach the state in this structure
++ * enum clocks_state max_clocks_state - [in] state to be stored
++ */
++static void store_max_clocks_state(
++ struct display_clock *base,
++ enum clocks_state max_clocks_state)
++{
++ struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base);
++
++ switch (max_clocks_state) {
++ case CLOCKS_STATE_LOW:
++ case CLOCKS_STATE_NOMINAL:
++ case CLOCKS_STATE_PERFORMANCE:
++ case CLOCKS_STATE_ULTRA_LOW:
++ dc->max_clks_state = max_clocks_state;
++ break;
++
++ case CLOCKS_STATE_INVALID:
++ default:
++ /*Invalid Clocks State!*/
++ ASSERT_CRITICAL(false);
++ break;
++ }
++}
++
++static enum clocks_state get_min_clocks_state(struct display_clock *base)
++{
++ return base->cur_min_clks_state;
++}
++
++static bool set_min_clocks_state(
++ struct display_clock *base,
++ enum clocks_state clocks_state)
++{
++ struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base);
++
++ if (clocks_state > dc->max_clks_state) {
++ /*Requested state exceeds max supported state.*/
++ dal_logger_write(base->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "Requested state exceeds max supported state");
++ return false;
++ } else if (clocks_state == base->cur_min_clks_state) {
++ /*if we're trying to set the same state, we can just return
++ * since nothing needs to be done*/
++ return true;
++ }
++
++ base->cur_min_clks_state = clocks_state;
++
++ return true;
++}
++
++static uint32_t get_dp_ref_clk_frequency(struct display_clock *dc)
++{
++ uint32_t dispclk_cntl_value;
++ uint32_t dp_ref_clk_cntl_value;
++ uint32_t dp_ref_clk_cntl_src_sel_value;
++ uint32_t dp_ref_clk_khz = 600000;
++ uint32_t target_div = INVALID_DIVIDER;
++ struct display_clock_dce110 *disp_clk = FROM_DISPLAY_CLOCK(dc);
++
++ /* ASSERT DP Reference Clock source is from DFS*/
++ dp_ref_clk_cntl_value = dal_read_reg(dc->ctx,
++ mmDPREFCLK_CNTL);
++
++ dp_ref_clk_cntl_src_sel_value =
++ get_reg_field_value(
++ dp_ref_clk_cntl_value,
++ DPREFCLK_CNTL, DPREFCLK_SRC_SEL);
++
++ ASSERT(dp_ref_clk_cntl_src_sel_value == 0);
++
++ /* Read the mmDENTIST_DISPCLK_CNTL to get the currently
++ * programmed DID DENTIST_DPREFCLK_WDIVIDER*/
++ dispclk_cntl_value = dal_read_reg(dc->ctx,
++ mmDENTIST_DISPCLK_CNTL);
++
++ /* Convert DENTIST_DPREFCLK_WDIVIDERto actual divider*/
++ target_div = dal_divider_range_get_divider(
++ divider_ranges,
++ DIVIDER_RANGE_MAX,
++ get_reg_field_value(dispclk_cntl_value,
++ DENTIST_DISPCLK_CNTL,
++ DENTIST_DPREFCLK_WDIVIDER));
++
++
++ if (target_div != INVALID_DIVIDER) {
++ /* Calculate the current DFS clock, in kHz.*/
++ dp_ref_clk_khz = (DIVIDER_RANGE_SCALE_FACTOR
++ * disp_clk->dentist_vco_freq_khz) / target_div;
++ }
++
++ /* SW will adjust DP REF Clock average value for all purposes
++ * (DP DTO / DP Audio DTO and DP GTC)
++ if clock is spread for all cases:
++ -if SS enabled on DP Ref clock and HW de-spreading enabled with SW
++ calculations for DS_INCR/DS_MODULO (this is planned to be default case)
++ -if SS enabled on DP Ref clock and HW de-spreading enabled with HW
++ calculations (not planned to be used, but average clock should still
++ be valid)
++ -if SS enabled on DP Ref clock and HW de-spreading disabled
++ (should not be case with CIK) then SW should program all rates
++ generated according to average value (case as with previous ASICs)
++ */
++ if ((disp_clk->ss_on_gpu_pll) && (disp_clk->gpu_pll_ss_divider != 0)) {
++ struct fixed32_32 ss_percentage = dal_fixed32_32_div_int(
++ dal_fixed32_32_from_fraction(
++ disp_clk->gpu_pll_ss_percentage,
++ disp_clk->gpu_pll_ss_divider), 200);
++ struct fixed32_32 adj_dp_ref_clk_khz;
++
++ ss_percentage = dal_fixed32_32_sub(dal_fixed32_32_one,
++ ss_percentage);
++ adj_dp_ref_clk_khz =
++ dal_fixed32_32_mul_int(
++ ss_percentage,
++ dp_ref_clk_khz);
++ dp_ref_clk_khz = dal_fixed32_32_floor(adj_dp_ref_clk_khz);
++ }
++
++ return dp_ref_clk_khz;
++}
++
++
++static void destroy(struct display_clock **base)
++{
++ struct display_clock_dce110 *dc110;
++
++ dc110 = DCLCK110_FROM_BASE(*base);
++
++ dc_service_free((*base)->ctx, dc110);
++
++ *base = NULL;
++}
++
++static uint32_t get_validation_clock(struct display_clock *dc)
++{
++ uint32_t clk = 0;
++ struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
++
++ switch (disp_clk->max_clks_state) {
++ case CLOCKS_STATE_ULTRA_LOW:
++ /*Currently not supported, it has 0 in table entry*/
++ case CLOCKS_STATE_LOW:
++ clk = max_clks_by_state[CLOCKS_STATE_LOW].
++ display_clk_khz;
++ break;
++
++ case CLOCKS_STATE_NOMINAL:
++ clk = max_clks_by_state[CLOCKS_STATE_NOMINAL].
++ display_clk_khz;
++ break;
++
++ case CLOCKS_STATE_PERFORMANCE:
++ clk = max_clks_by_state[CLOCKS_STATE_PERFORMANCE].
++ display_clk_khz;
++ break;
++
++ case CLOCKS_STATE_INVALID:
++ default:
++ /*Invalid Clocks State*/
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "Invalid clock state");
++ /* just return the display engine clock for
++ * lowest supported state*/
++ clk = max_clks_by_state[CLOCKS_STATE_LOW].
++ display_clk_khz;
++ break;
++ }
++ return clk;
++}
++
++static struct fixed32_32 get_deep_color_factor(struct min_clock_params *params)
++{
++ /* DeepColorFactor = IF (HDMI = True, bpp / 24, 1)*/
++ struct fixed32_32 deep_color_factor = dal_fixed32_32_from_int(1);
++
++ if (params->signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
++ return deep_color_factor;
++
++ switch (params->deep_color_depth) {
++ case COLOR_DEPTH_101010:
++ /*deep color ratio for 30bpp is 30/24 = 1.25*/
++ deep_color_factor = dal_fixed32_32_from_fraction(30, 24);
++ break;
++
++ case COLOR_DEPTH_121212:
++ /* deep color ratio for 36bpp is 36/24 = 1.5*/
++ deep_color_factor = dal_fixed32_32_from_fraction(36, 24);
++ break;
++
++ case COLOR_DEPTH_161616:
++ /* deep color ratio for 48bpp is 48/24 = 2.0 */
++ deep_color_factor = dal_fixed32_32_from_fraction(48, 24);
++ break;
++ default:
++ break;
++ }
++ return deep_color_factor;
++}
++
++static struct fixed32_32 get_scaler_efficiency(
++ struct dc_context *ctx,
++ struct min_clock_params *params)
++{
++ struct fixed32_32 scaler_efficiency = dal_fixed32_32_from_int(3);
++
++ if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB18BPP) {
++ scaler_efficiency =
++ dal_fixed32_32_add(
++ dal_fixed32_32_from_fraction(35555, 10000),
++ dal_fixed32_32_from_fraction(
++ 55556,
++ 100000 * 10000));
++ } else if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB24BPP) {
++ scaler_efficiency =
++ dal_fixed32_32_add(
++ dal_fixed32_32_from_fraction(34285, 10000),
++ dal_fixed32_32_from_fraction(
++ 71429,
++ 100000 * 10000));
++ } else if (params->scaler_efficiency == V_SCALER_EFFICIENCY_LB30BPP)
++ scaler_efficiency = dal_fixed32_32_from_fraction(32, 10);
++
++ return scaler_efficiency;
++}
++
++static struct fixed32_32 get_lb_lines_in_per_line_out(
++ struct min_clock_params *params,
++ struct fixed32_32 v_scale_ratio)
++{
++ struct fixed32_32 two = dal_fixed32_32_from_int(2);
++ struct fixed32_32 four = dal_fixed32_32_from_int(4);
++ struct fixed32_32 f4_to_3 = dal_fixed32_32_from_fraction(4, 3);
++ struct fixed32_32 f6_to_4 = dal_fixed32_32_from_fraction(6, 4);
++
++ if (params->line_buffer_prefetch_enabled)
++ return dal_fixed32_32_max(v_scale_ratio, dal_fixed32_32_one);
++ else if (dal_fixed32_32_le(v_scale_ratio, dal_fixed32_32_one))
++ return dal_fixed32_32_one;
++ else if (dal_fixed32_32_le(v_scale_ratio, f4_to_3))
++ return f4_to_3;
++ else if (dal_fixed32_32_le(v_scale_ratio, f6_to_4))
++ return f6_to_4;
++ else if (dal_fixed32_32_le(v_scale_ratio, two))
++ return two;
++ else if (dal_fixed32_32_le(v_scale_ratio, dal_fixed32_32_from_int(3)))
++ return four;
++ else
++ return dal_fixed32_32_zero;
++}
++
++static uint32_t get_actual_required_display_clk(
++ struct display_clock_dce110 *disp_clk,
++ uint32_t target_clk_khz)
++{
++ uint32_t disp_clk_khz = target_clk_khz;
++ uint32_t div = INVALID_DIVIDER;
++ uint32_t did = INVALID_DID;
++ uint32_t scaled_vco =
++ disp_clk->dentist_vco_freq_khz * DIVIDER_RANGE_SCALE_FACTOR;
++
++ ASSERT_CRITICAL(!!disp_clk_khz);
++
++ if (disp_clk_khz)
++ div = scaled_vco / disp_clk_khz;
++
++ did = dal_divider_range_get_did(divider_ranges, DIVIDER_RANGE_MAX, div);
++
++ if (did != INVALID_DID) {
++ div = dal_divider_range_get_divider(
++ divider_ranges, DIVIDER_RANGE_MAX, did);
++
++ if ((div != INVALID_DIVIDER) &&
++ (did > DIVIDER_RANGE_01_BASE_DIVIDER_ID))
++ if (disp_clk_khz > (scaled_vco / div))
++ div = dal_divider_range_get_divider(
++ divider_ranges, DIVIDER_RANGE_MAX,
++ did - 1);
++
++ if (div != INVALID_DIVIDER)
++ disp_clk_khz = scaled_vco / div;
++
++ }
++ /* We need to add 10KHz to this value because the accuracy in VBIOS is
++ in 10KHz units. So we need to always round the last digit up in order
++ to reach the next div level.*/
++ return disp_clk_khz + 10;
++}
++
++static uint32_t calc_single_display_min_clks(
++ struct display_clock *base,
++ struct min_clock_params *params,
++ bool set_clk)
++{
++ struct fixed32_32 h_scale_ratio = dal_fixed32_32_one;
++ struct fixed32_32 v_scale_ratio = dal_fixed32_32_one;
++ uint32_t pix_clk_khz = 0;
++ uint32_t lb_source_width = 0;
++ struct fixed32_32 deep_color_factor;
++ struct fixed32_32 scaler_efficiency;
++ struct fixed32_32 v_filter_init;
++ uint32_t v_filter_init_trunc;
++ uint32_t num_lines_at_frame_start = 3;
++ struct fixed32_32 v_filter_init_ceil;
++ struct fixed32_32 lines_per_lines_out_at_frame_start;
++ struct fixed32_32 lb_lines_in_per_line_out; /* in middle of the frame*/
++ uint32_t src_wdth_rnd_to_chunks;
++ struct fixed32_32 scaling_coeff;
++ struct fixed32_32 h_blank_granularity_factor =
++ dal_fixed32_32_one;
++ struct fixed32_32 fx_disp_clk_mhz;
++ struct fixed32_32 line_time;
++ struct fixed32_32 disp_pipe_pix_throughput;
++ struct fixed32_32 fx_alt_disp_clk_mhz;
++ uint32_t disp_clk_khz;
++ uint32_t alt_disp_clk_khz;
++ struct display_clock_dce110 *disp_clk_110 = DCLCK110_FROM_BASE(base);
++ uint32_t max_clk_khz = get_validation_clock(base);
++ bool panning_allowed = false; /* TODO: receive this value from AS */
++
++ if (params == NULL) {
++ dal_logger_write(base->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "Invalid input parameter in %s",
++ __func__);
++ return 0;
++ }
++
++ deep_color_factor = get_deep_color_factor(params);
++ scaler_efficiency = get_scaler_efficiency(base->ctx, params);
++ pix_clk_khz = params->requested_pixel_clock;
++ lb_source_width = params->source_view.width;
++
++ if (0 != params->dest_view.height && 0 != params->dest_view.width) {
++
++ h_scale_ratio = dal_fixed32_32_from_fraction(
++ params->source_view.width,
++ params->dest_view.width);
++ v_scale_ratio = dal_fixed32_32_from_fraction(
++ params->source_view.height,
++ params->dest_view.height);
++ } else {
++ dal_logger_write(base->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "Destination height or width is 0!\n");
++ }
++
++ v_filter_init =
++ dal_fixed32_32_add(
++ v_scale_ratio,
++ dal_fixed32_32_add_int(
++ dal_fixed32_32_div_int(
++ dal_fixed32_32_mul_int(
++ v_scale_ratio,
++ params->timing_info.INTERLACED),
++ 2),
++ params->scaling_info.v_taps + 1));
++ v_filter_init = dal_fixed32_32_div_int(v_filter_init, 2);
++
++ v_filter_init_trunc = dal_fixed32_32_floor(v_filter_init);
++
++ v_filter_init_ceil = dal_fixed32_32_from_fraction(
++ v_filter_init_trunc, 2);
++ v_filter_init_ceil = dal_fixed32_32_from_int(
++ dal_fixed32_32_ceil(v_filter_init_ceil));
++ v_filter_init_ceil = dal_fixed32_32_mul_int(v_filter_init_ceil, 2);
++
++ lines_per_lines_out_at_frame_start =
++ dal_fixed32_32_div_int(v_filter_init_ceil,
++ num_lines_at_frame_start);
++ lb_lines_in_per_line_out =
++ get_lb_lines_in_per_line_out(params, v_scale_ratio);
++
++ if (panning_allowed)
++ src_wdth_rnd_to_chunks =
++ ((lb_source_width - 1) / 128) * 128 + 256;
++ else
++ src_wdth_rnd_to_chunks =
++ ((lb_source_width + 127) / 128) * 128;
++
++ scaling_coeff =
++ dal_fixed32_32_div(
++ dal_fixed32_32_from_int(params->scaling_info.v_taps),
++ scaler_efficiency);
++
++ if (dal_fixed32_32_le(h_scale_ratio, dal_fixed32_32_one))
++ scaling_coeff = dal_fixed32_32_max(
++ dal_fixed32_32_from_int(
++ dal_fixed32_32_ceil(
++ dal_fixed32_32_from_fraction(
++ params->scaling_info.h_taps,
++ 4))),
++ dal_fixed32_32_max(
++ dal_fixed32_32_mul(
++ scaling_coeff,
++ h_scale_ratio),
++ dal_fixed32_32_one));
++
++ if (!params->line_buffer_prefetch_enabled &&
++ dal_fixed32_32_floor(lb_lines_in_per_line_out) != 2 &&
++ dal_fixed32_32_floor(lb_lines_in_per_line_out) != 4) {
++ uint32_t line_total_pixel =
++ params->timing_info.h_total + lb_source_width - 256;
++ h_blank_granularity_factor = dal_fixed32_32_div(
++ dal_fixed32_32_from_int(params->timing_info.h_total),
++ dal_fixed32_32_div(
++ dal_fixed32_32_from_fraction(
++ line_total_pixel, 2),
++ h_scale_ratio));
++ }
++
++ /* Calculate display clock with ramping. Ramping factor is 1.1*/
++ fx_disp_clk_mhz =
++ dal_fixed32_32_div_int(
++ dal_fixed32_32_mul_int(scaling_coeff, 11),
++ 10);
++ line_time = dal_fixed32_32_from_fraction(
++ params->timing_info.h_total * 1000, pix_clk_khz);
++
++ disp_pipe_pix_throughput = dal_fixed32_32_mul(
++ lb_lines_in_per_line_out, h_blank_granularity_factor);
++ disp_pipe_pix_throughput = dal_fixed32_32_max(
++ disp_pipe_pix_throughput,
++ lines_per_lines_out_at_frame_start);
++ disp_pipe_pix_throughput = dal_fixed32_32_div(dal_fixed32_32_mul_int(
++ disp_pipe_pix_throughput, src_wdth_rnd_to_chunks),
++ line_time);
++
++ if (0 != params->timing_info.h_total) {
++ fx_disp_clk_mhz =
++ dal_fixed32_32_max(
++ dal_fixed32_32_div_int(
++ dal_fixed32_32_mul_int(
++ scaling_coeff, pix_clk_khz),
++ 1000),
++ disp_pipe_pix_throughput);
++ fx_disp_clk_mhz =
++ dal_fixed32_32_mul(
++ fx_disp_clk_mhz,
++ dal_fixed32_32_from_fraction(11, 10));
++ }
++
++ fx_disp_clk_mhz = dal_fixed32_32_max(fx_disp_clk_mhz,
++ dal_fixed32_32_mul(deep_color_factor,
++ dal_fixed32_32_from_fraction(11, 10)));
++
++ /* Calculate display clock without ramping */
++ fx_alt_disp_clk_mhz = scaling_coeff;
++
++ if (0 != params->timing_info.h_total) {
++ fx_alt_disp_clk_mhz = dal_fixed32_32_max(
++ dal_fixed32_32_div_int(dal_fixed32_32_mul_int(
++ scaling_coeff, pix_clk_khz),
++ 1000),
++ dal_fixed32_32_div_int(dal_fixed32_32_mul_int(
++ disp_pipe_pix_throughput, 105),
++ 100));
++ }
++
++ if (set_clk && disp_clk_110->ss_on_gpu_pll &&
++ disp_clk_110->gpu_pll_ss_divider)
++ fx_alt_disp_clk_mhz = dal_fixed32_32_mul(fx_alt_disp_clk_mhz,
++ dal_fixed32_32_add_int(
++ dal_fixed32_32_div_int(
++ dal_fixed32_32_div_int(
++ dal_fixed32_32_from_fraction(
++ disp_clk_110->gpu_pll_ss_percentage,
++ disp_clk_110->gpu_pll_ss_divider), 100),
++ 2),
++ 1));
++
++ /* convert to integer */
++ disp_clk_khz = dal_fixed32_32_round(
++ dal_fixed32_32_mul_int(fx_disp_clk_mhz, 1000));
++ alt_disp_clk_khz = dal_fixed32_32_round(
++ dal_fixed32_32_mul_int(fx_alt_disp_clk_mhz, 1000));
++
++ if ((disp_clk_khz > max_clk_khz) && (alt_disp_clk_khz <= max_clk_khz))
++ disp_clk_khz = alt_disp_clk_khz;
++
++ if (set_clk) { /* only compensate clock if we are going to set it.*/
++ disp_clk_khz = get_actual_required_display_clk(
++ disp_clk_110, disp_clk_khz);
++ }
++
++ disp_clk_khz = disp_clk_khz > max_clk_khz ? max_clk_khz : disp_clk_khz;
++
++ return disp_clk_khz;
++}
++
++static uint32_t calculate_min_clock(
++ struct display_clock *base,
++ uint32_t path_num,
++ struct min_clock_params *params)
++{
++ uint32_t i;
++ uint32_t validation_clk_khz =
++ get_validation_clock(base);
++ uint32_t min_clk_khz = validation_clk_khz;
++ uint32_t max_clk_khz = 0;
++ struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base);
++
++ if (dc->use_max_disp_clk)
++ return min_clk_khz;
++
++ if (params != NULL) {
++ uint32_t disp_clk_khz = 0;
++
++ for (i = 0; i < path_num; ++i) {
++
++ disp_clk_khz = calc_single_display_min_clks(
++ base, params, true);
++
++ /* update the max required clock found*/
++ if (disp_clk_khz > max_clk_khz)
++ max_clk_khz = disp_clk_khz;
++
++ params++;
++ }
++ }
++
++ min_clk_khz = max_clk_khz;
++
++ if (min_clk_khz > validation_clk_khz)
++ min_clk_khz = validation_clk_khz;
++ else if (min_clk_khz < base->min_display_clk_threshold_khz)
++ min_clk_khz = base->min_display_clk_threshold_khz;
++
++ if (dc->use_max_disp_clk)
++ min_clk_khz = get_validation_clock(base);
++
++ return min_clk_khz;
++}
++
++static bool display_clock_integrated_info_construct(
++ struct display_clock_dce110 *disp_clk,
++ struct adapter_service *as)
++{
++ struct integrated_info info;
++ uint32_t i;
++
++ struct display_clock *base = &disp_clk->disp_clk_base;
++
++ if (!dal_adapter_service_get_integrated_info(as, &info))
++ return false;
++
++ disp_clk->dentist_vco_freq_khz = info.dentist_vco_freq;
++ if (disp_clk->dentist_vco_freq_khz == 0)
++ disp_clk->dentist_vco_freq_khz = 3600000;
++
++ base->min_display_clk_threshold_khz =
++ disp_clk->dentist_vco_freq_khz / 64;
++
++ /*update the maximum display clock for each power state*/
++ for (i = 0; i < NUMBER_OF_DISP_CLK_VOLTAGE; ++i) {
++ enum clocks_state clk_state = CLOCKS_STATE_INVALID;
++
++ switch (i) {
++ case 0:
++ clk_state = CLOCKS_STATE_ULTRA_LOW;
++ break;
++
++ case 1:
++ clk_state = CLOCKS_STATE_LOW;
++ break;
++
++ case 2:
++ clk_state = CLOCKS_STATE_NOMINAL;
++ break;
++
++ case 3:
++ clk_state = CLOCKS_STATE_PERFORMANCE;
++ break;
++
++ default:
++ clk_state = CLOCKS_STATE_INVALID;
++ break;
++ }
++
++ /*Do not allow bad VBIOS/SBIOS to override with invalid values,
++ * check for > 100MHz*/
++ if (info.disp_clk_voltage[i].max_supported_clk >= 100000) {
++ max_clks_by_state[clk_state].display_clk_khz =
++ info.disp_clk_voltage[i].max_supported_clk;
++ }
++ }
++ disp_clk->dfs_bypass_enabled =
++ dal_adapter_service_is_dfs_bypass_enabled(as);
++ disp_clk->use_max_disp_clk =
++ dal_adapter_service_is_feature_supported(
++ FEATURE_USE_MAX_DISPLAY_CLK);
++
++ return true;
++}
++
++static uint32_t get_clock(struct display_clock *dc)
++{
++ uint32_t disp_clock = get_validation_clock(dc);
++ uint32_t target_div = INVALID_DIVIDER;
++ uint32_t addr = mmDENTIST_DISPCLK_CNTL;
++ uint32_t value = 0;
++ uint32_t field = 0;
++ struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
++
++ if (disp_clk->dfs_bypass_enabled && disp_clk->dfs_bypass_disp_clk)
++ return disp_clk->dfs_bypass_disp_clk;
++
++ /* Read the mmDENTIST_DISPCLK_CNTL to get the currently programmed
++ DID DENTIST_DISPCLK_WDIVIDER.*/
++ value = dal_read_reg(dc->ctx, addr);
++ field = get_reg_field_value(
++ value, DENTIST_DISPCLK_CNTL, DENTIST_DISPCLK_WDIVIDER);
++
++ /* Convert DENTIST_DISPCLK_WDIVIDER to actual divider*/
++ target_div = dal_divider_range_get_divider(
++ divider_ranges,
++ DIVIDER_RANGE_MAX,
++ field);
++
++ if (target_div != INVALID_DIVIDER)
++ /* Calculate the current DFS clock in KHz.
++ Should be okay up to 42.9 THz before overflowing.*/
++ disp_clock = (DIVIDER_RANGE_SCALE_FACTOR
++ * disp_clk->dentist_vco_freq_khz) / target_div;
++ return disp_clock;
++}
++
++static enum clocks_state get_required_clocks_state(
++ struct display_clock *dc,
++ struct state_dependent_clocks *req_clocks)
++{
++ int32_t i;
++ struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
++ enum clocks_state low_req_clk = disp_clk->max_clks_state;
++
++ if (!req_clocks) {
++ /* NULL pointer*/
++ dal_logger_write(dc->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Invalid parameter",
++ __func__);
++ return CLOCKS_STATE_INVALID;
++ }
++
++ /* Iterate from highest supported to lowest valid state, and update
++ * lowest RequiredState with the lowest state that satisfies
++ * all required clocks
++ */
++ for (i = disp_clk->max_clks_state; i >= CLOCKS_STATE_ULTRA_LOW; --i) {
++ if ((req_clocks->display_clk_khz <=
++ max_clks_by_state[i].display_clk_khz) &&
++ (req_clocks->pixel_clk_khz <=
++ max_clks_by_state[i].pixel_clk_khz))
++ low_req_clk = i;
++ }
++ return low_req_clk;
++}
++
++static void set_clock(
++ struct display_clock *base,
++ uint32_t requested_clk_khz)
++{
++ struct bp_pixel_clock_parameters pxl_clk_params;
++ struct display_clock_dce110 *dc = DCLCK110_FROM_BASE(base);
++ struct bios_parser *bp = dal_adapter_service_get_bios_parser(base->as);
++
++ /* Prepare to program display clock*/
++ dc_service_memset(&pxl_clk_params, 0, sizeof(pxl_clk_params));
++
++ pxl_clk_params.target_pixel_clock = requested_clk_khz;
++ pxl_clk_params.pll_id = base->id;
++
++ dal_bios_parser_program_display_engine_pll(bp, &pxl_clk_params);
++
++ if (dc->dfs_bypass_enabled) {
++
++ /* Cache the fixed display clock*/
++ dc->dfs_bypass_disp_clk =
++ pxl_clk_params.dfs_bypass_display_clock;
++ }
++
++ /* from power down, we need mark the clock state as ClocksStateNominal
++ * from HWReset, so when resume we will call pplib voltage regulator.*/
++ if (requested_clk_khz == 0)
++ base->cur_min_clks_state = CLOCKS_STATE_NOMINAL;
++}
++
++static void set_clock_state(
++ struct display_clock *dc,
++ struct display_clock_state clk_state)
++{
++ struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
++
++ disp_clk->clock_state = clk_state;
++}
++
++static struct display_clock_state get_clock_state(
++ struct display_clock *dc)
++{
++ struct display_clock_dce110 *disp_clk = DCLCK110_FROM_BASE(dc);
++
++ return disp_clk->clock_state;
++}
++
++static uint32_t get_dfs_bypass_threshold(struct display_clock *dc)
++{
++ return DCE110_DFS_BYPASS_THRESHOLD_KHZ;
++}
++
++static const struct display_clock_funcs funcs = {
++ .destroy = destroy,
++ .calculate_min_clock = calculate_min_clock,
++ .get_clock = get_clock,
++ .get_clock_state = get_clock_state,
++ .get_dfs_bypass_threshold = get_dfs_bypass_threshold,
++ .get_dp_ref_clk_frequency = get_dp_ref_clk_frequency,
++ .get_min_clocks_state = get_min_clocks_state,
++ .get_required_clocks_state = get_required_clocks_state,
++ .get_validation_clock = get_validation_clock,
++ .set_clock = set_clock,
++ .set_clock_state = set_clock_state,
++ .set_dp_ref_clock_source = NULL,
++ .set_min_clocks_state = set_min_clocks_state,
++ .store_max_clocks_state = store_max_clocks_state,
++ .validate = NULL,
++};
++
++static bool dal_display_clock_dce110_construct(
++ struct display_clock_dce110 *dc110,
++ struct dc_context *ctx,
++ struct adapter_service *as)
++{
++ struct display_clock *dc_base = &dc110->disp_clk_base;
++
++ if (NULL == as)
++ return false;
++
++ if (!dal_display_clock_construct_base(dc_base, ctx, as))
++ return false;
++
++ dc_base->funcs = &funcs;
++
++ dc110->dfs_bypass_disp_clk = 0;
++
++ if (!display_clock_integrated_info_construct(dc110, as))
++ dal_logger_write(dc_base->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "Cannot obtain VBIOS integrated info\n");
++
++ dc110->gpu_pll_ss_percentage = 0;
++ dc110->gpu_pll_ss_divider = 1000;
++ dc110->ss_on_gpu_pll = false;
++
++ dc_base->id = CLOCK_SOURCE_ID_DFS;
++/* Initially set max clocks state to nominal. This should be updated by
++ * via a pplib call to DAL IRI eventually calling a
++ * DisplayEngineClock_Dce110::StoreMaxClocksState(). This call will come in
++ * on PPLIB init. This is from DCE5x. in case HW wants to use mixed method.*/
++ dc110->max_clks_state = CLOCKS_STATE_NOMINAL;
++
++ dal_divider_range_construct(
++ &divider_ranges[DIVIDER_RANGE_01],
++ DIVIDER_RANGE_01_START,
++ DIVIDER_RANGE_01_STEP_SIZE,
++ DIVIDER_RANGE_01_BASE_DIVIDER_ID,
++ DIVIDER_RANGE_02_BASE_DIVIDER_ID);
++ dal_divider_range_construct(
++ &divider_ranges[DIVIDER_RANGE_02],
++ DIVIDER_RANGE_02_START,
++ DIVIDER_RANGE_02_STEP_SIZE,
++ DIVIDER_RANGE_02_BASE_DIVIDER_ID,
++ DIVIDER_RANGE_03_BASE_DIVIDER_ID);
++ dal_divider_range_construct(
++ &divider_ranges[DIVIDER_RANGE_03],
++ DIVIDER_RANGE_03_START,
++ DIVIDER_RANGE_03_STEP_SIZE,
++ DIVIDER_RANGE_03_BASE_DIVIDER_ID,
++ DIVIDER_RANGE_MAX_DIVIDER_ID);
++
++ {
++ uint32_t ss_info_num =
++ dal_adapter_service_get_ss_info_num(
++ as,
++ AS_SIGNAL_TYPE_GPU_PLL);
++
++ if (ss_info_num) {
++ struct spread_spectrum_info info;
++ bool result;
++
++ dc_service_memset(&info, 0, sizeof(info));
++
++ result =
++ dal_adapter_service_get_ss_info(
++ as,
++ AS_SIGNAL_TYPE_GPU_PLL,
++ 0,
++ &info);
++
++ /* Based on VBIOS, VBIOS will keep entry for GPU PLL SS
++ * even if SS not enabled and in that case
++ * SSInfo.spreadSpectrumPercentage !=0 would be sign
++ * that SS is enabled
++ */
++ if (result && info.spread_spectrum_percentage != 0) {
++ dc110->ss_on_gpu_pll = true;
++ dc110->gpu_pll_ss_divider =
++ info.spread_percentage_divider;
++
++ if (info.type.CENTER_MODE == 0) {
++ /* Currently for DP Reference clock we
++ * need only SS percentage for
++ * downspread */
++ dc110->gpu_pll_ss_percentage =
++ info.spread_spectrum_percentage;
++ }
++ }
++
++ }
++ }
++
++ return true;
++}
++
++/*****************************************************************************
++ * public functions
++ *****************************************************************************/
++
++struct display_clock *dal_display_clock_dce110_create(
++ struct dc_context *ctx,
++ struct adapter_service *as)
++{
++ struct display_clock_dce110 *dc110;
++
++ dc110 = dc_service_alloc(ctx, sizeof(struct display_clock_dce110));
++
++ if (dc110 == NULL)
++ return NULL;
++
++ if (dal_display_clock_dce110_construct(dc110, ctx, as))
++ return &dc110->disp_clk_base;
++
++ dc_service_free(ctx, dc110);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.h
+new file mode 100644
+index 0000000..0cdc7b5
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/display_clock_dce110.h
+@@ -0,0 +1,53 @@
++/*
++ * 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_DISPLAY_CLOCK_DCE110_H__
++#define __DAL_DISPLAY_CLOCK_DCE110_H__
++
++#include "gpu/display_clock.h"
++
++struct display_clock_dce110 {
++ struct display_clock disp_clk_base;
++ /* Max display block clocks state*/
++ enum clocks_state max_clks_state;
++ bool use_max_disp_clk;
++ uint32_t dentist_vco_freq_khz;
++ /* Cache the status of DFS-bypass feature*/
++ bool dfs_bypass_enabled;
++ /* GPU PLL SS percentage (if down-spread enabled) */
++ uint32_t gpu_pll_ss_percentage;
++ /* GPU PLL SS percentage Divider (100 or 1000) */
++ uint32_t gpu_pll_ss_divider;
++ /* Flag for Enabled SS on GPU PLL */
++ bool ss_on_gpu_pll;
++ /* Cache the display clock returned by VBIOS if DFS-bypass is enabled.
++ * This is basically "Crystal Frequency In KHz" (XTALIN) frequency */
++ uint32_t dfs_bypass_disp_clk;
++ struct display_clock_state clock_state;
++};
++
++#define DCLCK110_FROM_BASE(dc_base) \
++ container_of(dc_base, struct display_clock_dce110, disp_clk_base)
++
++#endif /* __DAL_DISPLAY_CLOCK_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/ext_clock_source_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/ext_clock_source_dce110.c
+new file mode 100644
+index 0000000..7fd5984
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/ext_clock_source_dce110.c
+@@ -0,0 +1,383 @@
++/* 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 "dal_services.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "include/logger_interface.h"
++#include "include/adapter_service_interface.h"
++#include "include/fixed32_32.h"
++
++#include "ext_clock_source_dce110.h"
++
++/**
++ * In this file ECS stands for External Clock Source.
++ */
++
++#define ECS110_FROM_BASE(clk_src_ptr)\
++ container_of(\
++ container_of((clk_src_ptr), struct ext_clock_source, base), \
++ struct ext_clock_source_dce110, base)
++
++#define ECS_WARNING(...) \
++ dal_logger_write(ctx->logger, LOG_MAJOR_WARNING, \
++ LOG_MINOR_COMPONENT_GPU, __VA_ARGS__)
++
++#define ECS_ERROR(...) \
++ dal_logger_write(ctx->logger, LOG_MAJOR_ERROR, \
++ LOG_MINOR_COMPONENT_GPU, __VA_ARGS__)
++
++/******************************************************************************
++ * implementation functions
++ *****************************************************************************/
++
++static uint32_t controller_id_to_index(
++ struct clock_source *clk_src,
++ enum controller_id controller_id)
++{
++ struct dc_context *ctx = clk_src->ctx;
++ uint32_t index = 0;
++
++ switch (controller_id) {
++ case CONTROLLER_ID_D0:
++ index = 0;
++ break;
++ case CONTROLLER_ID_D1:
++ index = 1;
++ break;
++ case CONTROLLER_ID_D2:
++ index = 2;
++ break;
++ default:
++ ECS_ERROR("%s: invalid input controller_id = %d!\n",
++ __func__, controller_id);
++ break;
++ }
++
++ return index;
++}
++
++/* Adjust pixel rate by DTO programming (used for DisplayPort) */
++static bool adjust_dto_pixel_rate(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t requested_pix_clk_hz)
++{
++ struct ext_clock_source_dce110 *ecs110 =
++ ECS110_FROM_BASE(clk_src);
++ struct dc_context *ctx = clk_src->ctx;
++ uint32_t index;
++ uint32_t dto_phase_reg;
++ uint32_t dto_modulo_reg;
++ uint32_t dto_phase_rnd;
++ uint32_t addr;
++ uint32_t value;
++ struct fixed32_32 dto_phase;
++
++ if (NULL == pix_clk_params) {
++ ECS_WARNING("%s: invalid input!\n", __func__);
++ return false;
++ }
++
++ index = controller_id_to_index(clk_src, pix_clk_params->controller_id);
++
++ addr = ecs110->registers[index].dp_dtox_phase;
++ dto_phase_reg = dal_read_reg(ctx, addr);
++
++ addr = ecs110->registers[index].dp_dtox_modulo;
++ dto_modulo_reg = dal_read_reg(ctx, addr);
++
++ if (!dto_modulo_reg) {
++ ECS_WARNING("%s: current modulo is zero!\n", __func__);
++ return false;
++ }
++
++ dto_phase = dal_fixed32_32_from_int(requested_pix_clk_hz);
++
++ dto_phase = dal_fixed32_32_mul_int(dto_phase, dto_modulo_reg);
++
++ dto_phase = dal_fixed32_32_div_int(dto_phase,
++ pix_clk_params->dp_ref_clk * 1000);
++
++ dto_phase_rnd = dal_fixed32_32_round(dto_phase);
++
++ /* Program DTO Phase */
++ if (dto_phase_reg != dto_phase_rnd) {
++ /* If HW De-Spreading enabled on DP REF clock and if there will
++ * be case when Pixel rate > average DP Ref Clock, then need to
++ * disable de-spread for DP DTO (ATOMBIOS will program MODULO
++ * for average DP REF clock so no further SW adjustment
++ * needed) */
++ if (pix_clk_params->de_spread_params.hw_dso_n_dp_ref_clk) {
++
++ addr = ecs110->registers[index].crtcx_pixel_rate_cntl;
++ value = dal_read_reg(ctx, addr);
++
++ if (requested_pix_clk_hz / 1000 >
++ pix_clk_params->
++ de_spread_params.avg_dp_ref_clk_khz) {
++
++ set_reg_field_value(value, 1,
++ CRTC0_PIXEL_RATE_CNTL,
++ DP_DTO0_DS_DISABLE);
++ } else {
++ set_reg_field_value(value, 0,
++ CRTC0_PIXEL_RATE_CNTL,
++ DP_DTO0_DS_DISABLE);
++ }
++
++ dal_write_reg(ctx, addr, value);
++ }
++
++ value = 0;
++ addr = ecs110->registers[index].dp_dtox_phase;
++
++ set_reg_field_value(value, dto_phase_rnd,
++ DP_DTO0_PHASE,
++ DP_DTO0_PHASE);
++
++ dal_write_reg(ctx, addr, value);
++ }
++
++ return true;
++}
++
++/**
++ * Retrieve Pixel Rate (in Hz) from HW registers already programmed.
++ */
++uint32_t retrieve_dp_pixel_rate_from_display_pll(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *params)
++{
++ struct dc_context *ctx = clk_src->ctx;
++
++ /* TODO: update when DAL2 implements this function. */
++ DAL_LOGGER_NOT_IMPL(LOG_MINOR_COMPONENT_GPU, "%s\n", __func__);
++ return 0;
++}
++
++static uint32_t retrieve_dto_pix_rate_hz(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *params)
++{
++ struct ext_clock_source_dce110 *ecs110 =
++ ECS110_FROM_BASE(clk_src);
++ struct dc_context *ctx = clk_src->ctx;
++ uint32_t index;
++ uint32_t dto_phase_reg;
++ uint32_t dto_modulo_reg;
++ uint32_t addr;
++ uint32_t value;
++ uint32_t pix_rate_hz;
++ struct fixed32_32 p_clk;
++
++ if (params == NULL)
++ return 0;
++
++ if (NULL == params) {
++ ECS_WARNING("%s: invalid input!\n", __func__);
++ return false;
++ }
++
++ index = controller_id_to_index(clk_src, params->controller_id);
++
++ addr = ecs110->registers[index].crtcx_pixel_rate_cntl;
++ value = dal_read_reg(ctx, addr);
++
++ if (get_reg_field_value(value, CRTC0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE)
++ == 1) {
++
++ addr = ecs110->registers[index].dp_dtox_phase;
++ dto_phase_reg = dal_read_reg(ctx, addr);
++
++ addr = ecs110->registers[index].dp_dtox_modulo;
++ dto_modulo_reg = dal_read_reg(ctx, addr);
++
++ if (!dto_modulo_reg) {
++ ECS_WARNING("%s: current modulo is zero!\n", __func__);
++ return 0;
++ }
++
++ /* Calculate pixel clock from DTO Phase & Modulo*/
++ p_clk = dal_fixed32_32_from_int(params->dp_ref_clk * 1000);
++
++ p_clk = dal_fixed32_32_mul_int(p_clk, dto_phase_reg);
++
++ p_clk = dal_fixed32_32_div_int(p_clk, dto_modulo_reg);
++
++ pix_rate_hz = dal_fixed32_32_round(p_clk);
++ } else {
++ pix_rate_hz = retrieve_dp_pixel_rate_from_display_pll(clk_src,
++ params);
++ }
++
++ return pix_rate_hz;
++}
++
++/******************************************************************************
++ * create/destroy functions
++ *****************************************************************************/
++
++static void destruct(struct ext_clock_source_dce110 *ecs110)
++{
++ struct ext_clock_source *ext_cs = &ecs110->base;
++ struct clock_source *base = &ext_cs->base;
++
++ if (NULL != base->dp_ss_params) {
++ dc_service_free(base->ctx, base->dp_ss_params);
++ base->dp_ss_params = NULL;
++ }
++
++ dc_service_free(base->ctx, ecs110->registers);
++ ecs110->registers = NULL;
++}
++
++
++static void destroy(struct clock_source **clk_src)
++{
++ struct ext_clock_source_dce110 *ecs110;
++
++ ecs110 = ECS110_FROM_BASE(*clk_src);
++
++ destruct(ecs110);
++
++ dc_service_free((*clk_src)->ctx, ecs110);
++
++ *clk_src = NULL;
++}
++
++static const struct clock_source_impl funcs = {
++ .program_pix_clk = dal_ext_clock_source_program_pix_clk,
++ .adjust_pll_pixel_rate = dal_clock_source_base_adjust_pll_pixel_rate,
++ .adjust_dto_pixel_rate = adjust_dto_pixel_rate,
++ .retrieve_pll_pix_rate_hz =
++ dal_clock_source_base_retrieve_pll_pix_rate_hz,
++ .get_pix_clk_dividers = dal_ext_clock_source_get_pix_clk_dividers,
++ .destroy = destroy,
++ .retrieve_dto_pix_rate_hz = retrieve_dto_pix_rate_hz,
++ .power_down_pll = dal_ext_clock_source_power_down_pll
++};
++
++static bool construct(
++ struct ext_clock_source_dce110 *ecs110,
++ struct clock_source_init_data *clk_src_init_data)
++{
++ struct dc_context *ctx = clk_src_init_data->ctx;
++ struct ext_clock_source *ext_cs = &ecs110->base;
++ struct clock_source *base = &ext_cs->base;
++ uint32_t controllers_num;
++ struct registers *registers;
++
++ /* None of the base construct() functions allocates memory.
++ * That means, in case of error, we don't have to free memory
++ * allocated by base. */
++ if (!dal_ext_clock_source_construct(ext_cs, clk_src_init_data))
++ return false;
++
++ base->funcs = &funcs;
++
++ base->is_gen_lock_capable = false;
++ base->dp_ss_params = NULL;
++ base->dp_ss_params_cnt = 0;
++
++ ecs110->registers = NULL;
++
++ if (base->clk_src_id != CLOCK_SOURCE_ID_EXTERNAL) {
++ ECS_ERROR("ECS110:Invalid ClockSourceId = %d!\n",
++ base->clk_src_id);
++ return false;
++ }
++
++ controllers_num = dal_adapter_service_get_controllers_num(
++ base->adapter_service);
++
++ if (controllers_num <= 0 || controllers_num > 3) {
++ ECS_ERROR("ECS110:Invalid number of controllers = %d!\n",
++ controllers_num);
++ return false;
++ }
++
++ ecs110->registers = (struct registers *)
++ (dc_service_alloc(clk_src_init_data->ctx, sizeof(struct registers) * controllers_num));
++
++ if (ecs110->registers == NULL) {
++ ECS_ERROR("ECS110:Failed to allocate 'registers'!\n");
++ return false;
++ }
++
++ registers = ecs110->registers;
++
++ /* Assign register address. No break between cases */
++ switch (controllers_num) {
++ case 3:
++ registers[2].dp_dtox_phase = mmDP_DTO2_PHASE;
++ registers[2].dp_dtox_modulo = mmDP_DTO2_MODULO;
++ registers[2].crtcx_pixel_rate_cntl = mmCRTC2_PIXEL_RATE_CNTL;
++ /* fallthrough */
++ case 2:
++ registers[1].dp_dtox_phase = mmDP_DTO1_PHASE;
++ registers[1].dp_dtox_modulo = mmDP_DTO1_MODULO;
++ registers[1].crtcx_pixel_rate_cntl = mmCRTC1_PIXEL_RATE_CNTL;
++ /* fallthrough */
++ case 1:
++ registers[0].dp_dtox_phase = mmDP_DTO0_PHASE;
++ registers[0].dp_dtox_modulo = mmDP_DTO0_MODULO;
++ registers[0].crtcx_pixel_rate_cntl = mmCRTC0_PIXEL_RATE_CNTL;
++ break;
++
++ default:
++ /* We can not get here because we checked number of
++ * controllers already. */
++ break;
++ }
++
++ dal_clock_source_get_ss_info_from_atombios(
++ base,
++ AS_SIGNAL_TYPE_DISPLAY_PORT,
++ &base->dp_ss_params,
++ &base->dp_ss_params_cnt);
++
++ return true;
++}
++
++
++struct clock_source *dal_ext_clock_source_dce110_create(
++ struct clock_source_init_data *clk_src_init_data)
++{
++ struct ext_clock_source_dce110 *ecs110;
++
++ ecs110 = dc_service_alloc(clk_src_init_data->ctx, sizeof(struct ext_clock_source_dce110));
++
++ if (ecs110 == NULL)
++ return NULL;
++
++ if (!construct(ecs110, clk_src_init_data)) {
++ dc_service_free(clk_src_init_data->ctx, ecs110);
++ return NULL;
++ }
++
++ return &ecs110->base.base;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/ext_clock_source_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/ext_clock_source_dce110.h
+new file mode 100644
+index 0000000..4ea2ae2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/ext_clock_source_dce110.h
+@@ -0,0 +1,38 @@
++/* 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_EXT_CLOCK_SOURCE_DCE110__
++#define __DAL_EXT_CLOCK_SOURCE_DCE110__
++
++#include "../ext_clock_source.h"
++
++struct ext_clock_source_dce110 {
++ struct ext_clock_source base;
++ struct registers *registers;
++};
++
++struct clock_source *dal_ext_clock_source_dce110_create(
++ struct clock_source_init_data *clk_src_init_data);
++
++#endif /*__DAL_EXT_CLOCK_SOURCE_DCE110__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/pll_clock_source_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/pll_clock_source_dce110.c
+new file mode 100644
+index 0000000..d83eea3
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/pll_clock_source_dce110.c
+@@ -0,0 +1,718 @@
++/* 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 "dal_services.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++#include "include/logger_interface.h"
++#include "include/bios_parser_interface.h"
++#include "include/adapter_service_interface.h"
++#include "include/fixed32_32.h"
++#include "gpu/calc_pll_clock_source.h"
++#include "gpu/clock_source.h"
++#include "gpu/pll_clock_source.h"
++
++#include "gpu/dce110/pll_clock_source_dce110.h"
++
++enum fract_fb_divider_dec_points {
++ FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM = 6,
++ FRACT_FB_DIVIDER_DEC_POINTS_NO_DS_NUM = 1,
++};
++
++#define FROM_CLK_SRC(clk_src_ptr)\
++ container_of(\
++ container_of((clk_src_ptr), struct pll_clock_source, base), \
++ struct pll_clock_source_dce110, base)
++
++static bool calculate_ss(
++ struct pll_clock_source_dce110 *clk_src,
++ struct pll_settings *pll_settings,
++ const struct spread_spectrum_data *ss_data,
++ struct delta_sigma_data *ds_data)
++{
++ struct fixed32_32 fb_div;
++ struct fixed32_32 ss_amount;
++ struct fixed32_32 ss_nslip_amount;
++ struct fixed32_32 ss_ds_frac_amount;
++ struct fixed32_32 ss_step_size;
++ struct fixed32_32 modulation_time;
++
++ if (ds_data == NULL)
++ return false;
++ if (ss_data == NULL)
++ return false;
++ if (ss_data->percentage == 0)
++ return false;
++ if (pll_settings == NULL)
++ return false;
++
++
++ dc_service_memset(ds_data, 0, sizeof(struct delta_sigma_data));
++
++
++
++ /* compute SS_AMOUNT_FBDIV & SS_AMOUNT_NFRAC_SLIP & SS_AMOUNT_DSFRAC*/
++ /* 6 decimal point support in fractional feedback divider */
++ fb_div = dal_fixed32_32_from_fraction(
++ pll_settings->fract_feedback_divider, 1000000);
++ fb_div = dal_fixed32_32_add_int(fb_div, pll_settings->feedback_divider);
++
++ ds_data->ds_frac_amount = 0;
++ /*spreadSpectrumPercentage is in the unit of .01%,
++ * so have to divided by 100 * 100*/
++ ss_amount = dal_fixed32_32_mul(
++ fb_div, dal_fixed32_32_from_fraction(ss_data->percentage,
++ 100 * ss_data->percentage_divider));
++ ds_data->feedback_amount = dal_fixed32_32_floor(ss_amount);
++
++ ss_nslip_amount = dal_fixed32_32_sub(ss_amount,
++ dal_fixed32_32_from_int(ds_data->feedback_amount));
++ ss_nslip_amount = dal_fixed32_32_mul_int(ss_nslip_amount, 10);
++ ds_data->nfrac_amount = dal_fixed32_32_floor(ss_nslip_amount);
++
++ ss_ds_frac_amount = dal_fixed32_32_sub(ss_nslip_amount,
++ dal_fixed32_32_from_int(ds_data->nfrac_amount));
++ ss_ds_frac_amount = dal_fixed32_32_mul_int(ss_ds_frac_amount, 65536);
++ ds_data->ds_frac_amount = dal_fixed32_32_floor(ss_ds_frac_amount);
++
++ /* compute SS_STEP_SIZE_DSFRAC */
++ modulation_time = dal_fixed32_32_from_fraction(
++ pll_settings->reference_freq * 1000,
++ pll_settings->reference_divider * ss_data->modulation_freq_hz);
++
++
++ if (ss_data->flags.CENTER_SPREAD)
++ modulation_time = dal_fixed32_32_div_int(modulation_time, 4);
++ else
++ modulation_time = dal_fixed32_32_div_int(modulation_time, 2);
++
++ ss_step_size = dal_fixed32_32_div(ss_amount, modulation_time);
++ /* SS_STEP_SIZE_DSFRAC_DEC = Int(SS_STEP_SIZE * 2 ^ 16 * 10)*/
++ ss_step_size = dal_fixed32_32_mul_int(ss_step_size, 65536 * 10);
++ ds_data->ds_frac_size = dal_fixed32_32_floor(ss_step_size);
++
++ return true;
++}
++
++static bool disable_spread_spectrum(struct pll_clock_source_dce110 *clk_src)
++{
++ enum bp_result result;
++ struct bp_spread_spectrum_parameters bp_ss_params = {0};
++ struct clock_source *clock_source = NULL;
++
++ clock_source = &clk_src->base.base;
++ bp_ss_params.pll_id = clock_source->clk_src_id;
++
++ /*Call ASICControl to process ATOMBIOS Exec table*/
++ result = dal_bios_parser_enable_spread_spectrum_on_ppll(
++ clock_source->bios_parser,
++ &bp_ss_params,
++ false);
++
++ return result == BP_RESULT_OK;
++}
++
++static bool enable_spread_spectrum(
++ struct pll_clock_source_dce110 *clk_src,
++ enum signal_type signal, struct pll_settings *pll_settings)
++{
++ struct bp_spread_spectrum_parameters bp_params = {0};
++ struct delta_sigma_data d_s_data;
++ struct clock_source *clock_source = NULL;
++ const struct spread_spectrum_data *ss_data = NULL;
++
++ clock_source = &clk_src->base.base;
++ ss_data = dal_clock_source_get_ss_data_entry(
++ clock_source,
++ signal,
++ pll_settings->calculated_pix_clk);
++
++/* Pixel clock PLL has been programmed to generate desired pixel clock,
++ * now enable SS on pixel clock */
++/* TODO is it OK to return true not doing anything ??*/
++ if (ss_data != NULL && pll_settings->ss_percentage != 0) {
++ if (calculate_ss(clk_src, pll_settings, ss_data, &d_s_data)) {
++ bp_params.ds.feedback_amount =
++ d_s_data.feedback_amount;
++ bp_params.ds.nfrac_amount =
++ d_s_data.nfrac_amount;
++ bp_params.ds.ds_frac_size = d_s_data.ds_frac_size;
++ bp_params.ds_frac_amount =
++ d_s_data.ds_frac_amount;
++ bp_params.flags.DS_TYPE = 1;
++ bp_params.pll_id = clock_source->clk_src_id;
++ bp_params.percentage = ss_data->percentage;
++ if (ss_data->flags.CENTER_SPREAD)
++ bp_params.flags.CENTER_SPREAD = 1;
++ if (ss_data->flags.EXTERNAL_SS)
++ bp_params.flags.EXTERNAL_SS = 1;
++
++ if (BP_RESULT_OK !=
++ dal_bios_parser_enable_spread_spectrum_on_ppll(
++ clock_source->bios_parser,
++ &bp_params,
++ true))
++ return false;
++ } else
++ return false;
++ }
++ return true;
++}
++
++static void program_pixel_clk_resync(
++ struct pll_clock_source_dce110 *clk_src,
++ enum signal_type signal_type,
++ enum dc_color_depth colordepth)
++{
++ struct clock_source *clock_source = NULL;
++ uint32_t value = 0;
++
++ clock_source = &clk_src->base.base;
++
++ value = dal_read_reg(
++ clock_source->ctx,
++ clk_src->pixclkx_resync_cntl);
++
++ set_reg_field_value(
++ value,
++ 0,
++ PIXCLK1_RESYNC_CNTL,
++ DCCG_DEEP_COLOR_CNTL1);
++
++ /*
++ 24 bit mode: TMDS clock = 1.0 x pixel clock (1:1)
++ 30 bit mode: TMDS clock = 1.25 x pixel clock (5:4)
++ 36 bit mode: TMDS clock = 1.5 x pixel clock (3:2)
++ 48 bit mode: TMDS clock = 2 x pixel clock (2:1)
++ */
++ if (signal_type != SIGNAL_TYPE_HDMI_TYPE_A)
++ return;
++
++ switch (colordepth) {
++ case COLOR_DEPTH_888:
++ set_reg_field_value(
++ value,
++ 0,
++ PIXCLK1_RESYNC_CNTL,
++ DCCG_DEEP_COLOR_CNTL1);
++ break;
++ case COLOR_DEPTH_101010:
++ set_reg_field_value(
++ value,
++ 1,
++ PIXCLK1_RESYNC_CNTL,
++ DCCG_DEEP_COLOR_CNTL1);
++ break;
++ case COLOR_DEPTH_121212:
++ set_reg_field_value(
++ value,
++ 2,
++ PIXCLK1_RESYNC_CNTL,
++ DCCG_DEEP_COLOR_CNTL1);
++ break;
++ case COLOR_DEPTH_161616:
++ set_reg_field_value(
++ value,
++ 3,
++ PIXCLK1_RESYNC_CNTL,
++ DCCG_DEEP_COLOR_CNTL1);
++ break;
++ default:
++ break;
++ }
++
++ dal_write_reg(
++ clock_source->ctx,
++ clk_src->pixclkx_resync_cntl,
++ value);
++}
++
++static bool program_pix_clk(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ struct pll_clock_source_dce110 *pll_clk_src_dce110 =
++ FROM_CLK_SRC(clk_src);
++ struct bp_pixel_clock_parameters bp_pc_params = {0};
++
++ /* First disable SS
++ * ATOMBIOS will enable by default SS on PLL for DP,
++ * do not disable it here
++ */
++ if (!dc_is_dp_signal(pix_clk_params->signal_type))
++ disable_spread_spectrum(pll_clk_src_dce110);
++
++ /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
++ bp_pc_params.controller_id = pix_clk_params->controller_id;
++ bp_pc_params.pll_id = clk_src->clk_src_id;
++ bp_pc_params.target_pixel_clock =
++ pll_settings->actual_pix_clk;
++ bp_pc_params.reference_divider = pll_settings->reference_divider;
++ bp_pc_params.feedback_divider = pll_settings->feedback_divider;
++ bp_pc_params.fractional_feedback_divider =
++ pll_settings->fract_feedback_divider;
++ bp_pc_params.pixel_clock_post_divider =
++ pll_settings->pix_clk_post_divider;
++ bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
++ bp_pc_params.signal_type = pix_clk_params->signal_type;
++ bp_pc_params.dvo_config = pix_clk_params->dvo_cfg;
++ bp_pc_params.flags.SET_EXTERNAL_REF_DIV_SRC =
++ pll_settings->use_external_clk;
++
++ if (dal_bios_parser_set_pixel_clock(clk_src->bios_parser,
++ &bp_pc_params) != BP_RESULT_OK)
++ return false;
++
++/* Enable SS
++ * ATOMBIOS will enable by default SS for DP on PLL ( DP ID clock),
++ * based on HW display PLL team, SS control settings should be programmed
++ * during PLL Reset, but they do not have effect
++ * until SS_EN is asserted.*/
++ if (pix_clk_params->flags.ENABLE_SS && !dc_is_dp_signal(
++ pix_clk_params->signal_type))
++ if (!enable_spread_spectrum(pll_clk_src_dce110,
++ pix_clk_params->signal_type,
++ pll_settings))
++ return false;
++
++/* Resync deep color DTO */
++ program_pixel_clk_resync(pll_clk_src_dce110,
++ pix_clk_params->signal_type,
++ pix_clk_params->color_depth);
++
++ return true;
++}
++
++static void ss_info_from_atombios_destroy(
++ struct pll_clock_source_dce110 *clk_src)
++{
++ struct clock_source *cs = &clk_src->base.base;
++
++ if (NULL != cs->ep_ss_params) {
++ dc_service_free(cs->ctx, cs->ep_ss_params);
++ cs->ep_ss_params = NULL;
++ }
++
++ if (NULL != cs->dp_ss_params) {
++ dc_service_free(cs->ctx, cs->dp_ss_params);
++ cs->dp_ss_params = NULL;
++ }
++
++ if (NULL != cs->hdmi_ss_params) {
++ dc_service_free(cs->ctx, cs->hdmi_ss_params);
++ cs->hdmi_ss_params = NULL;
++ }
++
++ if (NULL != cs->dvi_ss_params) {
++ dc_service_free(cs->ctx, cs->dvi_ss_params);
++ cs->dvi_ss_params = NULL;
++ }
++}
++
++static void destruct(
++ struct pll_clock_source_dce110 *pll_cs)
++{
++ ss_info_from_atombios_destroy(pll_cs);
++
++ if (NULL != pll_cs->registers) {
++ dc_service_free(pll_cs->base.base.ctx, pll_cs->registers);
++ pll_cs->registers = NULL;
++ }
++}
++
++static void destroy(struct clock_source **clk_src)
++{
++ struct pll_clock_source_dce110 *pll_clk_src;
++
++ pll_clk_src = FROM_CLK_SRC(*clk_src);
++
++ destruct(pll_clk_src);
++ dc_service_free((*clk_src)->ctx, pll_clk_src);
++
++ *clk_src = NULL;
++}
++
++/**
++ * Calculate PLL Dividers for given Clock Value.
++ * First will call VBIOS Adjust Exec table to check if requested Pixel clock
++ * will be Adjusted based on usage.
++ * Then it will calculate PLL Dividers for this Adjusted clock using preferred
++ * method (Maximum VCO frequency).
++ *
++ * \return
++ * Calculation error in units of 0.01%
++ */
++static uint32_t get_pix_clk_dividers(
++ struct clock_source *cs,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ struct pll_clock_source_dce110 *pll_cs_110 = FROM_CLK_SRC(cs);
++ struct pll_clock_source *pll_base = &pll_cs_110->base;
++ uint32_t pll_calc_error = MAX_PLL_CALC_ERROR;
++ uint32_t addr = 0;
++ uint32_t value = 0;
++ uint32_t field = 0;
++
++ if (pix_clk_params == NULL || pll_settings == NULL
++ || pix_clk_params->requested_pix_clk == 0) {
++ dal_logger_write(cs->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Invalid parameters!!\n", __func__);
++ return pll_calc_error;
++ }
++
++ dc_service_memset(pll_settings, 0, sizeof(*pll_settings));
++
++ /* Check if reference clock is external (not pcie/xtalin)
++ * HW Dce80 spec:
++ * 00 - PCIE_REFCLK, 01 - XTALIN, 02 - GENERICA, 03 - GENERICB
++ * 04 - HSYNCA, 05 - GENLK_CLK, 06 - PCIE_REFCLK, 07 - DVOCLK0 */
++ addr = pll_cs_110->pxpll_cntl;
++ value = dal_read_reg(cs->ctx, addr);
++ field = get_reg_field_value(value, PLL_CNTL, PLL_REF_DIV_SRC);
++ pll_settings->use_external_clk = (field > 1);
++
++ /* VBIOS by default enables DP SS (spread on IDCLK) for DCE 8.0 always
++ * (we do not care any more from SI for some older DP Sink which
++ * does not report SS support, no known issues) */
++ if ((pix_clk_params->flags.ENABLE_SS) ||
++ (dc_is_dp_signal(pix_clk_params->signal_type))) {
++
++ const struct spread_spectrum_data *ss_data =
++ dal_clock_source_get_ss_data_entry(
++ cs,
++ pix_clk_params->signal_type,
++ pll_settings->adjusted_pix_clk);
++
++ if (NULL != ss_data)
++ pll_settings->ss_percentage = ss_data->percentage;
++ }
++
++ /* Check VBIOS AdjustPixelClock Exec table */
++ if (!dal_pll_clock_source_adjust_pix_clk(pll_base,
++ pix_clk_params, pll_settings)) {
++ /* Should never happen, ASSERT and fill up values to be able
++ * to continue. */
++ dal_logger_write(cs->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Failed to adjust pixel clock!!", __func__);
++ pll_settings->actual_pix_clk =
++ pix_clk_params->requested_pix_clk;
++ pll_settings->adjusted_pix_clk =
++ pix_clk_params->requested_pix_clk;
++
++ if (dc_is_dp_signal(pix_clk_params->signal_type))
++ pll_settings->adjusted_pix_clk = 100000;
++ }
++
++ /* Calculate Dividers */
++ if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A)
++ /*Calculate Dividers by HDMI object, no SS case or SS case */
++ pll_calc_error =
++ dal_clock_source_calculate_pixel_clock_pll_dividers(
++ &pll_cs_110->calc_pll_clock_source_hdmi,
++ pll_settings);
++ else
++ /*Calculate Dividers by default object, no SS case or SS case */
++ pll_calc_error =
++ dal_clock_source_calculate_pixel_clock_pll_dividers(
++ &pll_cs_110->calc_pll_clock_source,
++ pll_settings);
++
++ return pll_calc_error;
++}
++
++static const struct clock_source_impl funcs = {
++ .program_pix_clk = program_pix_clk,
++ .adjust_pll_pixel_rate = NULL,
++ .adjust_dto_pixel_rate = NULL,
++ .retrieve_pll_pix_rate_hz = NULL,
++ .get_pix_clk_dividers = get_pix_clk_dividers,
++ .destroy = destroy,
++ .retrieve_dto_pix_rate_hz = NULL,
++ .power_down_pll = dal_pll_clock_source_power_down_pll,
++};
++
++static void ss_info_from_atombios_create(
++ struct pll_clock_source_dce110 *clk_src)
++{
++ struct clock_source *base = &clk_src->base.base;
++
++ dal_clock_source_get_ss_info_from_atombios(
++ base,
++ AS_SIGNAL_TYPE_DISPLAY_PORT,
++ &base->dp_ss_params,
++ &base->dp_ss_params_cnt);
++ dal_clock_source_get_ss_info_from_atombios(
++ base,
++ AS_SIGNAL_TYPE_LVDS,
++ &base->ep_ss_params,
++ &base->ep_ss_params_cnt);
++ dal_clock_source_get_ss_info_from_atombios(
++ base,
++ AS_SIGNAL_TYPE_HDMI,
++ &base->hdmi_ss_params,
++ &base->hdmi_ss_params_cnt);
++ dal_clock_source_get_ss_info_from_atombios(
++ base,
++ AS_SIGNAL_TYPE_DVI,
++ &base->dvi_ss_params,
++ &base->dvi_ss_params_cnt);
++}
++
++
++static bool construct(
++ struct pll_clock_source_dce110 *pll_cs_dce110,
++ struct clock_source_init_data *clk_src_init_data)
++{
++ uint32_t controllers_num = 1;
++
++/* structure normally used with PLL ranges from ATOMBIOS; DS on by default */
++ struct calc_pll_clock_source_init_data calc_pll_cs_init_data = {
++ dal_adapter_service_get_bios_parser(clk_src_init_data->as),
++ 1, /* minPixelClockPLLPostDivider */
++ PLL_POST_DIV__PLL_POST_DIV_PIXCLK_MASK,
++ /* maxPixelClockPLLPostDivider*/
++ 1,/* minPLLRefDivider*/
++ PLL_REF_DIV__PLL_REF_DIV_MASK,/* maxPLLRefDivider*/
++ 0,
++/* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
++ 0,
++/* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
++ FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM,
++/*numberOfFractFBDividerDecimalPoints*/
++ FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM,
++/*number of decimal point to round off for fractional feedback divider value*/
++ clk_src_init_data->ctx
++ };
++/*structure for HDMI, no SS or SS% <= 0.06% for 27 MHz Ref clock */
++ struct calc_pll_clock_source_init_data calc_pll_cs_init_data_hdmi = {
++ dal_adapter_service_get_bios_parser(clk_src_init_data->as),
++ 1, /* minPixelClockPLLPostDivider */
++ PLL_POST_DIV__PLL_POST_DIV_PIXCLK_MASK,
++ /* maxPixelClockPLLPostDivider*/
++ 1,/* minPLLRefDivider*/
++ PLL_REF_DIV__PLL_REF_DIV_MASK,/* maxPLLRefDivider*/
++ 13500,
++ /* when 0 use minInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
++ 27000,
++ /* when 0 use maxInputPxlClkPLLFrequencyInKHz from firmwareInfo*/
++ FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM,
++ /*numberOfFractFBDividerDecimalPoints*/
++ FRACT_FB_DIVIDER_DEC_POINTS_MAX_NUM,
++/*number of decimal point to round off for fractional feedback divider value*/
++ clk_src_init_data->ctx
++ };
++
++ struct pll_clock_source *base = &pll_cs_dce110->base;
++ struct clock_source *superbase = &base->base;
++
++ if (!dal_pll_clock_source_construct(base, clk_src_init_data)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ superbase->funcs = &funcs;
++
++ superbase->is_clock_source_with_fixed_freq = false;
++ superbase->clk_sharing_lvl = CLOCK_SHARING_LEVEL_DISPLAY_PORT_SHAREABLE;
++
++ pll_cs_dce110->registers = NULL;
++
++/* PLL3 should not be used although it is available in online register spec */
++ if ((superbase->clk_src_id != CLOCK_SOURCE_ID_PLL1)
++ && (superbase->clk_src_id != CLOCK_SOURCE_ID_PLL0)) {
++
++
++ ASSERT_CRITICAL(false);
++ goto failure;
++ }
++
++/* From Driver side PLL0 is now used for non DP timing also,
++ * so it supports all signals except Wireless.
++ * Wireless signal type does not require a PLL clock source,
++ * so we will not waste a clock on it.
++*/
++ superbase->output_signals &= ~SIGNAL_TYPE_WIRELESS;
++
++ if (!dal_calc_pll_clock_source_max_vco_init(
++ &pll_cs_dce110->calc_pll_clock_source,
++ &calc_pll_cs_init_data)) {
++ ASSERT_CRITICAL(false);
++ goto failure;
++ }
++
++ if (base->ref_freq_khz == 48000) {
++ calc_pll_cs_init_data_hdmi.
++ min_override_input_pxl_clk_pll_freq_khz = 24000;
++ calc_pll_cs_init_data_hdmi.
++ max_override_input_pxl_clk_pll_freq_khz = 48000;
++ } else if (base->ref_freq_khz == 100000) {
++ calc_pll_cs_init_data_hdmi.
++ min_override_input_pxl_clk_pll_freq_khz = 25000;
++ calc_pll_cs_init_data_hdmi.
++ max_override_input_pxl_clk_pll_freq_khz = 50000;
++ }
++
++ if (!dal_calc_pll_clock_source_max_vco_init(
++ &pll_cs_dce110->calc_pll_clock_source_hdmi,
++ &calc_pll_cs_init_data_hdmi)) {
++ ASSERT_CRITICAL(false);
++ goto failure;
++ }
++
++ switch (superbase->clk_src_id) {
++ case CLOCK_SOURCE_ID_PLL0:
++ pll_cs_dce110->pixclkx_resync_cntl = mmPIXCLK0_RESYNC_CNTL;
++ pll_cs_dce110->ppll_fb_div = mmBPHYC_PLL0_PLL_FB_DIV;
++ pll_cs_dce110->ppll_ref_div = mmBPHYC_PLL0_PLL_REF_DIV;
++ pll_cs_dce110->ppll_post_div = mmBPHYC_PLL0_PLL_POST_DIV;
++ pll_cs_dce110->pxpll_ds_cntl = mmBPHYC_PLL0_PLL_DS_CNTL;
++ pll_cs_dce110->pxpll_ss_cntl = mmBPHYC_PLL0_PLL_SS_CNTL;
++ pll_cs_dce110->pxpll_ss_dsfrac =
++ mmBPHYC_PLL0_PLL_SS_AMOUNT_DSFRAC;
++ pll_cs_dce110->pxpll_cntl = mmBPHYC_PLL0_PLL_CNTL;
++ break;
++ case CLOCK_SOURCE_ID_PLL1:
++ pll_cs_dce110->pixclkx_resync_cntl = mmPIXCLK1_RESYNC_CNTL;
++ pll_cs_dce110->ppll_fb_div = mmBPHYC_PLL1_PLL_FB_DIV;
++ pll_cs_dce110->ppll_ref_div = mmBPHYC_PLL1_PLL_REF_DIV;
++ pll_cs_dce110->ppll_post_div = mmBPHYC_PLL1_PLL_POST_DIV;
++ pll_cs_dce110->pxpll_ds_cntl = mmBPHYC_PLL1_PLL_DS_CNTL;
++ pll_cs_dce110->pxpll_ss_cntl = mmBPHYC_PLL1_PLL_SS_CNTL;
++ pll_cs_dce110->pxpll_ss_dsfrac =
++ mmBPHYC_PLL1_PLL_SS_AMOUNT_DSFRAC;
++ pll_cs_dce110->pxpll_cntl = mmBPHYC_PLL1_PLL_CNTL;
++ break;
++ case CLOCK_SOURCE_ID_PLL2:
++ /* PLL2 is not supported */
++ default:
++ break;
++ }
++
++ controllers_num = dal_adapter_service_get_controllers_num(
++ superbase->adapter_service);
++
++ pll_cs_dce110->registers = dc_service_alloc(
++ clk_src_init_data->ctx,
++ sizeof(struct registers) * controllers_num);
++
++ if (pll_cs_dce110->registers == NULL) {
++ ASSERT_CRITICAL(false);
++ goto failure;
++ }
++
++ /* Assign register address. No break between cases */
++ switch (controllers_num) {
++ case 6:
++ pll_cs_dce110->registers[5].dp_dtox_phase =
++ mmDP_DTO5_PHASE;
++ pll_cs_dce110->registers[5].dp_dtox_modulo =
++ mmDP_DTO5_MODULO;
++ pll_cs_dce110->registers[5].crtcx_pixel_rate_cntl =
++ mmCRTC5_PIXEL_RATE_CNTL;
++ /* fall through*/
++
++ case 5:
++ pll_cs_dce110->registers[4].dp_dtox_phase =
++ mmDP_DTO4_PHASE;
++ pll_cs_dce110->registers[4].dp_dtox_modulo =
++ mmDP_DTO4_MODULO;
++ pll_cs_dce110->registers[4].crtcx_pixel_rate_cntl =
++ mmCRTC4_PIXEL_RATE_CNTL;
++ /* fall through*/
++
++ case 4:
++ pll_cs_dce110->registers[3].dp_dtox_phase =
++ mmDP_DTO3_PHASE;
++ pll_cs_dce110->registers[3].dp_dtox_modulo =
++ mmDP_DTO3_MODULO;
++ pll_cs_dce110->registers[3].crtcx_pixel_rate_cntl =
++ mmCRTC3_PIXEL_RATE_CNTL;
++ /* fall through*/
++
++ case 3:
++ pll_cs_dce110->registers[2].dp_dtox_phase =
++ mmDP_DTO2_PHASE;
++ pll_cs_dce110->registers[2].dp_dtox_modulo =
++ mmDP_DTO2_MODULO;
++ pll_cs_dce110->registers[2].crtcx_pixel_rate_cntl =
++ mmCRTC2_PIXEL_RATE_CNTL;
++ /* fall through*/
++
++ case 2:
++ pll_cs_dce110->registers[1].dp_dtox_phase =
++ mmDP_DTO1_PHASE;
++ pll_cs_dce110->registers[1].dp_dtox_modulo =
++ mmDP_DTO1_MODULO;
++ pll_cs_dce110->registers[1].crtcx_pixel_rate_cntl =
++ mmCRTC1_PIXEL_RATE_CNTL;
++ /* fall through*/
++
++ case 1:
++ pll_cs_dce110->registers[0].dp_dtox_phase =
++ mmDP_DTO0_PHASE;
++ pll_cs_dce110->registers[0].dp_dtox_modulo =
++ mmDP_DTO0_MODULO;
++ pll_cs_dce110->registers[0].crtcx_pixel_rate_cntl =
++ mmCRTC0_PIXEL_RATE_CNTL;
++
++ break;
++
++ default:
++ ASSERT_CRITICAL(false);
++ goto failure;
++ }
++
++ ss_info_from_atombios_create(pll_cs_dce110);
++
++ return true;
++
++failure:
++ destruct(pll_cs_dce110);
++
++ return false;
++}
++
++struct clock_source *dal_pll_clock_source_dce110_create(
++ struct clock_source_init_data *clk_src_init_data)
++{
++ struct pll_clock_source_dce110 *clk_src =
++ dc_service_alloc(clk_src_init_data->ctx, sizeof(struct pll_clock_source_dce110));
++
++ if (clk_src == NULL)
++ return NULL;
++
++ if (!construct(clk_src, clk_src_init_data)) {
++ dc_service_free(clk_src_init_data->ctx, clk_src);
++ return NULL;
++ }
++ return &(clk_src->base.base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/pll_clock_source_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/pll_clock_source_dce110.h
+new file mode 100644
+index 0000000..166b29a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/pll_clock_source_dce110.h
+@@ -0,0 +1,55 @@
++/* 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_PLL_CLOCK_SOURCE_DCE110_H__
++#define __DAL_PLL_CLOCK_SOURCE_DCE110_H__
++
++#include "../pll_clock_source.h"
++#include "../calc_pll_clock_source.h"
++
++struct pll_clock_source_dce110 {
++ struct pll_clock_source base;
++
++ struct calc_pll_clock_source calc_pll_clock_source;
++/* object for normal circumstances, SS = 0 or SS >= 0.2% (LVDS or DP)
++ * or even for SS =~0.02 (DVI) */
++
++ struct calc_pll_clock_source calc_pll_clock_source_hdmi;
++/* object for HDMI no SS or SS <= 0.06% */
++
++ struct registers *registers;
++
++ uint32_t pixclkx_resync_cntl;
++ uint32_t ppll_fb_div;
++ uint32_t ppll_ref_div;
++ uint32_t ppll_post_div;
++ uint32_t pxpll_ds_cntl;
++ uint32_t pxpll_ss_cntl;
++ uint32_t pxpll_ss_dsfrac;
++ uint32_t pxpll_cntl;
++};
++
++struct clock_source *dal_pll_clock_source_dce110_create(
++ struct clock_source_init_data *clk_src_init_data);
++
++#endif /*__DAL_PLL_CLOCK_SOURCE_DCE110__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/vce_clock_source_dce110.c b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/vce_clock_source_dce110.c
+new file mode 100644
+index 0000000..ce59228
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/vce_clock_source_dce110.c
+@@ -0,0 +1,193 @@
++/* 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 "dal_services.h"
++#include "vce_clock_source_dce110.h"
++#include "include/clock_source_types.h"
++#include "include/bios_parser_interface.h"
++#include "include/logger_interface.h"
++
++struct vce_clock_source_dce110 {
++ struct clock_source base;
++ uint32_t ref_freq_khz;
++};
++
++static uint32_t get_pix_clk_dividers(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ struct vce_clock_source_dce110 *vce_clk_src_dce110 =
++ container_of(
++ clk_src,
++ struct vce_clock_source_dce110,
++ base);
++ if (pix_clk_params == NULL ||
++ pll_settings == NULL ||
++ pix_clk_params->requested_pix_clk == 0) {
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Invalid parameters!!", __func__);
++ return MAX_PLL_CALC_ERROR;
++ }
++
++ dc_service_memset(pll_settings, 0, sizeof(struct pll_settings));
++ pll_settings->reference_freq = vce_clk_src_dce110->ref_freq_khz;
++ pll_settings->actual_pix_clk =
++ pix_clk_params->requested_pix_clk;
++ pll_settings->adjusted_pix_clk =
++ pix_clk_params->requested_pix_clk;
++ pll_settings->calculated_pix_clk =
++ pix_clk_params->requested_pix_clk;
++
++ return 0;
++}
++static bool program_pix_clk(struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ struct bp_pixel_clock_parameters bp_pix_clk_params = { 0 };
++
++ if (pll_settings->actual_pix_clk == 0)
++ return false;
++ /* this is SimNow for Nutmeg*/
++
++ bp_pix_clk_params.controller_id = pix_clk_params->controller_id;
++ bp_pix_clk_params.pll_id = clk_src->clk_src_id;
++ bp_pix_clk_params.target_pixel_clock = pll_settings->actual_pix_clk;
++ bp_pix_clk_params.encoder_object_id = pix_clk_params->encoder_object_id;
++ bp_pix_clk_params.signal_type = pix_clk_params->signal_type;
++
++ if (dal_bios_parser_set_pixel_clock(clk_src->bios_parser,
++ &bp_pix_clk_params) == BP_RESULT_OK)
++ return true;
++
++ return false;
++}
++
++static bool power_down_pll(struct clock_source *clk_src,
++ enum controller_id controller_id)
++{
++ return true;
++}
++
++static void destruct(
++ struct vce_clock_source_dce110 *vce_clk_src)
++{
++
++}
++
++static void destroy(
++ struct clock_source **clk_src)
++{
++ struct vce_clock_source_dce110 *vce_clk_src;
++
++ vce_clk_src =
++ container_of(*clk_src, struct vce_clock_source_dce110, base);
++
++ destruct(vce_clk_src);
++ dc_service_free((*clk_src)->ctx, vce_clk_src);
++
++ *clk_src = NULL;
++}
++
++static const struct clock_source_impl funcs = {
++ .program_pix_clk = program_pix_clk,
++ .adjust_pll_pixel_rate = dal_clock_source_base_adjust_pll_pixel_rate,
++ .adjust_dto_pixel_rate = dal_clock_source_base_adjust_dto_pix_rate,
++ .retrieve_pll_pix_rate_hz =
++ dal_clock_source_base_retrieve_pll_pix_rate_hz,
++ .get_pix_clk_dividers = get_pix_clk_dividers,
++ .destroy = destroy,
++ .retrieve_dto_pix_rate_hz =
++ dal_clock_source_base_retrieve_dto_pix_rate_hz,
++ .power_down_pll = power_down_pll,
++};
++
++static bool construct(
++ struct vce_clock_source_dce110 *vce_clk_src,
++ struct clock_source_init_data *clk_src_init_data)
++{
++ struct firmware_info fw_info = { { 0 } };
++
++ if (!dal_clock_source_construct(
++ &vce_clk_src->base, clk_src_init_data)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ if (vce_clk_src->base.clk_src_id != CLOCK_SOURCE_ID_VCE) {
++ dal_logger_write(clk_src_init_data->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "Invalid ClockSourceId = %d!\n",
++ vce_clk_src->base.clk_src_id);
++ ASSERT_CRITICAL(false);
++ dal_logger_write(clk_src_init_data->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_GPU,
++ "Failed to create DCE110VceClockSource.\n");
++ return false;
++ }
++
++ vce_clk_src->base.funcs = &funcs;
++ vce_clk_src->base.clk_sharing_lvl = CLOCK_SHARING_LEVEL_NOT_SHAREABLE;
++ vce_clk_src->base.is_clock_source_with_fixed_freq = false;
++
++
++ /*VCE clock source only supports SignalType_Wireless*/
++ vce_clk_src->base.output_signals |= SIGNAL_TYPE_WIRELESS;
++
++ /*Get Reference frequency, Input frequency range into PLL
++ * and Output frequency range of the PLL
++ * from ATOMBIOS Data table */
++ if (dal_bios_parser_get_firmware_info(
++ vce_clk_src->base.bios_parser,
++ &fw_info) != BP_RESULT_OK)
++ return false;
++
++ vce_clk_src->ref_freq_khz = fw_info.pll_info.crystal_frequency;
++
++ return true;
++}
++
++
++struct clock_source *dal_vce_clock_source_dce110_create(
++ struct clock_source_init_data *clk_src_init_data)
++
++{
++ struct vce_clock_source_dce110 *clk_src;
++
++ clk_src = dc_service_alloc(clk_src_init_data->ctx, sizeof(struct vce_clock_source_dce110));
++
++ if (clk_src == NULL)
++ return NULL;
++
++ if (!construct(clk_src, clk_src_init_data)) {
++ dc_service_free(clk_src_init_data->ctx, clk_src);
++ return NULL;
++ }
++
++ return &clk_src->base;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/dce110/vce_clock_source_dce110.h b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/vce_clock_source_dce110.h
+new file mode 100644
+index 0000000..227b169
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/dce110/vce_clock_source_dce110.h
+@@ -0,0 +1,32 @@
++/* 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_VCE_CLOCK_SOURCE_DCE110__
++#define __DAL_VCE_CLOCK_SOURCE_DCE110__
++
++#include "../clock_source.h"
++
++struct clock_source *dal_vce_clock_source_dce110_create(
++ struct clock_source_init_data *clk_src_init_data);
++
++#endif /*__DAL_VCE_CLOCK_SOURCE_DCE110__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c b/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c
+new file mode 100644
+index 0000000..a11aa84
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.c
+@@ -0,0 +1,204 @@
++/*
++ * 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 "dal_services.h"
++#include "display_clock.h"
++#include "adapter_service_interface.h"
++
++void dal_display_clock_base_set_dp_ref_clock_source(
++ struct display_clock *disp_clk,
++ enum clock_source_id clk_src)
++{/*must be implemented in derived*/
++
++}
++
++void dal_display_clock_base_set_clock_state(struct display_clock *disp_clk,
++ struct display_clock_state clk_state)
++{
++ /*Implemented only in DCE81*/
++}
++struct display_clock_state dal_display_clock_base_get_clock_state(
++ struct display_clock *disp_clk)
++{
++ /*Implemented only in DCE81*/
++ struct display_clock_state state = {0};
++ return state;
++}
++uint32_t dal_display_clock_base_get_dfs_bypass_threshold(
++ struct display_clock *disp_clk)
++{
++ /*Implemented only in DCE81*/
++ return 0;
++}
++
++bool dal_display_clock_construct_base(
++ struct display_clock *base,
++ struct dc_context *ctx,
++ struct adapter_service *as)
++{
++ base->ctx = ctx;
++ base->id = CLOCK_SOURCE_ID_DCPLL;
++ base->min_display_clk_threshold_khz = 0;
++ base->as = as;
++
++/* Initially set current min clocks state to invalid since we
++ * cannot make any assumption about PPLIB's initial state. This will be updated
++ * by HWSS via SetMinClocksState() on first mode set prior to programming
++ * state dependent clocks.*/
++ base->cur_min_clks_state = CLOCKS_STATE_INVALID;
++
++ return true;
++}
++
++void dal_display_clock_destroy(struct display_clock **disp_clk)
++{
++ if (!disp_clk || !*disp_clk) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ (*disp_clk)->funcs->destroy(disp_clk);
++
++ *disp_clk = NULL;
++}
++
++bool dal_display_clock_validate(
++ struct display_clock *disp_clk,
++ struct min_clock_params *params)
++{
++ return disp_clk->funcs->validate(disp_clk, params);
++}
++
++uint32_t dal_display_clock_calculate_min_clock(
++ struct display_clock *disp_clk,
++ uint32_t path_num,
++ struct min_clock_params *params)
++{
++ return disp_clk->funcs->calculate_min_clock(disp_clk, path_num, params);
++}
++
++uint32_t dal_display_clock_get_validation_clock(struct display_clock *disp_clk)
++{
++ return disp_clk->funcs->get_validation_clock(disp_clk);
++}
++
++void dal_display_clock_set_clock(
++ struct display_clock *disp_clk,
++ uint32_t requested_clock_khz)
++{
++ disp_clk->funcs->set_clock(disp_clk, requested_clock_khz);
++}
++
++uint32_t dal_display_clock_get_clock(struct display_clock *disp_clk)
++{
++ return disp_clk->funcs->get_clock(disp_clk);
++}
++
++enum clocks_state dal_display_clock_get_min_clocks_state(
++ struct display_clock *disp_clk)
++{
++ return disp_clk->funcs->get_min_clocks_state(disp_clk);
++}
++
++enum clocks_state dal_display_clock_get_required_clocks_state(
++ struct display_clock *disp_clk,
++ struct state_dependent_clocks *req_clocks)
++{
++ return disp_clk->funcs->get_required_clocks_state(disp_clk, req_clocks);
++}
++
++bool dal_display_clock_set_min_clocks_state(
++ struct display_clock *disp_clk,
++ enum clocks_state clocks_state)
++{
++ return disp_clk->funcs->set_min_clocks_state(disp_clk, clocks_state);
++}
++
++uint32_t dal_display_clock_get_dp_ref_clk_frequency(
++ struct display_clock *disp_clk)
++{
++ return disp_clk->funcs->get_dp_ref_clk_frequency(disp_clk);
++}
++
++/*the second parameter of "switchreferenceclock" is
++ * a dummy argument for all pre dce 6.0 versions*/
++
++void dal_display_clock_switch_reference_clock(
++ struct display_clock *disp_clk,
++ bool use_external_ref_clk,
++ uint32_t requested_clk_khz)
++{
++ /* TODO: requires Asic Control*/
++ /*
++ struct ac_pixel_clk_params params;
++ struct asic_control *ac =
++ dal_adapter_service_get_asic_control(disp_clk->as);
++ dc_service_memset(&params, 0, sizeof(struct ac_pixel_clk_params));
++
++ params.tgt_pixel_clk_khz = requested_clk_khz;
++ params.flags.SET_EXTERNAL_REF_DIV_SRC = use_external_ref_clk;
++ params.pll_id = disp_clk->id;
++ dal_asic_control_program_display_engine_pll(ac, &params);
++ */
++}
++
++void dal_display_clock_set_dp_ref_clock_source(
++ struct display_clock *disp_clk,
++ enum clock_source_id clk_src)
++{
++ disp_clk->funcs->set_dp_ref_clock_source(disp_clk, clk_src);
++}
++
++void dal_display_clock_store_max_clocks_state(
++ struct display_clock *disp_clk,
++ enum clocks_state max_clocks_state)
++{
++ disp_clk->funcs->store_max_clocks_state(disp_clk, max_clocks_state);
++}
++
++void dal_display_clock_set_clock_state(
++ struct display_clock *disp_clk,
++ struct display_clock_state clk_state)
++{
++ disp_clk->funcs->set_clock_state(disp_clk, clk_state);
++}
++
++struct display_clock_state dal_display_clock_get_clock_state(
++ struct display_clock *disp_clk)
++{
++ return disp_clk->funcs->get_clock_state(disp_clk);
++}
++
++uint32_t dal_display_clock_get_dfs_bypass_threshold(
++ struct display_clock *disp_clk)
++{
++ return disp_clk->funcs->get_dfs_bypass_threshold(disp_clk);
++}
++
++void dal_display_clock_invalid_clock_state(
++ struct display_clock *disp_clk)
++{
++ disp_clk->cur_min_clks_state = CLOCKS_STATE_INVALID;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h b/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h
+new file mode 100644
+index 0000000..845393b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/display_clock.h
+@@ -0,0 +1,82 @@
++/*
++ * 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_DISPLAY_CLOCK_H__
++#define __DAL_DISPLAY_CLOCK_H__
++
++#include "include/display_clock_interface.h"
++
++struct display_clock_funcs {
++ void (*destroy)(struct display_clock **to_destroy);
++ bool (*validate)(struct display_clock *disp_clk,
++ struct min_clock_params *params);
++ uint32_t (*calculate_min_clock)(struct display_clock *disp_clk,
++ uint32_t path_num, struct min_clock_params *params);
++ uint32_t (*get_validation_clock)(struct display_clock *disp_clk);
++ void (*set_clock)(struct display_clock *disp_clk,
++ uint32_t requested_clock_khz);
++ uint32_t (*get_clock)(struct display_clock *disp_clk);
++ enum clocks_state (*get_min_clocks_state)(
++ struct display_clock *disp_clk);
++ enum clocks_state (*get_required_clocks_state)(
++ struct display_clock *disp_clk,
++ struct state_dependent_clocks *req_clocks);
++ bool (*set_min_clocks_state)(struct display_clock *disp_clk,
++ enum clocks_state clocks_state);
++ uint32_t (*get_dp_ref_clk_frequency)(struct display_clock *disp_clk);
++ void (*set_dp_ref_clock_source)(struct display_clock *disp_clk,
++ enum clock_source_id clk_src);
++ void (*store_max_clocks_state)(struct display_clock *disp_clk,
++ enum clocks_state max_clocks_state);
++ void (*set_clock_state)(struct display_clock *disp_clk,
++ struct display_clock_state clk_state);
++ struct display_clock_state (*get_clock_state)(
++ struct display_clock *disp_clk);
++ uint32_t (*get_dfs_bypass_threshold)(struct display_clock *disp_clk);
++};
++
++struct display_clock {
++ struct dc_context *ctx;
++ const struct display_clock_funcs *funcs;
++ uint32_t min_display_clk_threshold_khz;
++ enum clock_source_id id;
++ struct adapter_service *as;
++
++ enum clocks_state cur_min_clks_state;
++};
++void dal_display_clock_base_set_dp_ref_clock_source(
++ struct display_clock *disp_clk,
++ enum clock_source_id clk_src);
++struct display_clock_state dal_display_clock_base_get_clock_state(
++ struct display_clock *disp_clk);
++uint32_t dal_display_clock_base_get_dfs_bypass_threshold(
++ struct display_clock *disp_clk);
++void dal_display_clock_base_set_clock_state(struct display_clock *disp_clk,
++ struct display_clock_state clk_state);
++bool dal_display_clock_construct_base(
++ struct display_clock *base,
++ struct dc_context *ctx,
++ struct adapter_service *as);
++#endif /* __DAL_DISPLAY_CLOCK_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c b/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c
+new file mode 100644
+index 0000000..3b04447
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.c
+@@ -0,0 +1,127 @@
++/*
++ * 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 "dal_services.h"
++#include "divider_range.h"
++
++bool dal_divider_range_construct(
++ struct divider_range *div_range,
++ uint32_t range_start,
++ uint32_t range_step,
++ uint32_t did_min,
++ uint32_t did_max)
++{
++ div_range->div_range_start = range_start;
++ div_range->div_range_step = range_step;
++ div_range->did_min = did_min;
++ div_range->did_max = did_max;
++
++ if (div_range->div_range_step == 0) {
++ div_range->div_range_step = 1;
++ /*div_range_step cannot be zero*/
++ BREAK_TO_DEBUGGER();
++ }
++ /* Calculate this based on the other inputs.*/
++ /* See DividerRange.h for explanation of */
++ /* the relationship between divider id (DID) and a divider.*/
++ /* Number of Divider IDs = (Maximum Divider ID - Minimum Divider ID)*/
++ /* Maximum divider identified in this range =
++ * (Number of Divider IDs)*Step size between dividers
++ * + The start of this range.*/
++ div_range->div_range_end = (did_max - did_min) * range_step
++ + range_start;
++ return true;
++}
++
++static uint32_t dal_divider_range_calc_divider(
++ struct divider_range *div_range,
++ uint32_t did)
++{
++ /* Is this DID within our range?*/
++ if ((did < div_range->did_min) || (did >= div_range->did_max))
++ return INVALID_DIVIDER;
++
++ return ((did - div_range->did_min) * div_range->div_range_step)
++ + div_range->div_range_start;
++
++}
++
++static uint32_t dal_divider_range_calc_did(
++ struct divider_range *div_range,
++ uint32_t div)
++{
++ uint32_t did;
++ /* Check before dividing.*/
++ if (div_range->div_range_step == 0) {
++ div_range->div_range_step = 1;
++ /*div_range_step cannot be zero*/
++ BREAK_TO_DEBUGGER();
++ }
++ /* Is this divider within our range?*/
++ if ((div < div_range->div_range_start)
++ || (div >= div_range->div_range_end))
++ return INVALID_DID;
++/* did = (divider - range_start + (range_step-1)) / range_step) + did_min*/
++ did = div - div_range->div_range_start;
++ did += div_range->div_range_step - 1;
++ did /= div_range->div_range_step;
++ did += div_range->did_min;
++ return did;
++}
++
++uint32_t dal_divider_range_get_divider(
++ struct divider_range *div_range,
++ uint32_t ranges_num,
++ uint32_t did)
++{
++ uint32_t div = INVALID_DIVIDER;
++ uint32_t i;
++
++ for (i = 0; i < ranges_num; i++) {
++ /* Calculate divider with given divider ID*/
++ div = dal_divider_range_calc_divider(&div_range[i], did);
++ /* Found a valid return divider*/
++ if (div != INVALID_DIVIDER)
++ break;
++ }
++ return div;
++}
++uint32_t dal_divider_range_get_did(
++ struct divider_range *div_range,
++ uint32_t ranges_num,
++ uint32_t divider)
++{
++ uint32_t did = INVALID_DID;
++ uint32_t i;
++
++ for (i = 0; i < ranges_num; i++) {
++ /* CalcDid returns InvalidDid if a divider ID isn't found*/
++ did = dal_divider_range_calc_did(&div_range[i], divider);
++ /* Found a valid return did*/
++ if (did != INVALID_DID)
++ break;
++ }
++ return did;
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h b/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h
+new file mode 100644
+index 0000000..2ec1034
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/divider_range.h
+@@ -0,0 +1,63 @@
++/*
++ * 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_DIVIDER_RANGE_H__
++#define __DAL_DIVIDER_RANGE_H__
++
++enum divider_error_types {
++ INVALID_DID = 0,
++ INVALID_DIVIDER = 1
++};
++
++struct divider_range {
++ uint32_t div_range_start;
++ /* The end of this range of dividers.*/
++ uint32_t div_range_end;
++ /* The distance between each divider in this range.*/
++ uint32_t div_range_step;
++ /* The divider id for the lowest divider.*/
++ uint32_t did_min;
++ /* The divider id for the highest divider.*/
++ uint32_t did_max;
++};
++
++bool dal_divider_range_construct(
++ struct divider_range *div_range,
++ uint32_t range_start,
++ uint32_t range_step,
++ uint32_t did_min,
++ uint32_t did_max);
++
++uint32_t dal_divider_range_get_divider(
++ struct divider_range *div_range,
++ uint32_t ranges_num,
++ uint32_t did);
++uint32_t dal_divider_range_get_did(
++ struct divider_range *div_range,
++ uint32_t ranges_num,
++ uint32_t divider);
++
++
++#endif /* __DAL_DIVIDER_RANGE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.c b/drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.c
+new file mode 100644
+index 0000000..ac27cd7
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.c
+@@ -0,0 +1,119 @@
++/* 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 "dal_services.h"
++#include "include/clock_source_types.h"
++#include "include/bios_parser_interface.h"
++#include "include/logger_interface.h"
++#include "ext_clock_source.h"
++
++uint32_t dal_ext_clock_source_get_pix_clk_dividers(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ struct ext_clock_source *ext_clk_src = container_of(
++ clk_src,
++ struct ext_clock_source,
++ base);
++
++ if (pix_clk_params == NULL ||
++ pll_settings == NULL ||
++ pix_clk_params->requested_pix_clk == 0) {
++ dal_logger_write(clk_src->ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_GPU,
++ "%s: Invalid parameters!!", __func__);
++ return MAX_PLL_CALC_ERROR;
++ }
++
++ dc_service_memset(pll_settings, 0, sizeof(struct pll_settings));
++ pll_settings->adjusted_pix_clk = ext_clk_src->ext_clk_freq_khz;
++ pll_settings->calculated_pix_clk = ext_clk_src->ext_clk_freq_khz;
++ pll_settings->actual_pix_clk =
++ pix_clk_params->requested_pix_clk;
++ return 0;
++}
++
++bool dal_ext_clock_source_program_pix_clk(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ struct bp_pixel_clock_parameters bp_pix_clk_params = {0};
++
++ bp_pix_clk_params.controller_id = pix_clk_params->controller_id;
++ bp_pix_clk_params.pll_id = clk_src->clk_src_id;
++ bp_pix_clk_params.target_pixel_clock =
++ pix_clk_params->requested_pix_clk;
++ bp_pix_clk_params.encoder_object_id = pix_clk_params->encoder_object_id;
++ bp_pix_clk_params.signal_type = pix_clk_params->signal_type;
++ bp_pix_clk_params.dvo_config = pix_clk_params->dvo_cfg;
++
++
++ if (dal_bios_parser_set_pixel_clock(
++ clk_src->bios_parser,
++ &bp_pix_clk_params) == BP_RESULT_OK)
++ return true;
++ return false;
++
++}
++
++bool dal_ext_clock_source_power_down_pll(struct clock_source *clk_src,
++ enum controller_id controller_id)
++{
++ return true;
++}
++
++bool dal_ext_clock_source_construct(
++ struct ext_clock_source *ext_clk_src,
++ struct clock_source_init_data *clk_src_init_data)
++{
++ struct firmware_info fw_info = { { 0 } };
++
++ if (!dal_clock_source_construct(
++ &ext_clk_src->base, clk_src_init_data)) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ ext_clk_src->base.clk_sharing_lvl =
++ CLOCK_SHARING_LEVEL_DISPLAY_PORT_SHAREABLE;
++ ext_clk_src->base.is_clock_source_with_fixed_freq = true;
++ /* ExtClock has fixed frequency,
++ * so it supports only DisplayPort signals.*/
++ ext_clk_src->base.output_signals =
++ SIGNAL_TYPE_DISPLAY_PORT |
++ SIGNAL_TYPE_DISPLAY_PORT_MST |
++ SIGNAL_TYPE_EDP;
++
++ /*Get External clock frequency from ATOMBIOS Data table */
++ if (dal_bios_parser_get_firmware_info(
++ ext_clk_src->base.bios_parser,
++ &fw_info) != BP_RESULT_OK)
++ return false;
++ ext_clk_src->ext_clk_freq_khz = fw_info.
++ external_clock_source_frequency_for_dp;
++ return true;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.h b/drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.h
+new file mode 100644
+index 0000000..bef1dc4
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/ext_clock_source.h
+@@ -0,0 +1,47 @@
++/* 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_EXT_CLOCK_SOURCE_H__
++#define __DAL_EXT_CLOCK_SOURCE_H__
++
++#include "clock_source.h"
++
++struct ext_clock_source {
++ struct clock_source base;
++ uint32_t ext_clk_freq_khz;
++};
++
++bool dal_ext_clock_source_construct(
++ struct ext_clock_source *ext_cs,
++ struct clock_source_init_data *clk_src_init_data);
++bool dal_ext_clock_source_power_down_pll(struct clock_source *clk_src,
++ enum controller_id controller_id);
++uint32_t dal_ext_clock_source_get_pix_clk_dividers(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings);
++bool dal_ext_clock_source_program_pix_clk(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings);
++#endif /*__DAL_EXT_CLOCK_SOURCE_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.c b/drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.c
+new file mode 100644
+index 0000000..8bb0304
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.c
+@@ -0,0 +1,141 @@
++/* 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 "dal_services.h"
++#include "include/bios_parser_interface.h"
++#include "pll_clock_source.h"
++
++bool dal_pll_clock_source_power_down_pll(
++ struct clock_source *clk_src,
++ enum controller_id controller_id)
++{
++
++ enum bp_result bp_result;
++ struct bp_pixel_clock_parameters bp_pixel_clock_params = {0};
++
++ /* If Pixel Clock is 0 it means Power Down Pll*/
++ bp_pixel_clock_params.controller_id = controller_id;
++ bp_pixel_clock_params.pll_id = clk_src->clk_src_id;
++ bp_pixel_clock_params.flags.FORCE_PROGRAMMING_OF_PLL = 1;
++
++ /*Call ASICControl to process ATOMBIOS Exec table*/
++ bp_result = dal_bios_parser_set_pixel_clock(
++ clk_src->bios_parser,
++ &bp_pixel_clock_params);
++
++ return bp_result == BP_RESULT_OK;
++}
++
++bool dal_pll_clock_source_adjust_pix_clk(
++ struct pll_clock_source *pll_clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings)
++{
++ uint32_t actual_pix_clk_khz = 0;
++ uint32_t requested_clk_khz = 0;
++ struct bp_adjust_pixel_clock_parameters bp_adjust_pixel_clock_params = {
++ 0 };
++ enum bp_result bp_result;
++
++ switch (pix_clk_params->signal_type) {
++ case SIGNAL_TYPE_HDMI_TYPE_A: {
++ requested_clk_khz = pix_clk_params->requested_pix_clk;
++
++ switch (pix_clk_params->color_depth) {
++ case COLOR_DEPTH_101010:
++ requested_clk_khz = (requested_clk_khz * 5) >> 2;
++ break; /* x1.25*/
++ case COLOR_DEPTH_121212:
++ requested_clk_khz = (requested_clk_khz * 6) >> 2;
++ break; /* x1.5*/
++ case COLOR_DEPTH_161616:
++ requested_clk_khz = requested_clk_khz * 2;
++ break; /* x2.0*/
++ default:
++ break;
++ }
++
++ actual_pix_clk_khz = requested_clk_khz;
++ }
++ break;
++
++ case SIGNAL_TYPE_DISPLAY_PORT:
++ case SIGNAL_TYPE_DISPLAY_PORT_MST:
++ case SIGNAL_TYPE_EDP:
++ requested_clk_khz = pix_clk_params->requested_sym_clk;
++ actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
++ break;
++
++ default:
++ requested_clk_khz = pix_clk_params->requested_pix_clk;
++ actual_pix_clk_khz = pix_clk_params->requested_pix_clk;
++ break;
++ }
++
++ bp_adjust_pixel_clock_params.pixel_clock = requested_clk_khz;
++ bp_adjust_pixel_clock_params.
++ encoder_object_id = pix_clk_params->encoder_object_id;
++ bp_adjust_pixel_clock_params.signal_type = pix_clk_params->signal_type;
++ bp_adjust_pixel_clock_params.dvo_config = pix_clk_params->dvo_cfg;
++ bp_adjust_pixel_clock_params.
++ display_pll_config = pix_clk_params->disp_pll_cfg;
++ bp_adjust_pixel_clock_params.
++ ss_enable = pix_clk_params->flags.ENABLE_SS;
++ bp_result = dal_bios_parser_adjust_pixel_clock(
++ pll_clk_src->base.bios_parser,
++ &bp_adjust_pixel_clock_params);
++ if (bp_result == BP_RESULT_OK) {
++ pll_settings->actual_pix_clk = actual_pix_clk_khz;
++ pll_settings->adjusted_pix_clk =
++ bp_adjust_pixel_clock_params.adjusted_pixel_clock;
++ pll_settings->reference_divider =
++ bp_adjust_pixel_clock_params.reference_divider;
++ pll_settings->pix_clk_post_divider =
++ bp_adjust_pixel_clock_params.pixel_clock_post_divider;
++
++ return true;
++ }
++
++ return false;
++}
++
++bool dal_pll_clock_source_construct(
++ struct pll_clock_source *pll_clk_src,
++ struct clock_source_init_data *clk_src_init_data)
++{
++ struct firmware_info fw_info = { { 0 } };
++
++ if (!dal_clock_source_construct(
++ &pll_clk_src->base,
++ clk_src_init_data))
++ return false;
++
++ if (dal_bios_parser_get_firmware_info(
++ pll_clk_src->base.bios_parser,
++ &fw_info) != BP_RESULT_OK)
++ return false;
++ pll_clk_src->ref_freq_khz = fw_info.pll_info.crystal_frequency;
++
++ return true;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.h b/drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.h
+new file mode 100644
+index 0000000..8339e1f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/gpu/pll_clock_source.h
+@@ -0,0 +1,52 @@
++/* 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_PLL_CLOCK_SOURCE_H__
++#define __DAL_PLL_CLOCK_SOURCE_H__
++
++#include "gpu/clock_source.h"
++
++struct pll_clock_source {
++ struct clock_source base;
++ uint32_t ref_freq_khz;
++};
++
++struct delta_sigma_data {
++ uint32_t feedback_amount;
++ uint32_t nfrac_amount;
++ uint32_t ds_frac_size;
++ uint32_t ds_frac_amount;
++};
++
++bool dal_pll_clock_source_construct(
++ struct pll_clock_source *pll_clk_src,
++ struct clock_source_init_data *clk_src_init_data);
++
++bool dal_pll_clock_source_adjust_pix_clk(
++ struct pll_clock_source *pll_clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings);
++bool dal_pll_clock_source_power_down_pll(
++ struct clock_source *clk_src,
++ enum controller_id controller_id);
++#endif /*__DAL_PLL_CLOCK_SOURCE_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/Makefile b/drivers/gpu/drm/amd/dal/dc/i2caux/Makefile
+new file mode 100644
+index 0000000..15902a8
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/Makefile
+@@ -0,0 +1,23 @@
++#
++# Makefile for the 'i2c' sub-component of DAL.
++# It provides the control and status of HW i2c engine of the adapter.
++
++I2CAUX = aux_engine.o engine_base.o i2caux.o i2c_engine.o \
++ i2c_generic_hw_engine.o i2c_hw_engine.o i2c_sw_engine.o
++
++AMD_DAL_I2CAUX = $(addprefix $(AMDDALPATH)/dc/i2caux/,$(I2CAUX))
++
++AMD_DAL_FILES += $(AMD_DAL_I2CAUX)
++
++
++###############################################################################
++# DCE 11x family
++###############################################################################
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++I2CAUX_DCE110 = i2caux_dce110.o i2c_sw_engine_dce110.o i2c_hw_engine_dce110.o \
++ aux_engine_dce110.o
++
++AMD_DAL_I2CAUX_DCE110 = $(addprefix $(AMDDALPATH)/dc/i2caux/dce110/,$(I2CAUX_DCE110))
++
++AMD_DAL_FILES += $(AMD_DAL_I2CAUX_DCE110)
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.c b/drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.c
+new file mode 100644
+index 0000000..824ceec
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.c
+@@ -0,0 +1,568 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "engine.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "aux_engine.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++#include "include/link_service_types.h"
++
++/*
++ * This unit
++ */
++
++enum {
++ AUX_INVALID_REPLY_RETRY_COUNTER = 1,
++ AUX_TIMED_OUT_RETRY_COUNTER = 2,
++ AUX_DEFER_RETRY_COUNTER = 6
++};
++
++#define FROM_ENGINE(ptr) \
++ container_of((ptr), struct aux_engine, base)
++
++enum i2caux_engine_type dal_aux_engine_get_engine_type(
++ const struct engine *engine)
++{
++ return I2CAUX_ENGINE_TYPE_AUX;
++}
++
++bool dal_aux_engine_acquire(
++ struct engine *engine,
++ struct ddc *ddc)
++{
++ struct aux_engine *aux_engine = FROM_ENGINE(engine);
++
++ enum gpio_result result;
++
++ result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
++ GPIO_DDC_CONFIG_TYPE_MODE_AUX);
++
++ if (result != GPIO_RESULT_OK)
++ return false;
++
++ if (!aux_engine->funcs->acquire_engine(aux_engine)) {
++ dal_ddc_close(ddc);
++ return false;
++ }
++
++ engine->ddc = ddc;
++
++ return true;
++}
++
++struct read_command_context {
++ uint8_t *buffer;
++ uint8_t current_read_length;
++ uint32_t offset;
++ enum i2caux_transaction_status status;
++
++ struct aux_request_transaction_data request;
++ struct aux_reply_transaction_data reply;
++
++ uint8_t returned_byte;
++
++ uint32_t timed_out_retry_aux;
++ uint32_t invalid_reply_retry_aux;
++ uint32_t defer_retry_aux;
++ uint32_t defer_retry_i2c;
++ uint32_t invalid_reply_retry_aux_on_ack;
++
++ bool transaction_complete;
++ bool operation_succeeded;
++};
++
++static void process_read_reply(
++ struct aux_engine *engine,
++ struct read_command_context *ctx)
++{
++ engine->funcs->process_channel_reply(engine, &ctx->reply);
++
++ switch (ctx->reply.status) {
++ case AUX_TRANSACTION_REPLY_AUX_ACK:
++ ctx->defer_retry_aux = 0;
++ if (ctx->returned_byte > ctx->current_read_length) {
++ ctx->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
++ ctx->operation_succeeded = false;
++ } else if (ctx->returned_byte < ctx->current_read_length) {
++ ctx->current_read_length -= ctx->returned_byte;
++
++ ctx->offset += ctx->returned_byte;
++
++ ++ctx->invalid_reply_retry_aux_on_ack;
++
++ if (ctx->invalid_reply_retry_aux_on_ack >
++ AUX_INVALID_REPLY_RETRY_COUNTER) {
++ ctx->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
++ ctx->operation_succeeded = false;
++ }
++ } else {
++ ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
++ ctx->transaction_complete = true;
++ ctx->operation_succeeded = true;
++ }
++ break;
++ case AUX_TRANSACTION_REPLY_AUX_NACK:
++ ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
++ ctx->operation_succeeded = false;
++ break;
++ case AUX_TRANSACTION_REPLY_AUX_DEFER:
++ ++ctx->defer_retry_aux;
++
++ if (ctx->defer_retry_aux > AUX_DEFER_RETRY_COUNTER) {
++ ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ ctx->operation_succeeded = false;
++ }
++ break;
++ case AUX_TRANSACTION_REPLY_I2C_DEFER:
++ ctx->defer_retry_aux = 0;
++
++ ++ctx->defer_retry_i2c;
++
++ if (ctx->defer_retry_i2c > AUX_DEFER_RETRY_COUNTER) {
++ ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ ctx->operation_succeeded = false;
++ }
++ break;
++ default:
++ ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
++ ctx->operation_succeeded = false;
++ }
++}
++
++static void process_read_request(
++ struct aux_engine *engine,
++ struct read_command_context *ctx)
++{
++ enum aux_channel_operation_result operation_result;
++
++ engine->funcs->submit_channel_request(engine, &ctx->request);
++
++ operation_result = engine->funcs->get_channel_status(
++ engine, &ctx->returned_byte);
++
++ switch (operation_result) {
++ case AUX_CHANNEL_OPERATION_SUCCEEDED:
++ if (ctx->returned_byte > ctx->current_read_length) {
++ ctx->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
++ ctx->operation_succeeded = false;
++ } else {
++ ctx->timed_out_retry_aux = 0;
++ ctx->invalid_reply_retry_aux = 0;
++
++ ctx->reply.length = ctx->returned_byte;
++ ctx->reply.data = ctx->buffer;
++
++ process_read_reply(engine, ctx);
++ }
++ break;
++ case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
++ ++ctx->invalid_reply_retry_aux;
++
++ if (ctx->invalid_reply_retry_aux >
++ AUX_INVALID_REPLY_RETRY_COUNTER) {
++ ctx->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
++ ctx->operation_succeeded = false;
++ } else
++ dc_service_delay_in_microseconds(engine->base.ctx, 400);
++ break;
++ case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
++ ++ctx->timed_out_retry_aux;
++
++ if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
++ ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ ctx->operation_succeeded = false;
++ } else {
++ /* DP 1.2a, table 2-58:
++ * "S3: AUX Request CMD PENDING:
++ * retry 3 times, with 400usec wait on each"
++ * The HW timeout is set to 550usec,
++ * so we should not wait here */
++ }
++ break;
++ default:
++ ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
++ ctx->operation_succeeded = false;
++ }
++}
++
++static bool read_command(
++ struct aux_engine *engine,
++ struct i2caux_transaction_request *request,
++ bool middle_of_transaction)
++{
++ struct read_command_context ctx;
++
++ ctx.buffer = request->payload.data;
++ ctx.current_read_length = request->payload.length;
++ ctx.offset = 0;
++ ctx.timed_out_retry_aux = 0;
++ ctx.invalid_reply_retry_aux = 0;
++ ctx.defer_retry_aux = 0;
++ ctx.defer_retry_i2c = 0;
++ ctx.invalid_reply_retry_aux_on_ack = 0;
++ ctx.transaction_complete = false;
++ ctx.operation_succeeded = true;
++
++ if (request->payload.address_space ==
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
++ ctx.request.type = AUX_TRANSACTION_TYPE_DP;
++ ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_READ;
++ ctx.request.address = request->payload.address;
++ } else if (request->payload.address_space ==
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
++ ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
++ ctx.request.action = middle_of_transaction ?
++ I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
++ I2CAUX_TRANSACTION_ACTION_I2C_READ;
++ ctx.request.address = request->payload.address >> 1;
++ } else {
++ /* in DAL2, there was no return in such case */
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ ctx.request.delay = 0;
++
++ do {
++ dc_service_memset(ctx.buffer + ctx.offset, 0, ctx.current_read_length);
++
++ ctx.request.data = ctx.buffer + ctx.offset;
++ ctx.request.length = ctx.current_read_length;
++
++ process_read_request(engine, &ctx);
++
++ request->status = ctx.status;
++
++ if (ctx.operation_succeeded && !ctx.transaction_complete)
++ if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
++ dc_service_sleep_in_milliseconds(engine->base.ctx, engine->delay);
++ } while (ctx.operation_succeeded && !ctx.transaction_complete);
++
++ return ctx.operation_succeeded;
++}
++
++struct write_command_context {
++ bool mot;
++
++ uint8_t *buffer;
++ uint8_t current_write_length;
++ enum i2caux_transaction_status status;
++
++ struct aux_request_transaction_data request;
++ struct aux_reply_transaction_data reply;
++
++ uint8_t returned_byte;
++
++ uint32_t timed_out_retry_aux;
++ uint32_t invalid_reply_retry_aux;
++ uint32_t defer_retry_aux;
++ uint32_t defer_retry_i2c;
++ uint32_t max_defer_retry;
++ uint32_t ack_m_retry;
++
++ uint8_t reply_data[DEFAULT_AUX_MAX_DATA_SIZE];
++
++ bool transaction_complete;
++ bool operation_succeeded;
++};
++
++static void process_write_reply(
++ struct aux_engine *engine,
++ struct write_command_context *ctx)
++{
++ engine->funcs->process_channel_reply(engine, &ctx->reply);
++
++ switch (ctx->reply.status) {
++ case AUX_TRANSACTION_REPLY_AUX_ACK:
++ ctx->operation_succeeded = true;
++
++ if (ctx->returned_byte) {
++ ctx->request.action = ctx->mot ?
++ I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
++ I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
++
++ ctx->current_write_length = 0;
++
++ ++ctx->ack_m_retry;
++
++ if (ctx->ack_m_retry > AUX_DEFER_RETRY_COUNTER) {
++ ctx->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ ctx->operation_succeeded = false;
++ } else
++ dc_service_delay_in_microseconds(engine->base.ctx, 300);
++ } else {
++ ctx->status = I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
++ ctx->defer_retry_aux = 0;
++ ctx->ack_m_retry = 0;
++ ctx->transaction_complete = true;
++ }
++ break;
++ case AUX_TRANSACTION_REPLY_AUX_NACK:
++ ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
++ ctx->operation_succeeded = false;
++ break;
++ case AUX_TRANSACTION_REPLY_AUX_DEFER:
++ ++ctx->defer_retry_aux;
++
++ if (ctx->defer_retry_aux > ctx->max_defer_retry) {
++ ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ ctx->operation_succeeded = false;
++ }
++ break;
++ case AUX_TRANSACTION_REPLY_I2C_DEFER:
++ ctx->defer_retry_aux = 0;
++ ctx->current_write_length = 0;
++
++ ctx->request.action = ctx->mot ?
++ I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT :
++ I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST;
++
++ ++ctx->defer_retry_i2c;
++
++ if (ctx->defer_retry_i2c > ctx->max_defer_retry) {
++ ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ ctx->operation_succeeded = false;
++ }
++ break;
++ default:
++ ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
++ ctx->operation_succeeded = false;
++ }
++}
++
++static void process_write_request(
++ struct aux_engine *engine,
++ struct write_command_context *ctx)
++{
++ enum aux_channel_operation_result operation_result;
++
++ engine->funcs->submit_channel_request(engine, &ctx->request);
++
++ operation_result = engine->funcs->get_channel_status(
++ engine, &ctx->returned_byte);
++
++ switch (operation_result) {
++ case AUX_CHANNEL_OPERATION_SUCCEEDED:
++ ctx->timed_out_retry_aux = 0;
++ ctx->invalid_reply_retry_aux = 0;
++
++ ctx->reply.length = ctx->returned_byte;
++ ctx->reply.data = ctx->reply_data;
++
++ process_write_reply(engine, ctx);
++ break;
++ case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY:
++ ++ctx->invalid_reply_retry_aux;
++
++ if (ctx->invalid_reply_retry_aux >
++ AUX_INVALID_REPLY_RETRY_COUNTER) {
++ ctx->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR;
++ ctx->operation_succeeded = false;
++ } else
++ dc_service_delay_in_microseconds(engine->base.ctx, 400);
++ break;
++ case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT:
++ ++ctx->timed_out_retry_aux;
++
++ if (ctx->timed_out_retry_aux > AUX_TIMED_OUT_RETRY_COUNTER) {
++ ctx->status = I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ ctx->operation_succeeded = false;
++ } else {
++ /* DP 1.2a, table 2-58:
++ * "S3: AUX Request CMD PENDING:
++ * retry 3 times, with 400usec wait on each"
++ * The HW timeout is set to 550usec,
++ * so we should not wait here */
++ }
++ break;
++ default:
++ ctx->status = I2CAUX_TRANSACTION_STATUS_UNKNOWN;
++ ctx->operation_succeeded = false;
++ }
++}
++
++static bool write_command(
++ struct aux_engine *engine,
++ struct i2caux_transaction_request *request,
++ bool middle_of_transaction)
++{
++ struct write_command_context ctx;
++
++ ctx.mot = middle_of_transaction;
++ ctx.buffer = request->payload.data;
++ ctx.current_write_length = request->payload.length;
++ ctx.timed_out_retry_aux = 0;
++ ctx.invalid_reply_retry_aux = 0;
++ ctx.defer_retry_aux = 0;
++ ctx.defer_retry_i2c = 0;
++ ctx.ack_m_retry = 0;
++ ctx.transaction_complete = false;
++ ctx.operation_succeeded = true;
++
++ if (request->payload.address_space ==
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD) {
++ ctx.request.type = AUX_TRANSACTION_TYPE_DP;
++ ctx.request.action = I2CAUX_TRANSACTION_ACTION_DP_WRITE;
++ ctx.request.address = request->payload.address;
++ } else if (request->payload.address_space ==
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C) {
++ ctx.request.type = AUX_TRANSACTION_TYPE_I2C;
++ ctx.request.action = middle_of_transaction ?
++ I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
++ I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
++ ctx.request.address = request->payload.address >> 1;
++ } else {
++ /* in DAL2, there was no return in such case */
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ ctx.request.delay = 0;
++
++ ctx.max_defer_retry =
++ (engine->max_defer_write_retry > AUX_DEFER_RETRY_COUNTER) ?
++ engine->max_defer_write_retry : AUX_DEFER_RETRY_COUNTER;
++
++ do {
++ ctx.request.data = ctx.buffer;
++ ctx.request.length = ctx.current_write_length;
++
++ process_write_request(engine, &ctx);
++
++ request->status = ctx.status;
++
++ if (ctx.operation_succeeded && !ctx.transaction_complete)
++ if (ctx.request.type == AUX_TRANSACTION_TYPE_I2C)
++ dc_service_sleep_in_milliseconds(engine->base.ctx, engine->delay);
++ } while (ctx.operation_succeeded && !ctx.transaction_complete);
++
++ return ctx.operation_succeeded;
++}
++
++static bool end_of_transaction_command(
++ struct aux_engine *engine,
++ struct i2caux_transaction_request *request)
++{
++ struct i2caux_transaction_request dummy_request;
++ uint8_t dummy_data;
++
++ /* [tcheng] We only need to send the stop (read with MOT = 0)
++ * for I2C-over-Aux, not native AUX */
++
++ if (request->payload.address_space !=
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C)
++ return false;
++
++ dummy_request.operation = request->operation;
++ dummy_request.payload.address_space = request->payload.address_space;
++ dummy_request.payload.address = request->payload.address;
++
++ /*
++ * Add a dummy byte due to some receiver quirk
++ * where one byte is sent along with MOT = 0.
++ * Ideally this should be 0.
++ */
++
++ dummy_request.payload.length = 0;
++ dummy_request.payload.data = &dummy_data;
++
++ if (request->operation == I2CAUX_TRANSACTION_READ)
++ return read_command(engine, &dummy_request, false);
++ else
++ return write_command(engine, &dummy_request, false);
++
++ /* according Syed, it does not need now DoDummyMOT */
++}
++
++bool dal_aux_engine_submit_request(
++ struct engine *engine,
++ struct i2caux_transaction_request *request,
++ bool middle_of_transaction)
++{
++ struct aux_engine *aux_engine = FROM_ENGINE(engine);
++
++ bool result;
++ bool mot_used = true;
++
++ switch (request->operation) {
++ case I2CAUX_TRANSACTION_READ:
++ result = read_command(aux_engine, request, mot_used);
++ break;
++ case I2CAUX_TRANSACTION_WRITE:
++ result = write_command(aux_engine, request, mot_used);
++ break;
++ default:
++ result = false;
++ }
++
++ /* [tcheng]
++ * need to send stop for the last transaction to free up the AUX
++ * if the above command fails, this would be the last transaction */
++
++ if (!middle_of_transaction || !result)
++ end_of_transaction_command(aux_engine, request);
++
++ /* mask AUX interrupt */
++
++ return result;
++}
++
++bool dal_aux_engine_construct(
++ struct aux_engine *engine,
++ struct dc_context *ctx)
++{
++ if (!dal_i2caux_construct_engine(&engine->base, ctx))
++ return false;
++ engine->delay = 0;
++ engine->max_defer_write_retry = 0;
++ return true;
++}
++
++void dal_aux_engine_destruct(
++ struct aux_engine *engine)
++{
++ dal_i2caux_destruct_engine(&engine->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.h b/drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.h
+new file mode 100644
+index 0000000..474f5e9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/aux_engine.h
+@@ -0,0 +1,119 @@
++/*
++ * 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_AUX_ENGINE_H__
++#define __DAL_AUX_ENGINE_H__
++
++enum aux_transaction_type {
++ AUX_TRANSACTION_TYPE_DP,
++ AUX_TRANSACTION_TYPE_I2C
++};
++
++struct aux_request_transaction_data {
++ enum aux_transaction_type type;
++ enum i2caux_transaction_action action;
++ /* 20-bit AUX channel transaction address */
++ uint32_t address;
++ /* delay, in 100-microsecond units */
++ uint8_t delay;
++ uint8_t length;
++ uint8_t *data;
++};
++
++enum aux_transaction_reply {
++ AUX_TRANSACTION_REPLY_AUX_ACK = 0x00,
++ AUX_TRANSACTION_REPLY_AUX_NACK = 0x01,
++ AUX_TRANSACTION_REPLY_AUX_DEFER = 0x02,
++
++ AUX_TRANSACTION_REPLY_I2C_ACK = 0x00,
++ AUX_TRANSACTION_REPLY_I2C_NACK = 0x10,
++ AUX_TRANSACTION_REPLY_I2C_DEFER = 0x20,
++
++ AUX_TRANSACTION_REPLY_INVALID = 0xFF
++};
++
++struct aux_reply_transaction_data {
++ enum aux_transaction_reply status;
++ uint8_t length;
++ uint8_t *data;
++};
++
++enum aux_channel_operation_result {
++ AUX_CHANNEL_OPERATION_SUCCEEDED,
++ AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN,
++ AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY,
++ AUX_CHANNEL_OPERATION_FAILED_TIMEOUT
++};
++
++struct aux_engine;
++
++struct aux_engine_funcs {
++ void (*destroy)(
++ struct aux_engine **ptr);
++ bool (*acquire_engine)(
++ struct aux_engine *engine);
++ void (*configure)(
++ struct aux_engine *engine,
++ union aux_config cfg);
++ bool (*start_gtc_sync)(
++ struct aux_engine *engine);
++ void (*stop_gtc_sync)(
++ struct aux_engine *engine);
++ void (*submit_channel_request)(
++ struct aux_engine *engine,
++ struct aux_request_transaction_data *request);
++ void (*process_channel_reply)(
++ struct aux_engine *engine,
++ struct aux_reply_transaction_data *reply);
++ enum aux_channel_operation_result (*get_channel_status)(
++ struct aux_engine *engine,
++ uint8_t *returned_bytes);
++};
++
++struct aux_engine {
++ struct engine base;
++ const struct aux_engine_funcs *funcs;
++ /* following values are expressed in milliseconds */
++ uint32_t delay;
++ uint32_t max_defer_write_retry;
++};
++
++bool dal_aux_engine_construct(
++ struct aux_engine *engine,
++ struct dc_context *ctx);
++
++void dal_aux_engine_destruct(
++ struct aux_engine *engine);
++bool dal_aux_engine_submit_request(
++ struct engine *ptr,
++ struct i2caux_transaction_request *request,
++ bool middle_of_transaction);
++bool dal_aux_engine_acquire(
++ struct engine *ptr,
++ struct ddc *ddc);
++enum i2caux_engine_type dal_aux_engine_get_engine_type(
++ const struct engine *engine);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/aux_engine_dce110.c b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/aux_engine_dce110.c
+new file mode 100644
+index 0000000..1b40a78
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/aux_engine_dce110.c
+@@ -0,0 +1,789 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "../engine.h"
++#include "../aux_engine.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "aux_engine_dce110.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++/*
++ * This unit
++ */
++
++/*
++ * @brief
++ * Cast 'struct aux_engine *'
++ * to 'struct aux_engine_dce110 *'
++ */
++#define FROM_AUX_ENGINE(ptr) \
++ container_of((ptr), struct aux_engine_dce110, base)
++
++/*
++ * @brief
++ * Cast 'struct engine *'
++ * to 'struct aux_engine_dce110 *'
++ */
++#define FROM_ENGINE(ptr) \
++ FROM_AUX_ENGINE(container_of((ptr), struct aux_engine, base))
++
++static void release_engine(
++ struct engine *engine)
++{
++ struct aux_engine_dce110 *aux_engine = FROM_ENGINE(engine);
++
++ const uint32_t addr = aux_engine->addr.aux_arb_control;
++
++ uint32_t value = dal_read_reg(engine->ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_ARB_CONTROL,
++ AUX_SW_DONE_USING_AUX_REG);
++
++ dal_write_reg(engine->ctx, addr, value);
++}
++
++static void destruct(
++ struct aux_engine_dce110 *engine);
++
++static void destroy(
++ struct aux_engine **aux_engine)
++{
++ struct aux_engine_dce110 *engine = FROM_AUX_ENGINE(*aux_engine);
++
++ destruct(engine);
++
++ dc_service_free((*aux_engine)->base.ctx, engine);
++
++ *aux_engine = NULL;
++}
++
++#define SW_CAN_ACCESS_AUX 1
++
++static bool acquire_engine(
++ struct aux_engine *engine)
++{
++ struct aux_engine_dce110 *aux_engine = FROM_AUX_ENGINE(engine);
++ uint32_t value;
++ uint32_t field;
++
++ /* enable AUX before request SW to access AUX */
++ {
++ const uint32_t addr = aux_engine->addr.aux_control;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ field = get_reg_field_value(
++ value,
++ AUX_CONTROL,
++ AUX_EN);
++
++ if (field == 0) {
++ uint8_t counter = 0;
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_CONTROL,
++ AUX_EN);
++
++ /*DP_AUX block as part of the enable sequence*/
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_CONTROL,
++ AUX_RESET);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ /*poll HW to make sure reset it done*/
++ do {
++ dc_service_delay_in_microseconds(engine->base.ctx, 1);
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ field = get_reg_field_value(
++ value,
++ AUX_CONTROL,
++ AUX_RESET_DONE);
++
++ counter++;
++
++ } while ((field == 0) && (counter < 11));
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUX_CONTROL,
++ AUX_RESET);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ counter = 0;
++
++ do {
++ dc_service_delay_in_microseconds(engine->base.ctx, 1);
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ field = get_reg_field_value(
++ value,
++ AUX_CONTROL,
++ AUX_RESET_DONE);
++
++ counter++;
++
++ } while ((field == 1) && (counter < 11));
++ } /*if (field)*/
++ }
++
++ /* request SW to access AUX */
++ {
++ const uint32_t addr = aux_engine->addr.aux_arb_control;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_ARB_CONTROL,
++ AUX_SW_USE_AUX_REG_REQ);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ field = get_reg_field_value(
++ value,
++ AUX_ARB_CONTROL,
++ AUX_REG_RW_CNTL_STATUS);
++
++ return field == SW_CAN_ACCESS_AUX;
++ }
++}
++
++static void configure(
++ struct aux_engine *engine,
++ union aux_config cfg)
++{
++ struct aux_engine_dce110 *aux_engine = FROM_AUX_ENGINE(engine);
++
++ const uint32_t addr = aux_engine->addr.aux_control;
++
++ uint32_t value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ (0 != cfg.bits.ALLOW_AUX_WHEN_HPD_LOW),
++ AUX_CONTROL,
++ AUX_IGNORE_HPD_DISCON);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++}
++
++static bool start_gtc_sync(
++ struct aux_engine *engine)
++{
++ /*TODO*/
++ return false;
++}
++
++static void stop_gtc_sync(
++ struct aux_engine *engine)
++{
++ /*TODO*/
++}
++
++#define COMPOSE_AUX_SW_DATA_16_20(command, address) \
++ ((command) | ((0xF0000 & (address)) >> 16))
++
++#define COMPOSE_AUX_SW_DATA_8_15(address) \
++ ((0xFF00 & (address)) >> 8)
++
++#define COMPOSE_AUX_SW_DATA_0_7(address) \
++ (0xFF & (address))
++
++static void submit_channel_request(
++ struct aux_engine *engine,
++ struct aux_request_transaction_data *request)
++{
++ struct aux_engine_dce110 *aux_engine = FROM_AUX_ENGINE(engine);
++ uint32_t value;
++ uint32_t length;
++
++ bool is_write =
++ ((request->type == AUX_TRANSACTION_TYPE_DP) &&
++ (request->action == I2CAUX_TRANSACTION_ACTION_DP_WRITE)) ||
++ ((request->type == AUX_TRANSACTION_TYPE_I2C) &&
++ ((request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
++ (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT)));
++
++ /* clear_aux_error */
++ {
++ const uint32_t addr = mmAUXN_IMPCAL;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUXN_IMPCAL,
++ AUXN_CALOUT_ERROR_AK);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUXN_IMPCAL,
++ AUXN_CALOUT_ERROR_AK);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++ }
++ {
++ const uint32_t addr = mmAUXP_IMPCAL;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUXP_IMPCAL,
++ AUXP_CALOUT_ERROR_AK);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUXP_IMPCAL,
++ AUXP_CALOUT_ERROR_AK);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++ }
++
++ /* force_default_calibrate */
++ {
++ const uint32_t addr = mmAUXN_IMPCAL;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUXN_IMPCAL,
++ AUXN_IMPCAL_ENABLE);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUXN_IMPCAL,
++ AUXN_IMPCAL_OVERRIDE_ENABLE);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++ }
++ {
++ const uint32_t addr = mmAUXP_IMPCAL;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUXP_IMPCAL,
++ AUXP_IMPCAL_OVERRIDE_ENABLE);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUXP_IMPCAL,
++ AUXP_IMPCAL_OVERRIDE_ENABLE);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++ }
++
++ /* set the delay and the number of bytes to write */
++ {
++ const uint32_t addr = aux_engine->addr.aux_sw_control;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ request->delay,
++ AUX_SW_CONTROL,
++ AUX_SW_START_DELAY);
++
++ /* The length include
++ * the 4 bit header and the 20 bit address
++ * (that is 3 byte).
++ * If the requested length is non zero this means
++ * an addition byte specifying the length is required. */
++
++ length = request->length ? 4 : 3;
++ if (is_write)
++ length += request->length;
++
++ set_reg_field_value(
++ value,
++ length,
++ AUX_SW_CONTROL,
++ AUX_SW_WR_BYTES);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++ }
++
++ /* program action and address and payload data (if 'is_write') */
++ {
++ const uint32_t addr = aux_engine->addr.aux_sw_data;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUX_SW_DATA,
++ AUX_SW_INDEX);
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUX_SW_DATA,
++ AUX_SW_DATA_RW);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_SW_DATA,
++ AUX_SW_AUTOINCREMENT_DISABLE);
++
++ set_reg_field_value(
++ value,
++ COMPOSE_AUX_SW_DATA_16_20(
++ request->action, request->address),
++ AUX_SW_DATA,
++ AUX_SW_DATA);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUX_SW_DATA,
++ AUX_SW_AUTOINCREMENT_DISABLE);
++
++ set_reg_field_value(
++ value,
++ COMPOSE_AUX_SW_DATA_8_15(request->address),
++ AUX_SW_DATA,
++ AUX_SW_DATA);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ set_reg_field_value(
++ value,
++ COMPOSE_AUX_SW_DATA_0_7(request->address),
++ AUX_SW_DATA,
++ AUX_SW_DATA);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ if (request->length) {
++ set_reg_field_value(
++ value,
++ request->length - 1,
++ AUX_SW_DATA,
++ AUX_SW_DATA);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++ }
++
++ if (is_write) {
++ /* Load the HW buffer with the Data to be sent.
++ * This is relevant for write operation.
++ * For read, the data recived data will be
++ * processed in process_channel_reply(). */
++ uint32_t i = 0;
++
++ while (i < request->length) {
++
++ set_reg_field_value(
++ value,
++ request->data[i],
++ AUX_SW_DATA,
++ AUX_SW_DATA);
++
++ dal_write_reg(
++ engine->base.ctx, addr, value);
++
++ ++i;
++ }
++ }
++ }
++
++ {
++ const uint32_t addr = aux_engine->addr.aux_interrupt_control;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_INTERRUPT_CONTROL,
++ AUX_SW_DONE_ACK);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++ }
++
++ {
++ const uint32_t addr = aux_engine->addr.aux_sw_control;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_SW_CONTROL,
++ AUX_SW_GO);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++ }
++}
++
++static void process_channel_reply(
++ struct aux_engine *engine,
++ struct aux_reply_transaction_data *reply)
++{
++ struct aux_engine_dce110 *aux_engine = FROM_AUX_ENGINE(engine);
++
++ /* Need to do a read to get the number of bytes to process
++ * Alternatively, this information can be passed -
++ * but that causes coupling which isn't good either. */
++
++ uint32_t bytes_replied;
++ uint32_t value;
++
++ {
++ const uint32_t addr = aux_engine->addr.aux_sw_status;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ bytes_replied = get_reg_field_value(
++ value,
++ AUX_SW_STATUS,
++ AUX_SW_REPLY_BYTE_COUNT);
++ }
++
++ if (bytes_replied) {
++ uint32_t reply_result;
++
++ const uint32_t addr = aux_engine->addr.aux_sw_data;
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ AUX_SW_DATA,
++ AUX_SW_INDEX);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_SW_DATA,
++ AUX_SW_AUTOINCREMENT_DISABLE);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ set_reg_field_value(
++ value,
++ 1,
++ AUX_SW_DATA,
++ AUX_SW_DATA_RW);
++
++ dal_write_reg(engine->base.ctx, addr, value);
++
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ reply_result = get_reg_field_value(
++ value,
++ AUX_SW_DATA,
++ AUX_SW_DATA);
++
++ reply_result = reply_result >> 4;
++
++ switch (reply_result) {
++ case 0: /* ACK */ {
++ uint32_t i = 0;
++
++ /* first byte was already used
++ * to get the command status */
++ --bytes_replied;
++
++ while (i < bytes_replied) {
++ value = dal_read_reg(
++ engine->base.ctx, addr);
++
++ reply->data[i] = get_reg_field_value(
++ value,
++ AUX_SW_DATA,
++ AUX_SW_DATA);
++
++ ++i;
++ }
++
++ reply->status = AUX_TRANSACTION_REPLY_AUX_ACK;
++ }
++ break;
++ case 1: /* NACK */
++ reply->status = AUX_TRANSACTION_REPLY_AUX_NACK;
++ break;
++ case 2: /* DEFER */
++ reply->status = AUX_TRANSACTION_REPLY_AUX_DEFER;
++ break;
++ case 4: /* AUX ACK / I2C NACK */
++ reply->status = AUX_TRANSACTION_REPLY_I2C_NACK;
++ break;
++ case 8: /* AUX ACK / I2C DEFER */
++ reply->status = AUX_TRANSACTION_REPLY_I2C_DEFER;
++ break;
++ default:
++ reply->status = AUX_TRANSACTION_REPLY_INVALID;
++ }
++ } else {
++ /* Need to handle an error case...
++ * hopefully, upper layer function won't call this function
++ * if the number of bytes in the reply was 0
++ * because there was surely an error that was asserted
++ * that should have been handled
++ * for hot plug case, this could happens*/
++ if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
++ ASSERT_CRITICAL(false);
++ }
++}
++
++static enum aux_channel_operation_result get_channel_status(
++ struct aux_engine *engine,
++ uint8_t *returned_bytes)
++{
++ struct aux_engine_dce110 *aux_engine = FROM_AUX_ENGINE(engine);
++
++ const uint32_t addr = aux_engine->addr.aux_sw_status;
++
++ uint32_t value;
++ uint32_t aux_sw_done;
++
++ if (returned_bytes == NULL) {
++ /*caller pass NULL pointer*/
++ ASSERT_CRITICAL(false);
++ return AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN;
++ }
++ *returned_bytes = 0;
++
++ /* poll to make sure that SW_DONE is asserted */
++ {
++ uint32_t time_elapsed = 0;
++
++ do {
++ value = dal_read_reg(engine->base.ctx, addr);
++
++ aux_sw_done = get_reg_field_value(
++ value,
++ AUX_SW_STATUS,
++ AUX_SW_DONE);
++
++ if (aux_sw_done)
++ break;
++
++ dc_service_delay_in_microseconds(engine->base.ctx, 10);
++
++ time_elapsed += 10;
++ } while (time_elapsed < aux_engine->timeout_period);
++
++
++ }
++
++ /* Note that the following bits are set in 'status.bits'
++ * during CTS 4.2.1.2:
++ * AUX_SW_RX_MIN_COUNT_VIOL, AUX_SW_RX_INVALID_STOP,
++ * AUX_SW_RX_RECV_NO_DET, AUX_SW_RX_RECV_INVALID_H.
++ *
++ * AUX_SW_RX_MIN_COUNT_VIOL is an internal,
++ * HW debugging bit and should be ignored. */
++ if (aux_sw_done) {
++ if (get_reg_field_value(
++ value,
++ AUX_SW_STATUS,
++ AUX_SW_RX_TIMEOUT_STATE) ||
++ get_reg_field_value(
++ value,
++ AUX_SW_STATUS,
++ AUX_SW_RX_TIMEOUT))
++ return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
++ else if (get_reg_field_value(
++ value,
++ AUX_SW_STATUS,
++ AUX_SW_RX_INVALID_STOP))
++ return AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
++
++ *returned_bytes = get_reg_field_value(
++ value,
++ AUX_SW_STATUS,
++ AUX_SW_REPLY_BYTE_COUNT);
++ if (*returned_bytes == 0)
++ return
++ AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY;
++ else {
++ *returned_bytes -= 1;
++ return AUX_CHANNEL_OPERATION_SUCCEEDED;
++ }
++ } else {
++ /*time_elapsed >= aux_engine->timeout_period */
++ if (!(value & AUX_SW_STATUS__AUX_SW_HPD_DISCON_MASK))
++ ASSERT_CRITICAL(false);
++ return AUX_CHANNEL_OPERATION_FAILED_TIMEOUT;
++ }
++}
++
++static const int32_t aux_channel_offset[] = {
++ mmDP_AUX0_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL,
++ mmDP_AUX1_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL,
++ mmDP_AUX2_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL,
++ mmDP_AUX3_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL,
++ mmDP_AUX4_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL,
++ mmDP_AUX5_AUX_CONTROL - mmDP_AUX0_AUX_CONTROL
++};
++
++static const struct aux_engine_funcs aux_engine_funcs = {
++ .destroy = destroy,
++ .acquire_engine = acquire_engine,
++ .configure = configure,
++ .start_gtc_sync = start_gtc_sync,
++ .stop_gtc_sync = stop_gtc_sync,
++ .submit_channel_request = submit_channel_request,
++ .process_channel_reply = process_channel_reply,
++ .get_channel_status = get_channel_status,
++};
++
++static const struct engine_funcs engine_funcs = {
++ .release_engine = release_engine,
++ .submit_request = dal_aux_engine_submit_request,
++ .keep_power_up_count = dal_i2caux_keep_power_up_count,
++ .get_engine_type = dal_aux_engine_get_engine_type,
++ .acquire = dal_aux_engine_acquire,
++};
++
++static bool construct(
++ struct aux_engine_dce110 *engine,
++ const struct aux_engine_dce110_init_data *aux_init_data)
++{
++ int32_t offset;
++
++ if (aux_init_data->engine_id >=
++ sizeof(aux_channel_offset) / sizeof(int32_t)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ if (!dal_aux_engine_construct(
++ &engine->base, aux_init_data->ctx)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++ engine->base.base.funcs = &engine_funcs;
++ engine->base.funcs = &aux_engine_funcs;
++ offset = aux_channel_offset[aux_init_data->engine_id];
++ engine->addr.aux_control = mmAUX_CONTROL + offset;
++ engine->addr.aux_arb_control = mmAUX_ARB_CONTROL + offset;
++ engine->addr.aux_sw_data = mmAUX_SW_DATA + offset;
++ engine->addr.aux_sw_control = mmAUX_SW_CONTROL + offset;
++ engine->addr.aux_interrupt_control = mmAUX_INTERRUPT_CONTROL + offset;
++ engine->addr.aux_sw_status = mmAUX_SW_STATUS + offset;
++ engine->addr.aux_gtc_sync_control = mmAUX_GTC_SYNC_CONTROL + offset;
++ engine->addr.aux_gtc_sync_status = mmAUX_GTC_SYNC_STATUS + offset;
++ engine->addr.aux_gtc_sync_controller_status =
++ mmAUX_GTC_SYNC_CONTROLLER_STATUS + offset;
++
++ engine->timeout_period = aux_init_data->timeout_period;
++
++ return true;
++}
++
++static void destruct(
++ struct aux_engine_dce110 *engine)
++{
++ dal_aux_engine_destruct(&engine->base);
++}
++
++struct aux_engine *dal_aux_engine_dce110_create(
++ const struct aux_engine_dce110_init_data *aux_init_data)
++{
++ struct aux_engine_dce110 *engine;
++
++ if (!aux_init_data) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ engine = dc_service_alloc(aux_init_data->ctx, sizeof(*engine));
++
++ if (!engine) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (construct(engine, aux_init_data))
++ return &engine->base;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(aux_init_data->ctx, engine);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/aux_engine_dce110.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/aux_engine_dce110.h
+new file mode 100644
+index 0000000..ec6899e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/aux_engine_dce110.h
+@@ -0,0 +1,56 @@
++/*
++ * 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_AUX_ENGINE_DCE110_H__
++#define __DAL_AUX_ENGINE_DCE110_H__
++
++#include "../aux_engine.h"
++
++struct aux_engine_dce110 {
++ struct aux_engine base;
++ struct {
++ uint32_t aux_control;
++ uint32_t aux_arb_control;
++ uint32_t aux_sw_data;
++ uint32_t aux_sw_control;
++ uint32_t aux_interrupt_control;
++ uint32_t aux_sw_status;
++ uint32_t aux_gtc_sync_control;
++ uint32_t aux_gtc_sync_status;
++ uint32_t aux_gtc_sync_controller_status;
++ } addr;
++ uint32_t timeout_period;
++};
++
++struct aux_engine_dce110_init_data {
++ uint32_t engine_id;
++ uint32_t timeout_period;
++ struct dc_context *ctx;
++};
++
++struct aux_engine *dal_aux_engine_dce110_create(
++ const struct aux_engine_dce110_init_data *aux_init_data);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_generic_hw_engine_dce110.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_generic_hw_engine_dce110.h
+new file mode 100644
+index 0000000..e6b6a97
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_generic_hw_engine_dce110.h
+@@ -0,0 +1,25 @@
++/*
++ * 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
++ *
++ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_hw_engine_dce110.c b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_hw_engine_dce110.c
+new file mode 100644
+index 0000000..17e89ce
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_hw_engine_dce110.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 "dal_services.h"
++#include "include/logger_interface.h"
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "../engine.h"
++#include "../i2c_engine.h"
++#include "../i2c_hw_engine.h"
++#include "../i2c_generic_hw_engine.h"
++/*
++ * Header of this unit
++ */
++
++#include "i2c_hw_engine_dce110.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++
++/*
++ * This unit
++ */
++
++enum dc_i2c_status {
++ DC_I2C_STATUS__DC_I2C_STATUS_IDLE,
++ DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW,
++ DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_HW
++};
++
++enum dc_i2c_arbitration {
++ DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL,
++ DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_HIGH
++};
++
++enum {
++ /* No timeout in HW
++ * (timeout implemented in SW by querying status) */
++ I2C_SETUP_TIME_LIMIT = 255,
++ I2C_HW_BUFFER_SIZE = 144
++};
++
++/*
++ * @brief
++ * Cast pointer to 'struct i2c_hw_engine *'
++ * to pointer 'struct i2c_hw_engine_dce110 *'
++ */
++#define FROM_I2C_HW_ENGINE(ptr) \
++ container_of((ptr), struct i2c_hw_engine_dce110, base)
++/*
++ * @brief
++ * Cast pointer to 'struct i2c_engine *'
++ * to pointer to 'struct i2c_hw_engine_dce110 *'
++ */
++#define FROM_I2C_ENGINE(ptr) \
++ FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base))
++
++/*
++ * @brief
++ * Cast pointer to 'struct engine *'
++ * to 'pointer to struct i2c_hw_engine_dce110 *'
++ */
++#define FROM_ENGINE(ptr) \
++ FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
++
++
++static void disable_i2c_hw_engine(
++ struct i2c_hw_engine_dce110 *engine)
++{
++ const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP;
++ uint32_t value = 0;
++
++ struct dc_context *ctx = NULL;
++
++ ctx = engine->base.base.base.ctx;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_ENABLE);
++
++ dal_write_reg(ctx, addr, value);
++}
++
++static void release_engine(
++ struct engine *engine)
++{
++ struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine);
++
++ struct i2c_engine *base = NULL;
++ bool safe_to_reset;
++ uint32_t value = 0;
++
++ base = &hw_engine->base.base;
++
++ /* Restore original HW engine speed */
++
++ base->funcs->set_speed(base, hw_engine->base.original_speed);
++
++ /* Release I2C */
++ {
++ value = dal_read_reg(engine->ctx, mmDC_I2C_ARBITRATION);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_ARBITRATION,
++ DC_I2C_SW_DONE_USING_I2C_REG);
++
++ dal_write_reg(engine->ctx, mmDC_I2C_ARBITRATION, value);
++ }
++
++ /* Reset HW engine */
++ {
++ uint32_t i2c_sw_status = 0;
++
++ value = dal_read_reg(engine->ctx, mmDC_I2C_SW_STATUS);
++
++ i2c_sw_status = get_reg_field_value(
++ value,
++ DC_I2C_SW_STATUS,
++ DC_I2C_SW_STATUS);
++ /* if used by SW, safe to reset */
++ safe_to_reset = (i2c_sw_status == 1);
++ }
++ {
++ value = dal_read_reg(engine->ctx, mmDC_I2C_CONTROL);
++
++ if (safe_to_reset)
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_CONTROL,
++ DC_I2C_SOFT_RESET);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_CONTROL,
++ DC_I2C_SW_STATUS_RESET);
++
++ dal_write_reg(engine->ctx, mmDC_I2C_CONTROL, value);
++ }
++
++ /* HW I2c engine - clock gating feature */
++ if (!hw_engine->engine_keep_power_up_count)
++ disable_i2c_hw_engine(hw_engine);
++}
++
++static void keep_power_up_count(
++ struct engine *engine,
++ bool keep_power_up)
++{
++ struct i2c_hw_engine_dce110 *hw_engine = FROM_ENGINE(engine);
++
++ if (keep_power_up)
++ ++hw_engine->engine_keep_power_up_count;
++ else {
++ --hw_engine->engine_keep_power_up_count;
++
++ if (!hw_engine->engine_keep_power_up_count)
++ disable_i2c_hw_engine(hw_engine);
++ }
++}
++
++static bool setup_engine(
++ struct i2c_engine *i2c_engine)
++{
++ uint32_t value = 0;
++ struct i2c_hw_engine_dce110 *engine = FROM_I2C_ENGINE(i2c_engine);
++
++ /* Program pin select */
++ {
++ const uint32_t addr = mmDC_I2C_CONTROL;
++
++ value = dal_read_reg(i2c_engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_GO);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_SOFT_RESET);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_SEND_RESET);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_SW_STATUS_RESET);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_TRANSACTION_COUNT);
++
++ set_reg_field_value(
++ value,
++ engine->engine_id,
++ DC_I2C_CONTROL,
++ DC_I2C_DDC_SELECT);
++
++
++ dal_write_reg(i2c_engine->base.ctx, addr, value);
++ }
++
++ /* Program time limit */
++ {
++ const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP;
++
++ value = dal_read_reg(i2c_engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ I2C_SETUP_TIME_LIMIT,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_TIME_LIMIT);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_ENABLE);
++
++ dal_write_reg(i2c_engine->base.ctx, addr, value);
++ }
++
++ /* Program HW priority
++ * set to High - interrupt software I2C at any time
++ * Enable restart of SW I2C that was interrupted by HW
++ * disable queuing of software while I2C is in use by HW */
++ {
++ value = dal_read_reg(i2c_engine->base.ctx,
++ mmDC_I2C_ARBITRATION);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_ARBITRATION,
++ DC_I2C_NO_QUEUED_SW_GO);
++
++ set_reg_field_value(
++ value,
++ DC_I2C_ARBITRATION__DC_I2C_SW_PRIORITY_NORMAL,
++ DC_I2C_ARBITRATION,
++ DC_I2C_SW_PRIORITY);
++
++ dal_write_reg(i2c_engine->base.ctx,
++ mmDC_I2C_ARBITRATION, value);
++ }
++
++ return true;
++}
++
++static uint32_t get_speed(
++ const struct i2c_engine *i2c_engine)
++{
++ const struct i2c_hw_engine_dce110 *engine = FROM_I2C_ENGINE(i2c_engine);
++
++ const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED;
++
++ uint32_t pre_scale = 0;
++
++ uint32_t value = dal_read_reg(i2c_engine->base.ctx, addr);
++
++ pre_scale = get_reg_field_value(
++ value,
++ DC_I2C_DDC1_SPEED,
++ DC_I2C_DDC1_PRESCALE);
++
++ /* [anaumov] it seems following is unnecessary */
++ /*ASSERT(value.bits.DC_I2C_DDC1_PRESCALE);*/
++
++ return pre_scale ?
++ engine->reference_frequency / pre_scale :
++ engine->base.default_speed;
++}
++
++static void set_speed(
++ struct i2c_engine *i2c_engine,
++ uint32_t speed)
++{
++ struct i2c_hw_engine_dce110 *engine = FROM_I2C_ENGINE(i2c_engine);
++
++ if (speed) {
++ const uint32_t addr = engine->addr.DC_I2C_DDCX_SPEED;
++
++ uint32_t value = dal_read_reg(i2c_engine->base.ctx, addr);
++
++ set_reg_field_value(
++ value,
++ engine->reference_frequency / speed,
++ DC_I2C_DDC1_SPEED,
++ DC_I2C_DDC1_PRESCALE);
++
++ set_reg_field_value(
++ value,
++ 2,
++ DC_I2C_DDC1_SPEED,
++ DC_I2C_DDC1_THRESHOLD);
++
++ /*DCE11, HW add 100Khz support for I2c*/
++ if (speed > 50) {
++ set_reg_field_value(
++ value,
++ 2,
++ DC_I2C_DDC1_SPEED,
++ DC_I2C_DDC1_START_STOP_TIMING_CNTL);
++ } else {
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_DDC1_SPEED,
++ DC_I2C_DDC1_START_STOP_TIMING_CNTL);
++ }
++
++ dal_write_reg(i2c_engine->base.ctx, addr, value);
++ }
++}
++
++static inline void reset_hw_engine(struct engine *engine)
++{
++ uint32_t value = dal_read_reg(engine->ctx, mmDC_I2C_CONTROL);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_CONTROL,
++ DC_I2C_SOFT_RESET);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_CONTROL,
++ DC_I2C_SW_STATUS_RESET);
++
++ dal_write_reg(engine->ctx, mmDC_I2C_CONTROL, value);
++}
++
++static bool is_hw_busy(struct engine *engine)
++{
++ uint32_t i2c_sw_status = 0;
++
++ uint32_t value = dal_read_reg(engine->ctx, mmDC_I2C_SW_STATUS);
++
++ i2c_sw_status = get_reg_field_value(
++ value,
++ DC_I2C_SW_STATUS,
++ DC_I2C_SW_STATUS);
++
++ if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_IDLE)
++ return false;
++
++ reset_hw_engine(engine);
++
++ value = dal_read_reg(engine->ctx, mmDC_I2C_SW_STATUS);
++
++ i2c_sw_status = get_reg_field_value(
++ value,
++ DC_I2C_SW_STATUS,
++ DC_I2C_SW_STATUS);
++
++ return i2c_sw_status != DC_I2C_STATUS__DC_I2C_STATUS_IDLE;
++}
++
++/*
++ * @brief
++ * DC_GPIO_DDC MM register offsets
++ */
++static const uint32_t transaction_addr[] = {
++ mmDC_I2C_TRANSACTION0,
++ mmDC_I2C_TRANSACTION1,
++ mmDC_I2C_TRANSACTION2,
++ mmDC_I2C_TRANSACTION3
++};
++
++static bool process_transaction(
++ struct i2c_hw_engine_dce110 *engine,
++ struct i2c_request_transaction_data *request)
++{
++ uint8_t length = request->length;
++ uint8_t *buffer = request->data;
++
++ bool last_transaction = false;
++ uint32_t value = 0;
++
++ struct dc_context *ctx = NULL;
++
++ ctx = engine->base.base.base.ctx;
++
++ {
++ const uint32_t addr =
++ transaction_addr[engine->transaction_count];
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_TRANSACTION0,
++ DC_I2C_STOP_ON_NACK0);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_TRANSACTION0,
++ DC_I2C_START0);
++
++
++ if ((engine->transaction_count == 3) ||
++ (request->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
++ (request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) {
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_TRANSACTION0,
++ DC_I2C_STOP0);
++
++ last_transaction = true;
++ } else
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_TRANSACTION0,
++ DC_I2C_STOP0);
++
++ set_reg_field_value(
++ value,
++ (0 != (request->action &
++ I2CAUX_TRANSACTION_ACTION_I2C_READ)),
++ DC_I2C_TRANSACTION0,
++ DC_I2C_RW0);
++
++ set_reg_field_value(
++ value,
++ length,
++ DC_I2C_TRANSACTION0,
++ DC_I2C_COUNT0);
++
++ dal_write_reg(ctx, addr, value);
++ }
++
++ /* Write the I2C address and I2C data
++ * into the hardware circular buffer, one byte per entry.
++ * As an example, the 7-bit I2C slave address for CRT monitor
++ * for reading DDC/EDID information is 0b1010001.
++ * For an I2C send operation, the LSB must be programmed to 0;
++ * for I2C receive operation, the LSB must be programmed to 1. */
++
++ {
++ value = 0;
++
++ set_reg_field_value(
++ value,
++ false,
++ DC_I2C_DATA,
++ DC_I2C_DATA_RW);
++
++ set_reg_field_value(
++ value,
++ request->address,
++ DC_I2C_DATA,
++ DC_I2C_DATA);
++
++ if (engine->transaction_count == 0) {
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_DATA,
++ DC_I2C_INDEX);
++
++ /*enable index write*/
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_DATA,
++ DC_I2C_INDEX_WRITE);
++
++ engine->buffer_used_write = 0;
++ }
++
++ dal_write_reg(ctx, mmDC_I2C_DATA, value);
++
++ engine->buffer_used_write++;
++
++ if (!(request->action & I2CAUX_TRANSACTION_ACTION_I2C_READ)) {
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_DATA,
++ DC_I2C_INDEX_WRITE);
++
++ while (length) {
++
++ set_reg_field_value(
++ value,
++ *buffer++,
++ DC_I2C_DATA,
++ DC_I2C_DATA);
++
++ dal_write_reg(ctx, mmDC_I2C_DATA, value);
++
++ engine->buffer_used_write++;
++ --length;
++ }
++ }
++ }
++
++ ++engine->transaction_count;
++ engine->buffer_used_bytes += length + 1;
++
++ return last_transaction;
++}
++
++static void execute_transaction(
++ struct i2c_hw_engine_dce110 *engine)
++{
++ uint32_t value = 0;
++ struct dc_context *ctx = NULL;
++
++ ctx = engine->base.base.base.ctx;
++
++ {
++ const uint32_t addr = engine->addr.DC_I2C_DDCX_SETUP;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_DATA_DRIVE_EN);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_CLK_DRIVE_EN);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_DATA_DRIVE_SEL);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_INTRA_TRANSACTION_DELAY);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_DDC1_SETUP,
++ DC_I2C_DDC1_INTRA_BYTE_DELAY);
++
++ dal_write_reg(ctx, addr, value);
++ }
++
++ {
++ const uint32_t addr = mmDC_I2C_CONTROL;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_SOFT_RESET);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_SW_STATUS_RESET);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_SEND_RESET);
++
++ set_reg_field_value(
++ value,
++ 0,
++ DC_I2C_CONTROL,
++ DC_I2C_GO);
++
++ set_reg_field_value(
++ value,
++ engine->transaction_count - 1,
++ DC_I2C_CONTROL,
++ DC_I2C_TRANSACTION_COUNT);
++
++ dal_write_reg(ctx, addr, value);
++ }
++
++ /* start I2C transfer */
++ {
++ const uint32_t addr = mmDC_I2C_CONTROL;
++
++ value = dal_read_reg(ctx, addr);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_CONTROL,
++ DC_I2C_GO);
++
++ dal_write_reg(ctx, addr, value);
++ }
++
++ /* all transactions were executed and HW buffer became empty
++ * (even though it actually happens when status becomes DONE) */
++ engine->transaction_count = 0;
++ engine->buffer_used_bytes = 0;
++}
++
++static void submit_channel_request(
++ struct i2c_engine *engine,
++ struct i2c_request_transaction_data *request)
++{
++ request->status = I2C_CHANNEL_OPERATION_SUCCEEDED;
++
++ if (!process_transaction(FROM_I2C_ENGINE(engine), request))
++ return;
++
++ if (is_hw_busy(&engine->base)) {
++ request->status = I2C_CHANNEL_OPERATION_ENGINE_BUSY;
++ return;
++ }
++
++ execute_transaction(FROM_I2C_ENGINE(engine));
++}
++
++static void process_channel_reply(
++ struct i2c_engine *engine,
++ struct i2c_reply_transaction_data *reply)
++{
++ uint8_t length = reply->length;
++ uint8_t *buffer = reply->data;
++
++ struct i2c_hw_engine_dce110 *i2c_hw_engine_dce110 =
++ FROM_I2C_ENGINE(engine);
++
++ uint32_t value = 0;
++
++ /*set index*/
++ set_reg_field_value(
++ value,
++ i2c_hw_engine_dce110->buffer_used_write,
++ DC_I2C_DATA,
++ DC_I2C_INDEX);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_DATA,
++ DC_I2C_DATA_RW);
++
++ set_reg_field_value(
++ value,
++ 1,
++ DC_I2C_DATA,
++ DC_I2C_INDEX_WRITE);
++
++ dal_write_reg(engine->base.ctx, mmDC_I2C_DATA, value);
++
++ while (length) {
++ /* after reading the status,
++ * if the I2C operation executed successfully
++ * (i.e. DC_I2C_STATUS_DONE = 1) then the I2C controller
++ * should read data bytes from I2C circular data buffer */
++
++ value = dal_read_reg(engine->base.ctx, mmDC_I2C_DATA);
++
++ *buffer++ = get_reg_field_value(
++ value,
++ DC_I2C_DATA,
++ DC_I2C_DATA);
++
++ --length;
++ }
++}
++
++static enum i2c_channel_operation_result get_channel_status(
++ struct i2c_engine *engine,
++ uint8_t *returned_bytes)
++{
++ uint32_t i2c_sw_status = 0;
++ uint32_t value = dal_read_reg(engine->base.ctx, mmDC_I2C_SW_STATUS);
++
++ i2c_sw_status = get_reg_field_value(
++ value,
++ DC_I2C_SW_STATUS,
++ DC_I2C_SW_STATUS);
++
++ if (i2c_sw_status == DC_I2C_STATUS__DC_I2C_STATUS_USED_BY_SW)
++ return I2C_CHANNEL_OPERATION_ENGINE_BUSY;
++ else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_STOPPED_ON_NACK_MASK)
++ return I2C_CHANNEL_OPERATION_NO_RESPONSE;
++ else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_TIMEOUT_MASK)
++ return I2C_CHANNEL_OPERATION_TIMEOUT;
++ else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_ABORTED_MASK)
++ return I2C_CHANNEL_OPERATION_FAILED;
++ else if (value & DC_I2C_SW_STATUS__DC_I2C_SW_DONE_MASK)
++ return I2C_CHANNEL_OPERATION_SUCCEEDED;
++
++ /* in DAL2, I2C_RESULT_OK was returned */
++ return I2C_CHANNEL_OPERATION_NOT_STARTED;
++}
++
++static uint8_t get_hw_buffer_available_size(
++ const struct i2c_hw_engine *engine)
++{
++ return I2C_HW_BUFFER_SIZE -
++ FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes;
++}
++
++static uint32_t get_transaction_timeout(
++ const struct i2c_hw_engine *engine,
++ uint32_t length)
++{
++ uint32_t speed = engine->base.funcs->get_speed(&engine->base);
++
++ uint32_t period_timeout;
++ uint32_t num_of_clock_stretches;
++
++ if (!speed)
++ return 0;
++
++ period_timeout = (1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed;
++
++ num_of_clock_stretches = 1 + (length << 3) + 1;
++ num_of_clock_stretches +=
++ (FROM_I2C_HW_ENGINE(engine)->buffer_used_bytes << 3) +
++ (FROM_I2C_HW_ENGINE(engine)->transaction_count << 1);
++
++ return period_timeout * num_of_clock_stretches;
++}
++
++static void destroy(
++ struct i2c_engine **i2c_engine)
++{
++ struct i2c_hw_engine_dce110 *engine_dce110 =
++ FROM_I2C_ENGINE(*i2c_engine);
++
++ dal_i2c_hw_engine_destruct(&engine_dce110->base);
++
++ dc_service_free((*i2c_engine)->base.ctx, engine_dce110);
++
++ *i2c_engine = NULL;
++}
++/*
++ * @brief
++ * DC_I2C_DDC1_SETUP MM register offsets
++ *
++ * @note
++ * The indices of this offset array are DDC engine IDs
++ */
++static const int32_t ddc_setup_offset[] = {
++
++ mmDC_I2C_DDC1_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 1 */
++ mmDC_I2C_DDC2_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 2 */
++ mmDC_I2C_DDC3_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 3 */
++ mmDC_I2C_DDC4_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 4 */
++ mmDC_I2C_DDC5_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 5 */
++ mmDC_I2C_DDC6_SETUP - mmDC_I2C_DDC1_SETUP, /* DDC Engine 6 */
++ mmDC_I2C_DDCVGA_SETUP - mmDC_I2C_DDC1_SETUP /* DDC Engine 7 */
++};
++
++/*
++ * @brief
++ * DC_I2C_DDC1_SPEED MM register offsets
++ *
++ * @note
++ * The indices of this offset array are DDC engine IDs
++ */
++static const int32_t ddc_speed_offset[] = {
++ mmDC_I2C_DDC1_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 1 */
++ mmDC_I2C_DDC2_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 2 */
++ mmDC_I2C_DDC3_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 3 */
++ mmDC_I2C_DDC4_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 4 */
++ mmDC_I2C_DDC5_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 5 */
++ mmDC_I2C_DDC6_SPEED - mmDC_I2C_DDC1_SPEED, /* DDC Engine 6 */
++ mmDC_I2C_DDCVGA_SPEED - mmDC_I2C_DDC1_SPEED /* DDC Engine 7 */
++};
++
++static const struct i2c_engine_funcs i2c_engine_funcs = {
++ .destroy = destroy,
++ .get_speed = get_speed,
++ .set_speed = set_speed,
++ .setup_engine = setup_engine,
++ .submit_channel_request = submit_channel_request,
++ .process_channel_reply = process_channel_reply,
++ .get_channel_status = get_channel_status,
++ .acquire_engine = dal_i2c_hw_engine_acquire_engine,
++};
++
++static const struct engine_funcs engine_funcs = {
++ .release_engine = release_engine,
++ .keep_power_up_count = keep_power_up_count,
++ .get_engine_type = dal_i2c_hw_engine_get_engine_type,
++ .acquire = dal_i2c_engine_acquire,
++ .submit_request = dal_i2c_hw_engine_submit_request,
++};
++
++static const struct i2c_hw_engine_funcs i2c_hw_engine_funcs = {
++ .get_hw_buffer_available_size = get_hw_buffer_available_size,
++ .get_transaction_timeout = get_transaction_timeout,
++ .wait_on_operation_result = dal_i2c_hw_engine_wait_on_operation_result,
++};
++
++static bool construct(
++ struct i2c_hw_engine_dce110 *engine_dce110,
++ const struct i2c_hw_engine_dce110_create_arg *arg)
++{
++ uint32_t xtal_ref_div = 0;
++ uint32_t value = 0;
++
++ /*ddc_setup_offset of dce80 and dce110 have the same register name
++ * but different offset. Do not need different array*/
++ if (arg->engine_id >= sizeof(ddc_setup_offset) / sizeof(int32_t))
++ return false;
++ if (arg->engine_id >= sizeof(ddc_speed_offset) / sizeof(int32_t))
++ return false;
++ if (!arg->reference_frequency)
++ return false;
++
++ if (!dal_i2c_hw_engine_construct(&engine_dce110->base, arg->ctx))
++ return false;
++
++ engine_dce110->base.base.base.funcs = &engine_funcs;
++ engine_dce110->base.base.funcs = &i2c_engine_funcs;
++ engine_dce110->base.funcs = &i2c_hw_engine_funcs;
++ engine_dce110->base.default_speed = arg->default_speed;
++
++ engine_dce110->engine_id = arg->engine_id;
++
++ engine_dce110->buffer_used_bytes = 0;
++ engine_dce110->transaction_count = 0;
++ engine_dce110->engine_keep_power_up_count = 1;
++
++ /*values which are not included by arg*/
++ engine_dce110->addr.DC_I2C_DDCX_SETUP =
++ mmDC_I2C_DDC1_SETUP + ddc_setup_offset[arg->engine_id];
++ engine_dce110->addr.DC_I2C_DDCX_SPEED =
++ mmDC_I2C_DDC1_SPEED + ddc_speed_offset[arg->engine_id];
++
++
++ value = dal_read_reg(
++ engine_dce110->base.base.base.ctx,
++ mmMICROSECOND_TIME_BASE_DIV);
++
++ xtal_ref_div = get_reg_field_value(
++ value,
++ MICROSECOND_TIME_BASE_DIV,
++ XTAL_REF_DIV);
++
++ if (xtal_ref_div == 0) {
++ dal_logger_write(
++ engine_dce110->base.base.base.ctx->logger,
++ LOG_MAJOR_WARNING,
++ LOG_MINOR_COMPONENT_I2C_AUX,
++ "Invalid base timer divider\n",
++ __func__);
++ xtal_ref_div = 2;
++ }
++
++ /*Calculating Reference Clock by divding original frequency by
++ * XTAL_REF_DIV.
++ * At upper level, uint32_t reference_frequency =
++ * dal_i2caux_get_reference_clock(as) >> 1
++ * which already divided by 2. So we need x2 to get original
++ * reference clock from ppll_info
++ */
++ engine_dce110->reference_frequency =
++ (arg->reference_frequency * 2) / xtal_ref_div;
++
++
++ return true;
++}
++
++struct i2c_engine *dal_i2c_hw_engine_dce110_create(
++ const struct i2c_hw_engine_dce110_create_arg *arg)
++{
++ struct i2c_hw_engine_dce110 *engine_dce10;
++
++ if (!arg) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ engine_dce10 = dc_service_alloc(arg->ctx, sizeof(struct i2c_hw_engine_dce110));
++
++ if (!engine_dce10) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (construct(engine_dce10, arg))
++ return &engine_dce10->base.base;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(arg->ctx, engine_dce10);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_hw_engine_dce110.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_hw_engine_dce110.h
+new file mode 100644
+index 0000000..fc2ae36
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_hw_engine_dce110.h
+@@ -0,0 +1,58 @@
++/*
++ * 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_I2C_HW_ENGINE_DCE110_H__
++#define __DAL_I2C_HW_ENGINE_DCE110_H__
++
++struct i2c_hw_engine_dce110 {
++ struct i2c_hw_engine base;
++ struct {
++ uint32_t DC_I2C_DDCX_SETUP;
++ uint32_t DC_I2C_DDCX_SPEED;
++ } addr;
++ uint32_t engine_id;
++ /* expressed in kilohertz */
++ uint32_t reference_frequency;
++ /* number of bytes currently used in HW buffer */
++ uint32_t buffer_used_bytes;
++ /* number of bytes used for write transaction in HW buffer
++ * - this will be used as the index to read from*/
++ uint32_t buffer_used_write;
++ /* number of pending transactions (before GO) */
++ uint32_t transaction_count;
++ uint32_t engine_keep_power_up_count;
++};
++
++struct i2c_hw_engine_dce110_create_arg {
++ uint32_t engine_id;
++ uint32_t reference_frequency;
++ uint32_t default_speed;
++ struct dc_context *ctx;
++};
++
++struct i2c_engine *dal_i2c_hw_engine_dce110_create(
++ const struct i2c_hw_engine_dce110_create_arg *arg);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_sw_engine_dce110.c b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_sw_engine_dce110.c
+new file mode 100644
+index 0000000..c415a4e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_sw_engine_dce110.c
+@@ -0,0 +1,172 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "../engine.h"
++#include "../i2c_engine.h"
++#include "../i2c_sw_engine.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "i2c_sw_engine_dce110.h"
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++/*
++ * @brief
++ * Cast 'struct i2c_sw_engine *'
++ * to 'struct i2c_sw_engine_dce110 *'
++ */
++#define FROM_I2C_SW_ENGINE(ptr) \
++ container_of((ptr), struct i2c_sw_engine_dce110, base)
++/*
++ * @brief
++ * Cast 'struct i2c_engine *'
++ * to 'struct i2c_sw_engine_dce80 *'
++ */
++#define FROM_I2C_ENGINE(ptr) \
++ FROM_I2C_SW_ENGINE(container_of((ptr), struct i2c_sw_engine, base))
++
++/*
++ * @brief
++ * Cast 'struct engine *'
++ * to 'struct i2c_sw_engine_dce80 *'
++ */
++#define FROM_ENGINE(ptr) \
++ FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
++
++static void release_engine(
++ struct engine *engine)
++{
++}
++
++static void destruct(
++ struct i2c_sw_engine_dce110 *engine)
++{
++ dal_i2c_sw_engine_destruct(&engine->base);
++}
++
++static void destroy(
++ struct i2c_engine **engine)
++{
++ struct i2c_sw_engine_dce110 *sw_engine = FROM_I2C_ENGINE(*engine);
++
++ destruct(sw_engine);
++
++ dc_service_free((*engine)->base.ctx, sw_engine);
++
++ *engine = NULL;
++}
++
++static bool acquire_engine(
++ struct i2c_engine *engine,
++ struct ddc *ddc_handle)
++{
++ return dal_i2caux_i2c_sw_engine_acquire_engine(engine, ddc_handle);
++}
++
++static const struct i2c_engine_funcs i2c_engine_funcs = {
++ .acquire_engine = acquire_engine,
++ .destroy = destroy,
++ .get_speed = dal_i2c_sw_engine_get_speed,
++ .set_speed = dal_i2c_sw_engine_set_speed,
++ .setup_engine = dal_i2c_engine_setup_i2c_engine,
++ .submit_channel_request = dal_i2c_sw_engine_submit_channel_request,
++ .process_channel_reply = dal_i2c_engine_process_channel_reply,
++ .get_channel_status = dal_i2c_sw_engine_get_channel_status,
++};
++
++static const struct engine_funcs engine_funcs = {
++ .release_engine = release_engine,
++ .get_engine_type = dal_i2c_sw_engine_get_engine_type,
++ .acquire = dal_i2c_engine_acquire,
++ .submit_request = dal_i2c_sw_engine_submit_request,
++ .keep_power_up_count = dal_i2caux_keep_power_up_count,
++};
++
++static bool construct(
++ struct i2c_sw_engine_dce110 *engine_dce110,
++ const struct i2c_sw_engine_dce110_create_arg *arg_dce110)
++{
++ struct i2c_sw_engine_create_arg arg_base;
++
++ arg_base.ctx = arg_dce110->ctx;
++ arg_base.default_speed = arg_dce110->default_speed;
++
++ if (!dal_i2c_sw_engine_construct(
++ &engine_dce110->base, &arg_base)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ /*struct engine struct engine_funcs*/
++ engine_dce110->base.base.base.funcs = &engine_funcs;
++ /*struct i2c_engine struct i2c_engine_funcs*/
++ engine_dce110->base.base.funcs = &i2c_engine_funcs;
++ engine_dce110->base.default_speed = arg_dce110->default_speed;
++ engine_dce110->engine_id = arg_dce110->engine_id;
++
++ return true;
++}
++
++struct i2c_engine *dal_i2c_sw_engine_dce110_create(
++ const struct i2c_sw_engine_dce110_create_arg *arg)
++{
++ struct i2c_sw_engine_dce110 *engine_dce110;
++
++ if (!arg) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ engine_dce110 = dc_service_alloc(arg->ctx, sizeof(struct i2c_sw_engine_dce110));
++
++ if (!engine_dce110) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (construct(engine_dce110, arg))
++ return &engine_dce110->base.base;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(arg->ctx, engine_dce110);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_sw_engine_dce110.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_sw_engine_dce110.h
+new file mode 100644
+index 0000000..c48c61f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2c_sw_engine_dce110.h
+@@ -0,0 +1,43 @@
++/*
++ * 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_I2C_SW_ENGINE_DCE110_H__
++#define __DAL_I2C_SW_ENGINE_DCE110_H__
++
++struct i2c_sw_engine_dce110 {
++ struct i2c_sw_engine base;
++ uint32_t engine_id;
++};
++
++struct i2c_sw_engine_dce110_create_arg {
++ uint32_t engine_id;
++ uint32_t default_speed;
++ struct dc_context *ctx;
++};
++
++struct i2c_engine *dal_i2c_sw_engine_dce110_create(
++ const struct i2c_sw_engine_dce110_create_arg *arg);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.c b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.c
+new file mode 100644
+index 0000000..71d1a6c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.c
+@@ -0,0 +1,260 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "../i2caux.h"
++#include "../engine.h"
++#include "../i2c_engine.h"
++#include "../i2c_sw_engine.h"
++#include "../i2c_hw_engine.h"
++
++/*
++ * Header of this unit
++ */
++#include "i2caux_dce110.h"
++#include "i2c_sw_engine_dce110.h"
++#include "i2c_hw_engine_dce110.h"
++#include "aux_engine_dce110.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++/*cast pointer to struct i2caux TO pointer to struct i2caux_dce110*/
++#define FROM_I2C_AUX(ptr) \
++ container_of((ptr), struct i2caux_dce110, base)
++
++static void destruct(
++ struct i2caux_dce110 *i2caux_dce110)
++{
++ dal_i2caux_destruct(&i2caux_dce110->base);
++}
++
++static void destroy(
++ struct i2caux **i2c_engine)
++{
++ struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(*i2c_engine);
++
++ destruct(i2caux_dce110);
++
++ dc_service_free((*i2c_engine)->ctx, i2caux_dce110);
++
++ *i2c_engine = NULL;
++}
++
++static struct i2c_engine *acquire_i2c_hw_engine(
++ struct i2caux *i2caux,
++ struct ddc *ddc)
++{
++ struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(i2caux);
++
++ struct i2c_engine *engine = NULL;
++ /* generic hw engine is not used for EDID read
++ * It may be needed for external i2c device, like thermal chip,
++ * TODO will be implemented when needed.
++ * check dce80 bool non_generic for generic hw engine;
++ */
++
++ if (!ddc)
++ return NULL;
++
++ if (dal_ddc_is_hw_supported(ddc)) {
++ enum gpio_ddc_line line = dal_ddc_get_line(ddc);
++
++ if (line < GPIO_DDC_LINE_COUNT)
++ engine = i2caux->i2c_hw_engines[line];
++ }
++
++ if (!engine)
++ return NULL;
++
++ if (!i2caux_dce110->i2c_hw_buffer_in_use &&
++ engine->base.funcs->acquire(&engine->base, ddc)) {
++ i2caux_dce110->i2c_hw_buffer_in_use = true;
++ return engine;
++ }
++
++ return NULL;
++}
++
++static void release_engine(
++ struct i2caux *i2caux,
++ struct engine *engine)
++{
++ struct i2caux_dce110 *i2caux_dce110 = FROM_I2C_AUX(i2caux);
++
++ if (engine->funcs->get_engine_type(engine) ==
++ I2CAUX_ENGINE_TYPE_I2C_DDC_HW)
++ i2caux_dce110->i2c_hw_buffer_in_use = false;
++
++ dal_i2caux_release_engine(i2caux, engine);
++}
++
++static const enum gpio_ddc_line hw_ddc_lines[] = {
++ GPIO_DDC_LINE_DDC1,
++ GPIO_DDC_LINE_DDC2,
++ GPIO_DDC_LINE_DDC3,
++};
++
++static const enum gpio_ddc_line hw_aux_lines[] = {
++ GPIO_DDC_LINE_DDC1,
++ GPIO_DDC_LINE_DDC2,
++ GPIO_DDC_LINE_DDC3,
++};
++
++/* function table */
++static const struct i2caux_funcs i2caux_funcs = {
++ .destroy = destroy,
++ .acquire_i2c_hw_engine = acquire_i2c_hw_engine,
++ .release_engine = release_engine,
++ .acquire_i2c_sw_engine = dal_i2caux_acquire_i2c_sw_engine,
++ .acquire_aux_engine = dal_i2caux_acquire_aux_engine,
++};
++
++static bool construct(
++ struct i2caux_dce110 *i2caux_dce110,
++ struct adapter_service *as,
++ struct dc_context *ctx)
++{
++ uint32_t i = 0;
++ uint32_t reference_frequency = 0;
++ bool use_i2c_sw_engine = false;
++ struct i2caux *base = NULL;
++ /*TODO: For CZ bring up, if dal_i2caux_get_reference_clock
++ * does not return 48KHz, we need hard coded for 48Khz.
++ * Some BIOS setting incorrect cause this
++ * For production, we always get value from BIOS*/
++ reference_frequency =
++ dal_i2caux_get_reference_clock(as) >> 1;
++
++ use_i2c_sw_engine = dal_adapter_service_is_feature_supported(
++ FEATURE_RESTORE_USAGE_I2C_SW_ENGINE);
++
++ base = &i2caux_dce110->base;
++
++ if (!dal_i2caux_construct(base, as, ctx)) {
++ ASSERT_CRITICAL(false);
++ return false;
++ }
++
++ i2caux_dce110->base.funcs = &i2caux_funcs;
++ i2caux_dce110->i2c_hw_buffer_in_use = false;
++ /* Create I2C engines (DDC lines per connector)
++ * different I2C/AUX usage cases, DDC, Generic GPIO, AUX.
++ */
++ do {
++ enum gpio_ddc_line line_id = hw_ddc_lines[i];
++
++ struct i2c_hw_engine_dce110_create_arg hw_arg_dce110;
++
++ if (use_i2c_sw_engine) {
++ struct i2c_sw_engine_dce110_create_arg sw_arg;
++
++ sw_arg.engine_id = i;
++ sw_arg.default_speed = base->default_i2c_sw_speed;
++ sw_arg.ctx = ctx;
++ base->i2c_sw_engines[line_id] =
++ dal_i2c_sw_engine_dce110_create(&sw_arg);
++ }
++
++ hw_arg_dce110.engine_id = i;
++ hw_arg_dce110.reference_frequency = reference_frequency;
++ hw_arg_dce110.default_speed = base->default_i2c_hw_speed;
++ hw_arg_dce110.ctx = ctx;
++
++ base->i2c_hw_engines[line_id] =
++ dal_i2c_hw_engine_dce110_create(&hw_arg_dce110);
++
++ ++i;
++ } while (i < ARRAY_SIZE(hw_ddc_lines));
++
++ /* Create AUX engines for all lines which has assisted HW AUX
++ * 'i' (loop counter) used as DDC/AUX engine_id */
++
++ i = 0;
++
++ do {
++ enum gpio_ddc_line line_id = hw_aux_lines[i];
++
++ struct aux_engine_dce110_init_data aux_init_data;
++
++ aux_init_data.engine_id = i;
++ aux_init_data.timeout_period = base->aux_timeout_period;
++ aux_init_data.ctx = ctx;
++
++ base->aux_engines[line_id] =
++ dal_aux_engine_dce110_create(&aux_init_data);
++
++ ++i;
++ } while (i < ARRAY_SIZE(hw_aux_lines));
++
++ /*TODO Generic I2C SW and HW*/
++
++ return true;
++}
++
++/*
++ * dal_i2caux_dce110_create
++ *
++ * @brief
++ * public interface to allocate memory for DCE11 I2CAUX
++ *
++ * @param
++ * struct adapter_service *as - [in]
++ * struct dc_context *ctx - [in]
++ *
++ * @return
++ * pointer to the base struct of DCE11 I2CAUX
++ */
++struct i2caux *dal_i2caux_dce110_create(
++ struct adapter_service *as,
++ struct dc_context *ctx)
++{
++ struct i2caux_dce110 *i2caux_dce110 =
++ dc_service_alloc(ctx, sizeof(struct i2caux_dce110));
++
++ if (!i2caux_dce110) {
++ ASSERT_CRITICAL(false);
++ return NULL;
++ }
++
++ if (construct(i2caux_dce110, as, ctx))
++ return &i2caux_dce110->base;
++
++ ASSERT_CRITICAL(false);
++
++ dc_service_free(ctx, i2caux_dce110);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.h b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.h
+new file mode 100644
+index 0000000..1a7ba1b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/dce110/i2caux_dce110.h
+@@ -0,0 +1,39 @@
++/*
++ * 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_I2C_AUX_DCE110_H__
++#define __DAL_I2C_AUX_DCE110_H__
++
++struct i2caux_dce110 {
++ struct i2caux base;
++ /* indicate the I2C HW circular buffer is in use */
++ bool i2c_hw_buffer_in_use;
++};
++
++struct i2caux *dal_i2caux_dce110_create(
++ struct adapter_service *as,
++ struct dc_context *ctx);
++
++#endif /* __DAL_I2C_AUX_DCE110_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/engine.h b/drivers/gpu/drm/amd/dal/dc/i2caux/engine.h
+new file mode 100644
+index 0000000..d3635f8
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/engine.h
+@@ -0,0 +1,129 @@
++/*
++ * 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_ENGINE_H__
++#define __DAL_ENGINE_H__
++
++enum i2caux_transaction_operation {
++ I2CAUX_TRANSACTION_READ,
++ I2CAUX_TRANSACTION_WRITE
++};
++
++enum i2caux_transaction_address_space {
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C = 1,
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD
++};
++
++struct i2caux_transaction_payload {
++ enum i2caux_transaction_address_space address_space;
++ uint32_t address;
++ uint8_t length;
++ uint8_t *data;
++};
++
++enum i2caux_transaction_status {
++ I2CAUX_TRANSACTION_STATUS_UNKNOWN = (-1L),
++ I2CAUX_TRANSACTION_STATUS_SUCCEEDED,
++ I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY,
++ I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT,
++ I2CAUX_TRANSACTION_STATUS_FAILED_PROTOCOL_ERROR,
++ I2CAUX_TRANSACTION_STATUS_FAILED_NACK,
++ I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE,
++ I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION,
++ I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION,
++ I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW
++};
++
++struct i2caux_transaction_request {
++ enum i2caux_transaction_operation operation;
++ struct i2caux_transaction_payload payload;
++ enum i2caux_transaction_status status;
++};
++
++enum i2caux_engine_type {
++ I2CAUX_ENGINE_TYPE_UNKNOWN = (-1L),
++ I2CAUX_ENGINE_TYPE_AUX,
++ I2CAUX_ENGINE_TYPE_I2C_DDC_HW,
++ I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW,
++ I2CAUX_ENGINE_TYPE_I2C_SW
++};
++
++enum i2c_default_speed {
++ I2CAUX_DEFAULT_I2C_HW_SPEED = 50,
++ I2CAUX_DEFAULT_I2C_SW_SPEED = 50
++};
++
++enum i2caux_transaction_action {
++ I2CAUX_TRANSACTION_ACTION_I2C_WRITE = 0x00,
++ I2CAUX_TRANSACTION_ACTION_I2C_READ = 0x10,
++ I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST = 0x20,
++
++ I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT = 0x40,
++ I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT = 0x50,
++ I2CAUX_TRANSACTION_ACTION_I2C_STATUS_REQUEST_MOT = 0x60,
++
++ I2CAUX_TRANSACTION_ACTION_DP_WRITE = 0x80,
++ I2CAUX_TRANSACTION_ACTION_DP_READ = 0x90
++};
++
++struct engine;
++
++struct engine_funcs {
++ enum i2caux_engine_type (*get_engine_type)(
++ const struct engine *engine);
++ bool (*acquire)(
++ struct engine *engine,
++ struct ddc *ddc);
++ bool (*submit_request)(
++ struct engine *engine,
++ struct i2caux_transaction_request *request,
++ bool middle_of_transaction);
++ /* [anaumov] Actually, following method is meaningful
++ * only in I2C HW engines */
++ void (*keep_power_up_count)(
++ struct engine *engine,
++ bool keep_power_up);
++ void (*release_engine)(
++ struct engine *engine);
++};
++
++struct engine {
++ const struct engine_funcs *funcs;
++ struct ddc *ddc;
++ struct dc_context *ctx;
++};
++
++bool dal_i2caux_construct_engine(
++ struct engine *engine,
++ struct dc_context *ctx);
++
++void dal_i2caux_destruct_engine(
++ struct engine *engine);
++
++void dal_i2caux_keep_power_up_count(
++ struct engine *engine,
++ bool keep_power_up);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/engine_base.c b/drivers/gpu/drm/amd/dal/dc/i2caux/engine_base.c
+new file mode 100644
+index 0000000..2f87a65
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/engine_base.c
+@@ -0,0 +1,68 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "engine.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++void dal_i2caux_keep_power_up_count(
++ struct engine *engine,
++ bool keep_power_up)
++{
++
++}
++
++bool dal_i2caux_construct_engine(
++ struct engine *engine,
++ struct dc_context *ctx)
++{
++ engine->ddc = NULL;
++ engine->ctx = ctx;
++ return true;
++}
++
++void dal_i2caux_destruct_engine(
++ struct engine *engine)
++{
++ /* nothing to do */
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.c b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.c
+new file mode 100644
+index 0000000..78c7d61
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.c
+@@ -0,0 +1,122 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "engine.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "i2c_engine.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++#define FROM_ENGINE(ptr) \
++ container_of((ptr), struct i2c_engine, base)
++
++bool dal_i2c_engine_acquire(
++ struct engine *engine,
++ struct ddc *ddc_handle)
++{
++ struct i2c_engine *i2c_engine = FROM_ENGINE(engine);
++
++ uint32_t counter = 0;
++ bool result;
++
++ do {
++ result = i2c_engine->funcs->acquire_engine(
++ i2c_engine, ddc_handle);
++
++ if (result)
++ break;
++
++ /* i2c_engine is busy by VBios, lets wait and retry */
++
++ dc_service_delay_in_microseconds(engine->ctx, 10);
++
++ ++counter;
++ } while (counter < 2);
++
++ if (result) {
++ if (!i2c_engine->funcs->setup_engine(i2c_engine)) {
++ engine->funcs->release_engine(engine);
++ result = false;
++ }
++ }
++
++ return result;
++}
++
++bool dal_i2c_engine_setup_i2c_engine(
++ struct i2c_engine *engine)
++{
++ /* Derivative classes do not have to override this */
++
++ return true;
++}
++
++void dal_i2c_engine_submit_channel_request(
++ struct i2c_engine *engine,
++ struct i2c_request_transaction_data *request)
++{
++
++}
++
++void dal_i2c_engine_process_channel_reply(
++ struct i2c_engine *engine,
++ struct i2c_reply_transaction_data *reply)
++{
++
++}
++
++bool dal_i2c_engine_construct(
++ struct i2c_engine *engine,
++ struct dc_context *ctx)
++{
++ if (!dal_i2caux_construct_engine(&engine->base, ctx))
++ return false;
++
++ engine->timeout_delay = 0;
++ return true;
++}
++
++void dal_i2c_engine_destruct(
++ struct i2c_engine *engine)
++{
++ dal_i2caux_destruct_engine(&engine->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.h b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.h
+new file mode 100644
+index 0000000..20299fd
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_engine.h
+@@ -0,0 +1,113 @@
++/*
++ * 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_I2C_ENGINE_H__
++#define __DAL_I2C_ENGINE_H__
++
++enum i2c_channel_operation_result {
++ I2C_CHANNEL_OPERATION_SUCCEEDED,
++ I2C_CHANNEL_OPERATION_FAILED,
++ I2C_CHANNEL_OPERATION_NOT_GRANTED,
++ I2C_CHANNEL_OPERATION_IS_BUSY,
++ I2C_CHANNEL_OPERATION_NO_HANDLE_PROVIDED,
++ I2C_CHANNEL_OPERATION_CHANNEL_IN_USE,
++ I2C_CHANNEL_OPERATION_CHANNEL_CLIENT_MAX_ALLOWED,
++ I2C_CHANNEL_OPERATION_ENGINE_BUSY,
++ I2C_CHANNEL_OPERATION_TIMEOUT,
++ I2C_CHANNEL_OPERATION_NO_RESPONSE,
++ I2C_CHANNEL_OPERATION_HW_REQUEST_I2C_BUS,
++ I2C_CHANNEL_OPERATION_WRONG_PARAMETER,
++ I2C_CHANNEL_OPERATION_OUT_NB_OF_RETRIES,
++ I2C_CHANNEL_OPERATION_NOT_STARTED
++};
++
++struct i2c_request_transaction_data {
++ enum i2caux_transaction_action action;
++ enum i2c_channel_operation_result status;
++ uint8_t address;
++ uint8_t length;
++ uint8_t *data;
++};
++
++struct i2c_reply_transaction_data {
++ uint8_t length;
++ uint8_t *data;
++};
++
++struct i2c_engine;
++
++struct i2c_engine_funcs {
++ void (*destroy)(
++ struct i2c_engine **ptr);
++ uint32_t (*get_speed)(
++ const struct i2c_engine *engine);
++ void (*set_speed)(
++ struct i2c_engine *engine,
++ uint32_t speed);
++ bool (*acquire_engine)(
++ struct i2c_engine *engine,
++ struct ddc *ddc);
++ bool (*setup_engine)(
++ struct i2c_engine *engine);
++ void (*submit_channel_request)(
++ struct i2c_engine *engine,
++ struct i2c_request_transaction_data *request);
++ void (*process_channel_reply)(
++ struct i2c_engine *engine,
++ struct i2c_reply_transaction_data *reply);
++ enum i2c_channel_operation_result (*get_channel_status)(
++ struct i2c_engine *engine,
++ uint8_t *returned_bytes);
++};
++
++struct i2c_engine {
++ struct engine base;
++ const struct i2c_engine_funcs *funcs;
++ uint32_t timeout_delay;
++};
++
++bool dal_i2c_engine_construct(
++ struct i2c_engine *engine,
++ struct dc_context *ctx);
++
++void dal_i2c_engine_destruct(
++ struct i2c_engine *engine);
++
++bool dal_i2c_engine_setup_i2c_engine(
++ struct i2c_engine *engine);
++
++void dal_i2c_engine_submit_channel_request(
++ struct i2c_engine *engine,
++ struct i2c_request_transaction_data *request);
++
++void dal_i2c_engine_process_channel_reply(
++ struct i2c_engine *engine,
++ struct i2c_reply_transaction_data *reply);
++
++bool dal_i2c_engine_acquire(
++ struct engine *ptr,
++ struct ddc *ddc_handle);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.c b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.c
+new file mode 100644
+index 0000000..d91e259
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.c
+@@ -0,0 +1,287 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "engine.h"
++#include "i2c_engine.h"
++#include "i2c_hw_engine.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "i2c_generic_hw_engine.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++/*
++ * @brief
++ * Cast 'struct i2c_hw_engine *'
++ * to 'struct i2c_generic_hw_engine *'
++ */
++#define FROM_I2C_HW_ENGINE(ptr) \
++ container_of((ptr), struct i2c_generic_hw_engine, base)
++
++/*
++ * @brief
++ * Cast 'struct i2c_engine *'
++ * to 'struct i2c_generic_hw_engine *'
++ */
++#define FROM_I2C_ENGINE(ptr) \
++ FROM_I2C_HW_ENGINE(container_of((ptr), struct i2c_hw_engine, base))
++
++/*
++ * @brief
++ * Cast 'struct engine *'
++ * to 'struct i2c_generic_hw_engine *'
++ */
++#define FROM_ENGINE(ptr) \
++ FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
++
++enum i2caux_engine_type dal_i2c_generic_hw_engine_get_engine_type(
++ const struct engine *engine)
++{
++ return I2CAUX_ENGINE_TYPE_I2C_GENERIC_HW;
++}
++
++/*
++ * @brief
++ * Single transaction handling.
++ * Since transaction may be bigger than HW buffer size,
++ * it divides transaction to sub-transactions
++ * and uses batch transaction feature of the engine.
++ */
++bool dal_i2c_generic_hw_engine_submit_request(
++ struct engine *engine,
++ struct i2caux_transaction_request *i2caux_request,
++ bool middle_of_transaction)
++{
++ struct i2c_generic_hw_engine *hw_engine = FROM_ENGINE(engine);
++
++ struct i2c_hw_engine *base = &hw_engine->base;
++
++ uint8_t max_payload_size =
++ base->funcs->get_hw_buffer_available_size(base);
++
++ bool initial_stop_bit = !middle_of_transaction;
++
++ struct i2c_generic_transaction_attributes attributes;
++
++ enum i2c_channel_operation_result operation_result =
++ I2C_CHANNEL_OPERATION_FAILED;
++
++ bool result = false;
++
++ /* setup transaction initial properties */
++
++ uint8_t address = i2caux_request->payload.address;
++ uint8_t *current_payload = i2caux_request->payload.data;
++ uint8_t remaining_payload_size = i2caux_request->payload.length;
++
++ bool first_iteration = true;
++
++ if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
++ attributes.action = I2CAUX_TRANSACTION_ACTION_I2C_READ;
++ else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
++ attributes.action = I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
++ else {
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
++ return false;
++ }
++
++ /* Do batch transaction.
++ * Divide read/write data into payloads which fit HW buffer size.
++ * 1. Single transaction:
++ * start_bit = 1, stop_bit depends on session state, ack_on_read = 0;
++ * 2. Start of batch transaction:
++ * start_bit = 1, stop_bit = 0, ack_on_read = 1;
++ * 3. Middle of batch transaction:
++ * start_bit = 0, stop_bit = 0, ack_on_read = 1;
++ * 4. End of batch transaction:
++ * start_bit = 0, stop_bit depends on session state, ack_on_read = 0.
++ * Session stop bit is set if 'middle_of_transaction' = 0. */
++
++ while (remaining_payload_size) {
++ uint8_t current_transaction_size;
++ uint8_t current_payload_size;
++
++ bool last_iteration;
++ bool stop_bit;
++
++ /* Calculate current transaction size and payload size.
++ * Transaction size = total number of bytes in transaction,
++ * including slave's address;
++ * Payload size = number of data bytes in transaction. */
++
++ if (first_iteration) {
++ /* In the first sub-transaction we send slave's address
++ * thus we need to reserve one byte for it */
++ current_transaction_size =
++ (remaining_payload_size > max_payload_size - 1) ?
++ max_payload_size :
++ remaining_payload_size + 1;
++
++ current_payload_size = current_transaction_size - 1;
++ } else {
++ /* Second and further sub-transactions will have
++ * entire buffer reserved for data */
++ current_transaction_size =
++ (remaining_payload_size > max_payload_size) ?
++ max_payload_size :
++ remaining_payload_size;
++
++ current_payload_size = current_transaction_size;
++ }
++
++ last_iteration =
++ (remaining_payload_size == current_payload_size);
++
++ stop_bit = last_iteration ? initial_stop_bit : false;
++
++ /* write slave device address */
++
++ if (first_iteration)
++ hw_engine->funcs->write_address(hw_engine, address);
++
++ /* write current portion of data, if requested */
++
++ if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
++ hw_engine->funcs->write_data(
++ hw_engine,
++ current_payload,
++ current_payload_size);
++
++ /* execute transaction */
++
++ attributes.start_bit = first_iteration;
++ attributes.stop_bit = stop_bit;
++ attributes.last_read = last_iteration;
++ attributes.transaction_size = current_transaction_size;
++
++ hw_engine->funcs->execute_transaction(hw_engine, &attributes);
++
++ /* wait until transaction is processed; if it fails - quit */
++
++ operation_result = base->funcs->wait_on_operation_result(
++ base,
++ base->funcs->get_transaction_timeout(
++ base, current_transaction_size),
++ I2C_CHANNEL_OPERATION_ENGINE_BUSY);
++
++ if (operation_result != I2C_CHANNEL_OPERATION_SUCCEEDED)
++ break;
++
++ /* read current portion of data, if requested */
++
++ /* the read offset should be 1 for first sub-transaction,
++ * and 0 for any next one */
++
++ if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
++ hw_engine->funcs->read_data(hw_engine, current_payload,
++ current_payload_size, first_iteration ? 1 : 0);
++
++ /* update loop variables */
++
++ first_iteration = false;
++ current_payload += current_payload_size;
++ remaining_payload_size -= current_payload_size;
++ }
++
++ /* update transaction status */
++
++ switch (operation_result) {
++ case I2C_CHANNEL_OPERATION_SUCCEEDED:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
++ result = true;
++ break;
++ case I2C_CHANNEL_OPERATION_NO_RESPONSE:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
++ break;
++ case I2C_CHANNEL_OPERATION_TIMEOUT:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ break;
++ case I2C_CHANNEL_OPERATION_FAILED:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
++ break;
++ default:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
++ }
++
++ return result;
++}
++
++/*
++ * @brief
++ * Returns number of microseconds to wait until timeout to be considered
++ */
++uint32_t dal_i2c_generic_hw_engine_get_transaction_timeout(
++ const struct i2c_hw_engine *engine,
++ uint32_t length)
++{
++ const struct i2c_engine *base = &engine->base;
++
++ uint32_t speed = base->funcs->get_speed(base);
++
++ if (!speed)
++ return 0;
++
++ /* total timeout = period_timeout * (start + data bits count + stop) */
++
++ return ((1000 * TRANSACTION_TIMEOUT_IN_I2C_CLOCKS) / speed) *
++ (1 + (length << 3) + 1);
++}
++
++bool dal_i2c_generic_hw_engine_construct(
++ struct i2c_generic_hw_engine *engine,
++ struct dc_context *ctx)
++{
++ if (!dal_i2c_hw_engine_construct(&engine->base, ctx))
++ return false;
++ return true;
++}
++
++void dal_i2c_generic_hw_engine_destruct(
++ struct i2c_generic_hw_engine *engine)
++{
++ dal_i2c_hw_engine_destruct(&engine->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.h b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.h
+new file mode 100644
+index 0000000..52f2aa2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_generic_hw_engine.h
+@@ -0,0 +1,77 @@
++/*
++ * 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_I2C_GENERIC_HW_ENGINE_H__
++#define __DAL_I2C_GENERIC_HW_ENGINE_H__
++
++struct i2c_generic_transaction_attributes {
++ enum i2caux_transaction_action action;
++ uint8_t transaction_size;
++ bool start_bit;
++ bool stop_bit;
++ bool last_read;
++};
++
++struct i2c_generic_hw_engine;
++
++struct i2c_generic_hw_engine_funcs {
++ void (*write_address)(
++ struct i2c_generic_hw_engine *engine,
++ uint8_t address);
++ void (*write_data)(
++ struct i2c_generic_hw_engine *engine,
++ const uint8_t *buffer,
++ uint8_t length);
++ void (*read_data)(
++ struct i2c_generic_hw_engine *engine,
++ uint8_t *buffer,
++ uint8_t length,
++ uint32_t offset);
++ void (*execute_transaction)(
++ struct i2c_generic_hw_engine *engine,
++ struct i2c_generic_transaction_attributes *attributes);
++};
++
++struct i2c_generic_hw_engine {
++ struct i2c_hw_engine base;
++ const struct i2c_generic_hw_engine_funcs *funcs;
++};
++
++bool dal_i2c_generic_hw_engine_construct(
++ struct i2c_generic_hw_engine *engine,
++ struct dc_context *ctx);
++
++void dal_i2c_generic_hw_engine_destruct(
++ struct i2c_generic_hw_engine *engine);
++enum i2caux_engine_type dal_i2c_generic_hw_engine_get_engine_type(
++ const struct engine *engine);
++bool dal_i2c_generic_hw_engine_submit_request(
++ struct engine *ptr,
++ struct i2caux_transaction_request *i2caux_request,
++ bool middle_of_transaction);
++uint32_t dal_i2c_generic_hw_engine_get_transaction_timeout(
++ const struct i2c_hw_engine *engine,
++ uint32_t length);
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.c b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.c
+new file mode 100644
+index 0000000..77f2b84
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.c
+@@ -0,0 +1,247 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "engine.h"
++#include "i2c_engine.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "i2c_hw_engine.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++/*
++ * @brief
++ * Cast 'struct i2c_engine *'
++ * to 'struct i2c_hw_engine *'
++ */
++#define FROM_I2C_ENGINE(ptr) \
++ container_of((ptr), struct i2c_hw_engine, base)
++
++/*
++ * @brief
++ * Cast 'struct engine *'
++ * to 'struct i2c_hw_engine *'
++ */
++#define FROM_ENGINE(ptr) \
++ FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
++
++enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type(
++ const struct engine *engine)
++{
++ return I2CAUX_ENGINE_TYPE_I2C_DDC_HW;
++}
++
++bool dal_i2c_hw_engine_submit_request(
++ struct engine *engine,
++ struct i2caux_transaction_request *i2caux_request,
++ bool middle_of_transaction)
++{
++ struct i2c_hw_engine *hw_engine = FROM_ENGINE(engine);
++
++ struct i2c_request_transaction_data request;
++
++ uint32_t transaction_timeout;
++
++ enum i2c_channel_operation_result operation_result;
++
++ bool result = false;
++
++ /* We need following:
++ * transaction length will not exceed
++ * the number of free bytes in HW buffer (minus one for address)*/
++
++ if (i2caux_request->payload.length >=
++ hw_engine->funcs->get_hw_buffer_available_size(hw_engine)) {
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_BUFFER_OVERFLOW;
++ return false;
++ }
++
++ if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
++ request.action = middle_of_transaction ?
++ I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
++ I2CAUX_TRANSACTION_ACTION_I2C_READ;
++ else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
++ request.action = middle_of_transaction ?
++ I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
++ I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
++ else {
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
++ /* [anaumov] in DAL2, there was no "return false" */
++ return false;
++ }
++
++ request.address = (uint8_t)i2caux_request->payload.address;
++ request.length = i2caux_request->payload.length;
++ request.data = i2caux_request->payload.data;
++
++ /* obtain timeout value before submitting request */
++
++ transaction_timeout = hw_engine->funcs->get_transaction_timeout(
++ hw_engine, i2caux_request->payload.length + 1);
++
++ hw_engine->base.funcs->submit_channel_request(
++ &hw_engine->base, &request);
++
++ if ((request.status == I2C_CHANNEL_OPERATION_FAILED) ||
++ (request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY)) {
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY;
++ return false;
++ }
++
++ /* wait until transaction proceed */
++
++ operation_result = hw_engine->funcs->wait_on_operation_result(
++ hw_engine,
++ transaction_timeout,
++ I2C_CHANNEL_OPERATION_ENGINE_BUSY);
++
++ /* update transaction status */
++
++ switch (operation_result) {
++ case I2C_CHANNEL_OPERATION_SUCCEEDED:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
++ result = true;
++ break;
++ case I2C_CHANNEL_OPERATION_NO_RESPONSE:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
++ break;
++ case I2C_CHANNEL_OPERATION_TIMEOUT:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ break;
++ case I2C_CHANNEL_OPERATION_FAILED:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
++ break;
++ default:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
++ }
++
++ if (result && (i2caux_request->operation == I2CAUX_TRANSACTION_READ)) {
++ struct i2c_reply_transaction_data reply;
++
++ reply.data = i2caux_request->payload.data;
++ reply.length = i2caux_request->payload.length;
++
++ hw_engine->base.funcs->
++ process_channel_reply(&hw_engine->base, &reply);
++ }
++
++ return result;
++}
++
++bool dal_i2c_hw_engine_acquire_engine(
++ struct i2c_engine *engine,
++ struct ddc *ddc)
++{
++ enum gpio_result result;
++ uint32_t current_speed;
++
++ result = dal_ddc_open(ddc, GPIO_MODE_HARDWARE,
++ GPIO_DDC_CONFIG_TYPE_MODE_I2C);
++
++ if (result != GPIO_RESULT_OK)
++ return false;
++
++ engine->base.ddc = ddc;
++
++ current_speed = engine->funcs->get_speed(engine);
++
++ if (current_speed)
++ FROM_I2C_ENGINE(engine)->original_speed = current_speed;
++
++ return true;
++}
++/*
++ * @brief
++ * Queries in a loop for current engine status
++ * until retrieved status matches 'expected_result', or timeout occurs.
++ * Timeout given in microseconds
++ * and the status query frequency is also one per microsecond.
++ */
++enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result(
++ struct i2c_hw_engine *engine,
++ uint32_t timeout,
++ enum i2c_channel_operation_result expected_result)
++{
++ enum i2c_channel_operation_result result;
++ uint32_t i = 0;
++
++ if (!timeout)
++ return I2C_CHANNEL_OPERATION_SUCCEEDED;
++
++ do {
++ result = engine->base.funcs->get_channel_status(
++ &engine->base, NULL);
++
++ if (result != expected_result)
++ break;
++
++ dc_service_delay_in_microseconds(engine->base.base.ctx, 1);
++
++ ++i;
++ } while (i < timeout);
++
++ return result;
++}
++
++bool dal_i2c_hw_engine_construct(
++ struct i2c_hw_engine *engine,
++ struct dc_context *ctx)
++{
++ if (!dal_i2c_engine_construct(&engine->base, ctx))
++ return false;
++ engine->original_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
++ engine->default_speed = I2CAUX_DEFAULT_I2C_HW_SPEED;
++ return true;
++}
++
++void dal_i2c_hw_engine_destruct(
++ struct i2c_hw_engine *engine)
++{
++ dal_i2c_engine_destruct(&engine->base);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.h b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.h
+new file mode 100644
+index 0000000..5afbd70
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_hw_engine.h
+@@ -0,0 +1,80 @@
++/*
++ * 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_I2C_HW_ENGINE_H__
++#define __DAL_I2C_HW_ENGINE_H__
++
++enum {
++ TRANSACTION_TIMEOUT_IN_I2C_CLOCKS = 32
++};
++
++struct i2c_hw_engine;
++
++struct i2c_hw_engine_funcs {
++ uint8_t (*get_hw_buffer_available_size)(
++ const struct i2c_hw_engine *engine);
++ enum i2c_channel_operation_result (*wait_on_operation_result)(
++ struct i2c_hw_engine *engine,
++ uint32_t timeout,
++ enum i2c_channel_operation_result expected_result);
++ uint32_t (*get_transaction_timeout)(
++ const struct i2c_hw_engine *engine,
++ uint32_t length);
++};
++
++struct i2c_hw_engine {
++ struct i2c_engine base;
++ const struct i2c_hw_engine_funcs *funcs;
++
++ /* Values below are in kilohertz */
++ uint32_t original_speed;
++ uint32_t default_speed;
++};
++
++bool dal_i2c_hw_engine_construct(
++ struct i2c_hw_engine *engine,
++ struct dc_context *ctx);
++
++void dal_i2c_hw_engine_destruct(
++ struct i2c_hw_engine *engine);
++
++enum i2c_channel_operation_result dal_i2c_hw_engine_wait_on_operation_result(
++ struct i2c_hw_engine *engine,
++ uint32_t timeout,
++ enum i2c_channel_operation_result expected_result);
++
++bool dal_i2c_hw_engine_acquire_engine(
++ struct i2c_engine *engine,
++ struct ddc *ddc);
++
++bool dal_i2c_hw_engine_submit_request(
++ struct engine *ptr,
++ struct i2caux_transaction_request *i2caux_request,
++ bool middle_of_transaction);
++
++enum i2caux_engine_type dal_i2c_hw_engine_get_engine_type(
++ const struct engine *engine);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.c b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.c
+new file mode 100644
+index 0000000..c253917
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.c
+@@ -0,0 +1,615 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++#include "engine.h"
++#include "i2c_engine.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "i2c_sw_engine.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++/*
++ * This unit
++ */
++
++#define SCL false
++#define SDA true
++
++static inline bool read_bit_from_ddc(
++ struct ddc *ddc,
++ bool data_nor_clock)
++{
++ uint32_t value = 0;
++
++ if (data_nor_clock)
++ dal_ddc_get_data(ddc, &value);
++ else
++ dal_ddc_get_clock(ddc, &value);
++
++ return (value != 0);
++}
++
++static inline void write_bit_to_ddc(
++ struct ddc *ddc,
++ bool data_nor_clock,
++ bool bit)
++{
++ uint32_t value = bit ? 1 : 0;
++
++ if (data_nor_clock)
++ dal_ddc_set_data(ddc, value);
++ else
++ dal_ddc_set_clock(ddc, value);
++}
++
++static bool wait_for_scl_high(
++ struct dc_context *ctx,
++ struct ddc *ddc,
++ uint16_t clock_delay_div_4)
++{
++ uint32_t scl_retry = 0;
++ uint32_t scl_retry_max = I2C_SW_TIMEOUT_DELAY / clock_delay_div_4;
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ /* 3 milliseconds delay
++ * to wake up some displays from "low power" state.
++ */
++
++ do {
++ if (read_bit_from_ddc(ddc, SCL))
++ return true;
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ ++scl_retry;
++ } while (scl_retry <= scl_retry_max);
++
++ return false;
++}
++
++static bool start_sync(
++ struct dc_context *ctx,
++ struct ddc *ddc_handle,
++ uint16_t clock_delay_div_4)
++{
++ uint32_t retry = 0;
++
++ /* The I2C communications start signal is:
++ * the SDA going low from high, while the SCL is high. */
++
++ write_bit_to_ddc(ddc_handle, SCL, true);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ do {
++ write_bit_to_ddc(ddc_handle, SDA, true);
++
++ if (!read_bit_from_ddc(ddc_handle, SDA)) {
++ ++retry;
++ continue;
++ }
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SCL, true);
++
++ if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
++ break;
++
++ write_bit_to_ddc(ddc_handle, SDA, false);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SCL, false);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ return true;
++ } while (retry <= I2C_SW_RETRIES);
++
++ return false;
++}
++
++static bool stop_sync(
++ struct dc_context *ctx,
++ struct ddc *ddc_handle,
++ uint16_t clock_delay_div_4)
++{
++ uint32_t retry = 0;
++
++ /* The I2C communications stop signal is:
++ * the SDA going high from low, while the SCL is high. */
++
++ write_bit_to_ddc(ddc_handle, SCL, false);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SDA, false);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SCL, true);
++
++ if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
++ return false;
++
++ write_bit_to_ddc(ddc_handle, SDA, true);
++
++ do {
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ if (read_bit_from_ddc(ddc_handle, SDA))
++ return true;
++
++ ++retry;
++ } while (retry <= 2);
++
++ return false;
++}
++
++static bool write_byte(
++ struct dc_context *ctx,
++ struct ddc *ddc_handle,
++ uint16_t clock_delay_div_4,
++ uint8_t byte)
++{
++ int32_t shift = 7;
++ bool ack;
++
++ /* bits are transmitted serially, starting from MSB */
++
++ do {
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SDA, (byte >> shift) & 1);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SCL, true);
++
++ if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
++ return false;
++
++ write_bit_to_ddc(ddc_handle, SCL, false);
++
++ --shift;
++ } while (shift >= 0);
++
++ /* The display sends ACK by preventing the SDA from going high
++ * after the SCL pulse we use to send our last data bit.
++ * If the SDA goes high after that bit, it's a NACK */
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SDA, true);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SCL, true);
++
++ if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
++ return false;
++
++ /* read ACK bit */
++
++ ack = !read_bit_from_ddc(ddc_handle, SDA);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4 << 1);
++
++ write_bit_to_ddc(ddc_handle, SCL, false);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4 << 1);
++
++ return ack;
++}
++
++static bool read_byte(
++ struct dc_context *ctx,
++ struct ddc *ddc_handle,
++ uint16_t clock_delay_div_4,
++ uint8_t *byte,
++ bool more)
++{
++ int32_t shift = 7;
++
++ uint8_t data = 0;
++
++ /* The data bits are read from MSB to LSB;
++ * bit is read while SCL is high */
++
++ do {
++ write_bit_to_ddc(ddc_handle, SCL, true);
++
++ if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
++ return false;
++
++ if (read_bit_from_ddc(ddc_handle, SDA))
++ data |= (1 << shift);
++
++ write_bit_to_ddc(ddc_handle, SCL, false);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4 << 1);
++
++ --shift;
++ } while (shift >= 0);
++
++ /* read only whole byte */
++
++ *byte = data;
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ /* send the acknowledge bit:
++ * SDA low means ACK, SDA high means NACK */
++
++ write_bit_to_ddc(ddc_handle, SDA, !more);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SCL, true);
++
++ if (!wait_for_scl_high(ctx, ddc_handle, clock_delay_div_4))
++ return false;
++
++ write_bit_to_ddc(ddc_handle, SCL, false);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ write_bit_to_ddc(ddc_handle, SDA, true);
++
++ dc_service_delay_in_microseconds(ctx, clock_delay_div_4);
++
++ return true;
++}
++
++static bool i2c_write(
++ struct dc_context *ctx,
++ struct ddc *ddc_handle,
++ uint16_t clock_delay_div_4,
++ uint8_t address,
++ uint8_t length,
++ const uint8_t *data)
++{
++ uint32_t i = 0;
++
++ if (!write_byte(ctx, ddc_handle, clock_delay_div_4, address))
++ return false;
++
++ while (i < length) {
++ if (!write_byte(ctx, ddc_handle, clock_delay_div_4, data[i]))
++ return false;
++ ++i;
++ }
++
++ return true;
++}
++
++static bool i2c_read(
++ struct dc_context *ctx,
++ struct ddc *ddc_handle,
++ uint16_t clock_delay_div_4,
++ uint8_t address,
++ uint8_t length,
++ uint8_t *data)
++{
++ uint32_t i = 0;
++
++ if (!write_byte(ctx, ddc_handle, clock_delay_div_4, address))
++ return false;
++
++ while (i < length) {
++ if (!read_byte(ctx, ddc_handle, clock_delay_div_4, data + i,
++ i < length - 1))
++ return false;
++ ++i;
++ }
++
++ return true;
++}
++
++/*
++ * @brief
++ * Cast 'struct i2c_engine *'
++ * to 'struct i2c_sw_engine *'
++ */
++#define FROM_I2C_ENGINE(ptr) \
++ container_of((ptr), struct i2c_sw_engine, base)
++
++/*
++ * @brief
++ * Cast 'struct engine *'
++ * to 'struct i2c_sw_engine *'
++ */
++#define FROM_ENGINE(ptr) \
++ FROM_I2C_ENGINE(container_of((ptr), struct i2c_engine, base))
++
++enum i2caux_engine_type dal_i2c_sw_engine_get_engine_type(
++ const struct engine *engine)
++{
++ return I2CAUX_ENGINE_TYPE_I2C_SW;
++}
++
++bool dal_i2c_sw_engine_submit_request(
++ struct engine *engine,
++ struct i2caux_transaction_request *i2caux_request,
++ bool middle_of_transaction)
++{
++ struct i2c_sw_engine *sw_engine = FROM_ENGINE(engine);
++
++ struct i2c_engine *base = &sw_engine->base;
++
++ struct i2c_request_transaction_data request;
++ bool operation_succeeded = false;
++
++ if (i2caux_request->operation == I2CAUX_TRANSACTION_READ)
++ request.action = middle_of_transaction ?
++ I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT :
++ I2CAUX_TRANSACTION_ACTION_I2C_READ;
++ else if (i2caux_request->operation == I2CAUX_TRANSACTION_WRITE)
++ request.action = middle_of_transaction ?
++ I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT :
++ I2CAUX_TRANSACTION_ACTION_I2C_WRITE;
++ else {
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_INVALID_OPERATION;
++ /* in DAL2, there was no "return false" */
++ return false;
++ }
++
++ request.address = (uint8_t)i2caux_request->payload.address;
++ request.length = i2caux_request->payload.length;
++ request.data = i2caux_request->payload.data;
++
++ base->funcs->submit_channel_request(base, &request);
++
++ if ((request.status == I2C_CHANNEL_OPERATION_ENGINE_BUSY) ||
++ (request.status == I2C_CHANNEL_OPERATION_FAILED))
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_CHANNEL_BUSY;
++ else {
++ enum i2c_channel_operation_result operation_result;
++
++ do {
++ operation_result =
++ base->funcs->get_channel_status(base, NULL);
++
++ switch (operation_result) {
++ case I2C_CHANNEL_OPERATION_SUCCEEDED:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_SUCCEEDED;
++ operation_succeeded = true;
++ break;
++ case I2C_CHANNEL_OPERATION_NO_RESPONSE:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_NACK;
++ break;
++ case I2C_CHANNEL_OPERATION_TIMEOUT:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_TIMEOUT;
++ break;
++ case I2C_CHANNEL_OPERATION_FAILED:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_INCOMPLETE;
++ break;
++ default:
++ i2caux_request->status =
++ I2CAUX_TRANSACTION_STATUS_FAILED_OPERATION;
++ break;
++ }
++ } while (operation_result == I2C_CHANNEL_OPERATION_ENGINE_BUSY);
++ }
++
++ return operation_succeeded;
++}
++
++uint32_t dal_i2c_sw_engine_get_speed(
++ const struct i2c_engine *engine)
++{
++ return FROM_I2C_ENGINE(engine)->speed;
++}
++
++void dal_i2c_sw_engine_set_speed(
++ struct i2c_engine *engine,
++ uint32_t speed)
++{
++ struct i2c_sw_engine *sw_engine = FROM_I2C_ENGINE(engine);
++
++ ASSERT(speed);
++
++ sw_engine->speed = speed ? speed : I2CAUX_DEFAULT_I2C_SW_SPEED;
++
++ sw_engine->clock_delay = 1000 / sw_engine->speed;
++
++ if (sw_engine->clock_delay < 12)
++ sw_engine->clock_delay = 12;
++}
++
++bool dal_i2caux_i2c_sw_engine_acquire_engine(
++ struct i2c_engine *engine,
++ struct ddc *ddc)
++{
++ enum gpio_result result;
++
++ result = dal_ddc_open(ddc, GPIO_MODE_FAST_OUTPUT,
++ GPIO_DDC_CONFIG_TYPE_MODE_I2C);
++
++ if (result != GPIO_RESULT_OK)
++ return false;
++
++ engine->base.ddc = ddc;
++
++ return true;
++}
++
++void dal_i2c_sw_engine_submit_channel_request(
++ struct i2c_engine *engine,
++ struct i2c_request_transaction_data *req)
++{
++ struct i2c_sw_engine *sw_engine = FROM_I2C_ENGINE(engine);
++
++ struct ddc *ddc = engine->base.ddc;
++ uint16_t clock_delay_div_4 = sw_engine->clock_delay >> 2;
++
++ /* send sync (start / repeated start) */
++
++ bool result = start_sync(engine->base.ctx, ddc, clock_delay_div_4);
++
++ /* process payload */
++
++ if (result) {
++ switch (req->action) {
++ case I2CAUX_TRANSACTION_ACTION_I2C_WRITE:
++ case I2CAUX_TRANSACTION_ACTION_I2C_WRITE_MOT:
++ result = i2c_write(engine->base.ctx, ddc, clock_delay_div_4,
++ req->address, req->length, req->data);
++ break;
++ case I2CAUX_TRANSACTION_ACTION_I2C_READ:
++ case I2CAUX_TRANSACTION_ACTION_I2C_READ_MOT:
++ result = i2c_read(engine->base.ctx, ddc, clock_delay_div_4,
++ req->address, req->length, req->data);
++ break;
++ default:
++ result = false;
++ break;
++ }
++ }
++
++ /* send stop if not 'mot' or operation failed */
++
++ if (!result ||
++ (req->action == I2CAUX_TRANSACTION_ACTION_I2C_WRITE) ||
++ (req->action == I2CAUX_TRANSACTION_ACTION_I2C_READ))
++ if (!stop_sync(engine->base.ctx, ddc, clock_delay_div_4))
++ result = false;
++
++ req->status = result ?
++ I2C_CHANNEL_OPERATION_SUCCEEDED :
++ I2C_CHANNEL_OPERATION_FAILED;
++}
++
++enum i2c_channel_operation_result dal_i2c_sw_engine_get_channel_status(
++ struct i2c_engine *engine,
++ uint8_t *returned_bytes)
++{
++ return dal_ddc_check_line_aborted(engine->base.ddc) ?
++ I2C_CHANNEL_OPERATION_FAILED :
++ I2C_CHANNEL_OPERATION_SUCCEEDED;
++}
++
++void dal_i2c_sw_engine_destruct(
++ struct i2c_sw_engine *engine)
++{
++ dal_i2c_engine_destruct(&engine->base);
++}
++
++static void destroy(
++ struct i2c_engine **ptr)
++{
++ dal_i2c_sw_engine_destruct(FROM_I2C_ENGINE(*ptr));
++
++ dc_service_free((*ptr)->base.ctx, *ptr);
++ *ptr = NULL;
++}
++
++static const struct i2c_engine_funcs i2c_engine_funcs = {
++ .acquire_engine = dal_i2caux_i2c_sw_engine_acquire_engine,
++ .destroy = destroy,
++ .get_speed = dal_i2c_sw_engine_get_speed,
++ .set_speed = dal_i2c_sw_engine_set_speed,
++ .setup_engine = dal_i2c_engine_setup_i2c_engine,
++ .submit_channel_request = dal_i2c_sw_engine_submit_channel_request,
++ .process_channel_reply = dal_i2c_engine_process_channel_reply,
++ .get_channel_status = dal_i2c_sw_engine_get_channel_status,
++};
++
++static void release_engine(
++ struct engine *engine)
++{
++
++}
++
++static const struct engine_funcs engine_funcs = {
++ .release_engine = release_engine,
++ .get_engine_type = dal_i2c_sw_engine_get_engine_type,
++ .acquire = dal_i2c_engine_acquire,
++ .submit_request = dal_i2c_sw_engine_submit_request,
++ .keep_power_up_count = dal_i2caux_keep_power_up_count,
++};
++
++bool dal_i2c_sw_engine_construct(
++ struct i2c_sw_engine *engine,
++ const struct i2c_sw_engine_create_arg *arg)
++{
++ if (!dal_i2c_engine_construct(&engine->base, arg->ctx))
++ return false;
++
++ dal_i2c_sw_engine_set_speed(&engine->base, arg->default_speed);
++ engine->base.funcs = &i2c_engine_funcs;
++ engine->base.base.funcs = &engine_funcs;
++ return true;
++}
++
++
++
++struct i2c_engine *dal_i2c_sw_engine_create(
++ const struct i2c_sw_engine_create_arg *arg)
++{
++ struct i2c_sw_engine *engine;
++
++ if (!arg) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ engine = dc_service_alloc(arg->ctx, sizeof(struct i2c_sw_engine));
++
++ if (!engine) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ if (dal_i2c_sw_engine_construct(engine, arg))
++ return &engine->base;
++
++ BREAK_TO_DEBUGGER();
++
++ dc_service_free(arg->ctx, engine);
++
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.h b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.h
+new file mode 100644
+index 0000000..e0cb4c3
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2c_sw_engine.h
+@@ -0,0 +1,81 @@
++/*
++ * 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_I2C_SW_ENGINE_H__
++#define __DAL_I2C_SW_ENGINE_H__
++
++enum {
++ I2C_SW_RETRIES = 10,
++ I2C_SW_SCL_READ_RETRIES = 128,
++ /* following value is in microseconds */
++ I2C_SW_TIMEOUT_DELAY = 3000
++};
++
++struct i2c_sw_engine;
++
++struct i2c_sw_engine {
++ struct i2c_engine base;
++ uint32_t clock_delay;
++ /* Values below are in KHz */
++ uint32_t speed;
++ uint32_t default_speed;
++};
++
++struct i2c_sw_engine_create_arg {
++ uint32_t default_speed;
++ struct dc_context *ctx;
++};
++
++bool dal_i2c_sw_engine_construct(
++ struct i2c_sw_engine *engine,
++ const struct i2c_sw_engine_create_arg *arg);
++
++bool dal_i2caux_i2c_sw_engine_acquire_engine(
++ struct i2c_engine *engine,
++ struct ddc *ddc_handle);
++
++void dal_i2c_sw_engine_destruct(
++ struct i2c_sw_engine *engine);
++
++struct i2c_engine *dal_i2c_sw_engine_create(
++ const struct i2c_sw_engine_create_arg *arg);
++enum i2caux_engine_type dal_i2c_sw_engine_get_engine_type(
++ const struct engine *engine);
++bool dal_i2c_sw_engine_submit_request(
++ struct engine *ptr,
++ struct i2caux_transaction_request *i2caux_request,
++ bool middle_of_transaction);
++uint32_t dal_i2c_sw_engine_get_speed(
++ const struct i2c_engine *engine);
++void dal_i2c_sw_engine_set_speed(
++ struct i2c_engine *ptr,
++ uint32_t speed);
++void dal_i2c_sw_engine_submit_channel_request(
++ struct i2c_engine *ptr,
++ struct i2c_request_transaction_data *req);
++enum i2c_channel_operation_result dal_i2c_sw_engine_get_channel_status(
++ struct i2c_engine *engine,
++ uint8_t *returned_bytes);
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
+new file mode 100644
+index 0000000..50262a4
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.c
+@@ -0,0 +1,519 @@
++/*
++ * 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 "dal_services.h"
++
++/*
++ * Pre-requisites: headers required by header of this unit
++ */
++
++#include "include/i2caux_interface.h"
++
++/*
++ * Header of this unit
++ */
++
++#include "i2caux.h"
++
++/*
++ * Post-requisites: headers required by this unit
++ */
++
++#include "engine.h"
++#include "i2c_engine.h"
++#include "aux_engine.h"
++
++/*
++ * This unit
++ */
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/i2caux_dce110.h"
++#endif
++
++/*
++ * @brief
++ * Plain API, available publicly
++ */
++
++struct i2caux *dal_i2caux_create(
++ struct adapter_service *as,
++ struct dc_context *ctx)
++{
++ enum dce_version dce_version;
++
++ if (!as) {
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++
++ dce_version = dal_adapter_service_get_dce_version(as);
++
++ switch (dce_version) {
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ return dal_i2caux_dce110_create(as, ctx);
++#endif
++ default:
++ BREAK_TO_DEBUGGER();
++ return NULL;
++ }
++}
++
++bool dal_i2caux_submit_i2c_command(
++ struct i2caux *i2caux,
++ struct ddc *ddc,
++ struct i2c_command *cmd)
++{
++ struct i2c_engine *engine;
++ uint8_t index_of_payload = 0;
++ bool result;
++
++ if (!ddc) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!cmd) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ switch (cmd->engine) {
++ case I2C_COMMAND_ENGINE_SW:
++ /* try to acquire SW engine first,
++ * acquire HW engine if SW engine not available */
++ engine = i2caux->funcs->acquire_i2c_sw_engine(i2caux, ddc);
++
++ if (!engine)
++ engine = i2caux->funcs->acquire_i2c_hw_engine(
++ i2caux, ddc);
++ break;
++ case I2C_COMMAND_ENGINE_HW:
++ case I2C_COMMAND_ENGINE_DEFAULT:
++ default:
++ /* try to acquire HW engine first,
++ * acquire SW engine if HW engine not available */
++ engine = i2caux->funcs->acquire_i2c_hw_engine(i2caux, ddc);
++
++ if (!engine)
++ engine = i2caux->funcs->acquire_i2c_sw_engine(
++ i2caux, ddc);
++ }
++
++ if (!engine)
++ return false;
++
++ engine->funcs->set_speed(engine, cmd->speed);
++
++ result = true;
++
++ while (index_of_payload < cmd->number_of_payloads) {
++ bool mot = (index_of_payload != cmd->number_of_payloads - 1);
++
++ struct i2c_payload *payload = cmd->payloads + index_of_payload;
++
++ struct i2caux_transaction_request request = { 0 };
++
++ request.operation = payload->write ?
++ I2CAUX_TRANSACTION_WRITE :
++ I2CAUX_TRANSACTION_READ;
++
++ request.payload.address_space =
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C;
++ request.payload.address = (payload->address << 1) |
++ !payload->write;
++ request.payload.length = payload->length;
++ request.payload.data = payload->data;
++
++ if (!engine->base.funcs->submit_request(
++ &engine->base, &request, mot)) {
++ result = false;
++ break;
++ }
++
++ ++index_of_payload;
++ }
++
++ i2caux->funcs->release_engine(i2caux, &engine->base);
++
++ return result;
++}
++
++bool dal_i2caux_submit_aux_command(
++ struct i2caux *i2caux,
++ struct ddc *ddc,
++ struct aux_command *cmd)
++{
++ struct aux_engine *engine;
++ uint8_t index_of_payload = 0;
++ bool result;
++
++ if (!ddc) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!cmd) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ engine = i2caux->funcs->acquire_aux_engine(i2caux, ddc);
++
++ if (!engine)
++ return false;
++
++ engine->delay = cmd->defer_delay;
++ engine->max_defer_write_retry = cmd->max_defer_write_retry;
++
++ result = true;
++
++ while (index_of_payload < cmd->number_of_payloads) {
++ bool mot = (index_of_payload != cmd->number_of_payloads - 1);
++
++ struct aux_payload *payload = cmd->payloads + index_of_payload;
++
++ struct i2caux_transaction_request request = { 0 };
++
++ request.operation = payload->write ?
++ I2CAUX_TRANSACTION_WRITE :
++ I2CAUX_TRANSACTION_READ;
++
++ if (payload->i2c_over_aux) {
++ request.payload.address_space =
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_I2C;
++
++ request.payload.address = (payload->address << 1) |
++ !payload->write;
++ } else {
++ request.payload.address_space =
++ I2CAUX_TRANSACTION_ADDRESS_SPACE_DPCD;
++
++ request.payload.address = payload->address;
++ }
++
++ request.payload.length = payload->length;
++ request.payload.data = payload->data;
++
++ if (!engine->base.funcs->submit_request(
++ &engine->base, &request, mot)) {
++ result = false;
++ break;
++ }
++
++ ++index_of_payload;
++ }
++
++ i2caux->funcs->release_engine(i2caux, &engine->base);
++
++ return result;
++}
++
++static bool get_hw_supported_ddc_line(
++ struct ddc *ddc,
++ enum gpio_ddc_line *line)
++{
++ enum gpio_ddc_line line_found;
++
++ if (!ddc) {
++ BREAK_TO_DEBUGGER();
++ return false;
++ }
++
++ if (!dal_ddc_is_hw_supported(ddc))
++ return false;
++
++ line_found = dal_ddc_get_line(ddc);
++
++ if (line_found >= GPIO_DDC_LINE_COUNT)
++ return false;
++
++ *line = line_found;
++
++ return true;
++}
++
++void dal_i2caux_keep_engine_power_up(
++ struct i2caux *i2caux,
++ struct ddc *ddc,
++ bool keep_power_up)
++{
++ enum gpio_ddc_line line;
++ struct i2c_engine *engine;
++
++ if (!get_hw_supported_ddc_line(ddc, &line))
++ return;
++
++ engine = i2caux->i2c_hw_engines[line];
++
++ engine->base.funcs->keep_power_up_count(&engine->base, keep_power_up);
++}
++
++bool dal_i2caux_start_gtc_sync(
++ struct i2caux *i2caux,
++ struct ddc *ddc)
++{
++ enum gpio_ddc_line line;
++
++ struct aux_engine *engine;
++
++ bool result;
++
++ if (!get_hw_supported_ddc_line(ddc, &line))
++ return false;
++
++ engine = i2caux->aux_engines[line];
++
++ if (!engine)
++ return false;
++
++ if (!engine->base.funcs->acquire(&engine->base, ddc))
++ return false;
++
++ result = engine->funcs->start_gtc_sync(engine);
++
++ i2caux->funcs->release_engine(i2caux, &engine->base);
++
++ return result;
++}
++
++bool dal_i2caux_stop_gtc_sync(
++ struct i2caux *i2caux,
++ struct ddc *ddc)
++{
++ enum gpio_ddc_line line;
++
++ struct aux_engine *engine;
++
++ if (!get_hw_supported_ddc_line(ddc, &line))
++ return false;
++
++ engine = i2caux->aux_engines[line];
++
++ if (!engine)
++ return false;
++
++ if (!engine->base.funcs->acquire(&engine->base, ddc))
++ return false;
++
++ engine->funcs->stop_gtc_sync(engine);
++
++ i2caux->funcs->release_engine(i2caux, &engine->base);
++
++ return true;
++}
++
++void dal_i2caux_configure_aux(
++ struct i2caux *i2caux,
++ struct ddc *ddc,
++ union aux_config cfg)
++{
++ struct aux_engine *engine =
++ i2caux->funcs->acquire_aux_engine(i2caux, ddc);
++
++ if (!engine)
++ return;
++
++ engine->funcs->configure(engine, cfg);
++
++ i2caux->funcs->release_engine(i2caux, &engine->base);
++}
++
++void dal_i2caux_destroy(
++ struct i2caux **i2caux)
++{
++ if (!i2caux || !*i2caux) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ (*i2caux)->funcs->destroy(i2caux);
++
++ *i2caux = NULL;
++}
++
++/*
++ * @brief
++ * An utility function used by 'struct i2caux' and its descendants
++ */
++
++uint32_t dal_i2caux_get_reference_clock(
++ struct adapter_service *as)
++{
++ struct firmware_info info = { { 0 } };
++
++ if (!dal_adapter_service_get_firmware_info(as, &info))
++ return 0;
++
++ return info.pll_info.crystal_frequency;
++}
++
++/*
++ * @brief
++ * i2caux
++ */
++
++enum {
++ /* following are expressed in KHz */
++ DEFAULT_I2C_SW_SPEED = 50,
++ DEFAULT_I2C_HW_SPEED = 50,
++
++ /* This is the timeout as defined in DP 1.2a,
++ * 2.3.4 "Detailed uPacket TX AUX CH State Description". */
++ AUX_TIMEOUT_PERIOD = 400,
++
++ /* Ideally, the SW timeout should be just above 550usec
++ * which is programmed in HW.
++ * But the SW timeout of 600usec is not reliable,
++ * because on some systems, delay_in_microseconds()
++ * returns faster than it should.
++ * EPR #379763: by trial-and-error on different systems,
++ * 700usec is the minimum reliable SW timeout for polling
++ * the AUX_SW_STATUS.AUX_SW_DONE bit.
++ * This timeout expires *only* when there is
++ * AUX Error or AUX Timeout conditions - not during normal operation.
++ * During normal operation, AUX_SW_STATUS.AUX_SW_DONE bit is set
++ * at most within ~240usec. That means,
++ * increasing this timeout will not affect normal operation,
++ * and we'll timeout after
++ * SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD = 1600usec.
++ * This timeout is especially important for
++ * resume from S3 and CTS. */
++ SW_AUX_TIMEOUT_PERIOD_MULTIPLIER = 4
++};
++
++struct i2c_engine *dal_i2caux_acquire_i2c_sw_engine(
++ struct i2caux *i2caux,
++ struct ddc *ddc)
++{
++ enum gpio_ddc_line line;
++ struct i2c_engine *engine = NULL;
++
++ if (get_hw_supported_ddc_line(ddc, &line))
++ engine = i2caux->i2c_sw_engines[line];
++
++ if (!engine)
++ engine = i2caux->i2c_generic_sw_engine;
++
++ if (!engine)
++ return NULL;
++
++ if (!engine->base.funcs->acquire(&engine->base, ddc))
++ return NULL;
++
++ return engine;
++}
++
++struct aux_engine *dal_i2caux_acquire_aux_engine(
++ struct i2caux *i2caux,
++ struct ddc *ddc)
++{
++ enum gpio_ddc_line line;
++ struct aux_engine *engine;
++
++ if (!get_hw_supported_ddc_line(ddc, &line))
++ return NULL;
++
++ engine = i2caux->aux_engines[line];
++
++ if (!engine)
++ return NULL;
++
++ if (!engine->base.funcs->acquire(&engine->base, ddc))
++ return NULL;
++
++ return engine;
++}
++
++void dal_i2caux_release_engine(
++ struct i2caux *i2caux,
++ struct engine *engine)
++{
++ engine->funcs->release_engine(engine);
++
++ dal_ddc_close(engine->ddc);
++
++ engine->ddc = NULL;
++}
++
++bool dal_i2caux_construct(
++ struct i2caux *i2caux,
++ struct adapter_service *as,
++ struct dc_context *ctx)
++{
++ uint32_t i = 0;
++
++ i2caux->ctx = ctx;
++ do {
++ i2caux->i2c_sw_engines[i] = NULL;
++ i2caux->i2c_hw_engines[i] = NULL;
++ i2caux->aux_engines[i] = NULL;
++
++ ++i;
++ } while (i < GPIO_DDC_LINE_COUNT);
++
++ i2caux->i2c_generic_sw_engine = NULL;
++ i2caux->i2c_generic_hw_engine = NULL;
++
++ i2caux->aux_timeout_period =
++ SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD;
++
++ i2caux->default_i2c_sw_speed = DEFAULT_I2C_SW_SPEED;
++ i2caux->default_i2c_hw_speed = DEFAULT_I2C_HW_SPEED;
++
++ return true;
++}
++
++void dal_i2caux_destruct(
++ struct i2caux *i2caux)
++{
++ uint32_t i = 0;
++
++ if (i2caux->i2c_generic_hw_engine)
++ i2caux->i2c_generic_hw_engine->funcs->destroy(
++ &i2caux->i2c_generic_hw_engine);
++
++ if (i2caux->i2c_generic_sw_engine)
++ i2caux->i2c_generic_sw_engine->funcs->destroy(
++ &i2caux->i2c_generic_sw_engine);
++
++ do {
++ if (i2caux->aux_engines[i])
++ i2caux->aux_engines[i]->funcs->destroy(
++ &i2caux->aux_engines[i]);
++
++ if (i2caux->i2c_hw_engines[i])
++ i2caux->i2c_hw_engines[i]->funcs->destroy(
++ &i2caux->i2c_hw_engines[i]);
++
++ if (i2caux->i2c_sw_engines[i])
++ i2caux->i2c_sw_engines[i]->funcs->destroy(
++ &i2caux->i2c_sw_engines[i]);
++
++ ++i;
++ } while (i < GPIO_DDC_LINE_COUNT);
++}
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.h b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.h
+new file mode 100644
+index 0000000..76f5b63
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/i2caux/i2caux.h
+@@ -0,0 +1,123 @@
++/*
++ * 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_I2C_AUX_H__
++#define __DAL_I2C_AUX_H__
++
++uint32_t dal_i2caux_get_reference_clock(
++ struct adapter_service *as);
++
++struct i2caux;
++
++struct engine;
++
++struct i2caux_funcs {
++ void (*destroy)(struct i2caux **ptr);
++ struct i2c_engine * (*acquire_i2c_sw_engine)(
++ struct i2caux *i2caux,
++ struct ddc *ddc);
++ struct i2c_engine * (*acquire_i2c_hw_engine)(
++ struct i2caux *i2caux,
++ struct ddc *ddc);
++ struct aux_engine * (*acquire_aux_engine)(
++ struct i2caux *i2caux,
++ struct ddc *ddc);
++ void (*release_engine)(
++ struct i2caux *i2caux,
++ struct engine *engine);
++};
++
++struct i2c_engine;
++struct aux_engine;
++
++struct i2caux {
++ struct dc_context *ctx;
++ const struct i2caux_funcs *funcs;
++ /* On ASIC we have certain amount of lines with HW DDC engine
++ * (4, 6, or maybe more in the future).
++ * For every such line, we create separate HW DDC engine
++ * (since we have these engines in HW) and separate SW DDC engine
++ * (to allow concurrent use of few lines).
++ * In similar way we have AUX engines. */
++
++ /* I2C SW engines, per DDC line.
++ * Only lines with HW DDC support will be initialized */
++ struct i2c_engine *i2c_sw_engines[GPIO_DDC_LINE_COUNT];
++
++ /* I2C HW engines, per DDC line.
++ * Only lines with HW DDC support will be initialized */
++ struct i2c_engine *i2c_hw_engines[GPIO_DDC_LINE_COUNT];
++
++ /* AUX engines, per DDC line.
++ * Only lines with HW AUX support will be initialized */
++ struct aux_engine *aux_engines[GPIO_DDC_LINE_COUNT];
++
++ /* For all other lines, we can use
++ * single instance of generic I2C HW engine
++ * (since in HW, there is single instance of it)
++ * or single instance of generic I2C SW engine.
++ * AUX is not supported for other lines. */
++
++ /* General-purpose I2C SW engine.
++ * Can be assigned dynamically to any line per transaction */
++ struct i2c_engine *i2c_generic_sw_engine;
++
++ /* General-purpose I2C generic HW engine.
++ * Can be assigned dynamically to almost any line per transaction */
++ struct i2c_engine *i2c_generic_hw_engine;
++
++ /* [anaumov] in DAL2, there is a Mutex */
++
++ uint32_t aux_timeout_period;
++
++ /* expressed in KHz */
++ uint32_t default_i2c_sw_speed;
++ uint32_t default_i2c_hw_speed;
++};
++
++bool dal_i2caux_construct(
++ struct i2caux *i2caux,
++ struct adapter_service *as,
++ struct dc_context *ctx);
++
++void dal_i2caux_release_engine(
++ struct i2caux *i2caux,
++ struct engine *engine);
++
++void dal_i2caux_destruct(
++ struct i2caux *i2caux);
++
++void dal_i2caux_destroy(
++ struct i2caux **ptr);
++
++struct i2c_engine *dal_i2caux_acquire_i2c_sw_engine(
++ struct i2caux *i2caux,
++ struct ddc *ddc);
++
++struct aux_engine *dal_i2caux_acquire_aux_engine(
++ struct i2caux *i2caux,
++ struct ddc *ddc);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h b/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
+new file mode 100644
+index 0000000..f7315c6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/bandwidth_calcs.h
+@@ -0,0 +1,463 @@
++/*
++ * Copyright 2015 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
++ *
++ */
++
++/**
++ * Bandwidth and Watermark calculations interface.
++ * (Refer to "DCE11_mode_support.xlsm" from Perforce.)
++ */
++#ifndef __BANDWIDTH_CALCS_H__
++#define __BANDWIDTH_CALCS_H__
++
++#include "bw_fixed.h"
++/*******************************************************************************
++ * There are three types of input into Calculations:
++ * 1. per-DCE static values - these are "hardcoded" properties of the DCEIP
++ * 2. board-level values - these are generally coming from VBIOS parser
++ * 3. mode/configuration values - depending Mode, Scaling number of Displays etc.
++ ******************************************************************************/
++
++enum bw_stereo_mode {
++ mono,
++ side_by_side,
++ top_bottom
++};
++
++enum bw_ul_mode {
++ ul_none,
++ ul_only,
++ ul_blend
++};
++
++enum bw_tiling_mode {
++ linear,
++ tiled
++};
++
++enum bw_panning_and_bezel_adj {
++ none,
++ any_lines
++};
++
++enum bw_underlay_surface_type {
++ yuv_420,
++ yuv_422
++};
++
++struct bw_calcs_input_dceip {
++ struct bw_fixed dmif_request_buffer_size;
++ struct bw_fixed de_tiling_buffer;
++ struct bw_fixed dcfclk_request_generation;
++ struct bw_fixed lines_interleaved_into_lb;
++ struct bw_fixed chunk_width;
++ struct bw_fixed number_of_graphics_pipes;
++ struct bw_fixed number_of_underlay_pipes;
++ bool display_write_back_supported;
++ bool argb_compression_support;
++ struct bw_fixed underlay_vscaler_efficiency6_bit_per_component;
++ struct bw_fixed underlay_vscaler_efficiency8_bit_per_component;
++ struct bw_fixed underlay_vscaler_efficiency10_bit_per_component;
++ struct bw_fixed underlay_vscaler_efficiency12_bit_per_component;
++ struct bw_fixed graphics_vscaler_efficiency6_bit_per_component;
++ struct bw_fixed graphics_vscaler_efficiency8_bit_per_component;
++ struct bw_fixed graphics_vscaler_efficiency10_bit_per_component;
++ struct bw_fixed graphics_vscaler_efficiency12_bit_per_component;
++ struct bw_fixed alpha_vscaler_efficiency;
++ struct bw_fixed max_dmif_buffer_allocated;
++ struct bw_fixed graphics_dmif_size;
++ struct bw_fixed underlay_luma_dmif_size;
++ struct bw_fixed underlay_chroma_dmif_size;
++ bool pre_downscaler_enabled;
++ bool underlay_downscale_prefetch_enabled;
++ struct bw_fixed lb_write_pixels_per_dispclk;
++ struct bw_fixed lb_size_per_component444;
++ bool graphics_lb_nodownscaling_multi_line_prefetching;
++ struct bw_fixed stutter_and_dram_clock_state_change_gated_before_cursor;
++ struct bw_fixed underlay420_luma_lb_size_per_component;
++ struct bw_fixed underlay420_chroma_lb_size_per_component;
++ struct bw_fixed underlay422_lb_size_per_component;
++ struct bw_fixed cursor_chunk_width;
++ struct bw_fixed cursor_dcp_buffer_lines;
++ struct bw_fixed cursor_memory_interface_buffer_pixels;
++ struct bw_fixed underlay_maximum_width_efficient_for_tiling;
++ struct bw_fixed underlay_maximum_height_efficient_for_tiling;
++ struct bw_fixed peak_pte_request_to_eviction_ratio_limiting_multiple_displays_or_single_rotated_display;
++ struct bw_fixed peak_pte_request_to_eviction_ratio_limiting_single_display_no_rotation;
++ struct bw_fixed minimum_outstanding_pte_request_limit;
++ struct bw_fixed maximum_total_outstanding_pte_requests_allowed_by_saw;
++ bool limit_excessive_outstanding_dmif_requests;
++ struct bw_fixed linear_mode_line_request_alternation_slice;
++ struct bw_fixed scatter_gather_lines_of_pte_prefetching_in_linear_mode;
++ struct bw_fixed display_write_back420_luma_mcifwr_buffer_size;
++ struct bw_fixed display_write_back420_chroma_mcifwr_buffer_size;
++ struct bw_fixed request_efficiency;
++ struct bw_fixed dispclk_per_request;
++ struct bw_fixed dispclk_ramping_factor;
++ struct bw_fixed display_pipe_throughput_factor;
++ struct bw_fixed scatter_gather_pte_request_rows_in_tiling_mode;
++ struct bw_fixed mcifwr_all_surfaces_burst_time; /* 0 todo: this is a bug*/
++};
++
++struct bw_calcs_input_vbios {
++ struct bw_fixed dram_channel_width_in_bits;
++ struct bw_fixed number_of_dram_channels;
++ struct bw_fixed number_of_dram_banks;
++ struct bw_fixed high_yclk;
++ struct bw_fixed high_dram_bandwidth_per_channel;
++ struct bw_fixed low_yclk;
++ struct bw_fixed low_dram_bandwidth_per_channel;
++ struct bw_fixed low_sclk;
++ struct bw_fixed mid_sclk;
++ struct bw_fixed high_sclk;
++ struct bw_fixed low_voltage_max_dispclk;
++ struct bw_fixed mid_voltage_max_dispclk;
++ struct bw_fixed high_voltage_max_dispclk;
++ struct bw_fixed data_return_bus_width;
++ struct bw_fixed trc;
++ struct bw_fixed dmifmc_urgent_latency;
++ struct bw_fixed stutter_self_refresh_exit_latency;
++ struct bw_fixed nbp_state_change_latency;
++ struct bw_fixed mcifwrmc_urgent_latency;
++ bool scatter_gather_enable;
++ struct bw_fixed down_spread_percentage;
++ struct bw_fixed cursor_width;
++ struct bw_fixed average_compression_rate;
++ struct bw_fixed number_of_request_slots_gmc_reserves_for_dmif_per_channel;
++ struct bw_fixed blackout_duration;
++ struct bw_fixed maximum_blackout_recovery_time;
++};
++
++struct bw_calcs_input_mode_data_internal {
++ /* data for all displays */
++ uint32_t number_of_displays;
++ struct bw_fixed graphics_rotation_angle;
++ struct bw_fixed underlay_rotation_angle;
++ bool display_synchronization_enabled;
++ enum bw_underlay_surface_type underlay_surface_type;
++ enum bw_panning_and_bezel_adj panning_and_bezel_adjustment;
++ enum bw_tiling_mode graphics_tiling_mode;
++ bool graphics_interlace_mode;
++ struct bw_fixed graphics_bytes_per_pixel;
++ struct bw_fixed graphics_htaps;
++ struct bw_fixed graphics_vtaps;
++ struct bw_fixed graphics_lb_bpc;
++ struct bw_fixed underlay_lb_bpc;
++ enum bw_tiling_mode underlay_tiling_mode;
++ struct bw_fixed underlay_htaps;
++ struct bw_fixed underlay_vtaps;
++ struct bw_fixed underlay_src_width;
++ struct bw_fixed underlay_src_height;
++ struct bw_fixed underlay_pitch_in_pixels;
++ enum bw_stereo_mode underlay_stereo_mode;
++ bool d0_fbc_enable;
++ bool d0_lpt_enable;
++ struct bw_fixed d0_htotal;
++ struct bw_fixed d0_pixel_rate;
++ struct bw_fixed d0_graphics_src_width;
++ struct bw_fixed d0_graphics_src_height;
++ struct bw_fixed d0_graphics_scale_ratio;
++ enum bw_stereo_mode d0_graphics_stereo_mode;
++ enum bw_ul_mode d0_underlay_mode;
++ struct bw_fixed d0_underlay_scale_ratio;
++ struct bw_fixed d1_htotal;
++ struct bw_fixed d1_pixel_rate;
++ struct bw_fixed d1_graphics_src_width;
++ struct bw_fixed d1_graphics_src_height;
++ struct bw_fixed d1_graphics_scale_ratio;
++ enum bw_stereo_mode d1_graphics_stereo_mode;
++ bool d1_display_write_back_dwb_enable;
++ enum bw_ul_mode d1_underlay_mode;
++ struct bw_fixed d1_underlay_scale_ratio;
++ struct bw_fixed d2_htotal;
++ struct bw_fixed d2_pixel_rate;
++ struct bw_fixed d2_graphics_src_width;
++ struct bw_fixed d2_graphics_src_height;
++ struct bw_fixed d2_graphics_scale_ratio;
++ enum bw_stereo_mode d2_graphics_stereo_mode;
++};
++
++struct bw_calcs_input_single_display {
++ uint32_t graphics_rotation_angle;
++ uint32_t underlay_rotation_angle;
++ enum bw_underlay_surface_type underlay_surface_type;
++ enum bw_panning_and_bezel_adj panning_and_bezel_adjustment;
++ uint32_t graphics_bytes_per_pixel;
++ bool graphics_interlace_mode;
++ enum bw_tiling_mode graphics_tiling_mode;
++ uint32_t graphics_h_taps;
++ uint32_t graphics_v_taps;
++ uint32_t graphics_lb_bpc;
++ uint32_t underlay_lb_bpc;
++ enum bw_tiling_mode underlay_tiling_mode;
++ uint32_t underlay_h_taps;
++ uint32_t underlay_v_taps;
++ uint32_t underlay_src_width;
++ uint32_t underlay_src_height;
++ uint32_t underlay_pitch_in_pixels;
++ enum bw_stereo_mode underlay_stereo_mode;
++ bool fbc_enable;
++ bool lpt_enable;
++ uint32_t h_total;
++ struct bw_fixed pixel_rate;
++ uint32_t graphics_src_width;
++ uint32_t graphics_src_height;
++ struct bw_fixed graphics_scale_ratio;
++ enum bw_stereo_mode graphics_stereo_mode;
++ enum bw_ul_mode underlay_mode;
++};
++
++#define BW_CALCS_MAX_NUM_DISPLAYS 3
++
++struct bw_calcs_input_mode_data {
++ /* data for all displays */
++ uint8_t number_of_displays;
++ bool display_synchronization_enabled;
++
++ struct bw_calcs_input_single_display
++ displays_data[BW_CALCS_MAX_NUM_DISPLAYS];
++};
++
++/*******************************************************************************
++ * Output data structure(s).
++ ******************************************************************************/
++#define maximum_number_of_surfaces 12
++struct bw_results_internal {
++ bool cpup_state_change_enable;
++ bool cpuc_state_change_enable;
++ bool nbp_state_change_enable;
++ bool stutter_mode_enable;
++ struct bw_fixed number_of_underlay_surfaces;
++ struct bw_fixed src_width_after_surface_type;
++ struct bw_fixed src_height_after_surface_type;
++ struct bw_fixed hsr_after_surface_type;
++ struct bw_fixed vsr_after_surface_type;
++ struct bw_fixed src_width_after_rotation;
++ struct bw_fixed src_height_after_rotation;
++ struct bw_fixed hsr_after_rotation;
++ struct bw_fixed vsr_after_rotation;
++ struct bw_fixed source_height_pixels;
++ struct bw_fixed hsr_after_stereo;
++ struct bw_fixed vsr_after_stereo;
++ struct bw_fixed source_width_in_lb;
++ struct bw_fixed lb_line_pitch;
++ struct bw_fixed underlay_maximum_source_efficient_for_tiling;
++ struct bw_fixed num_lines_at_frame_start;
++ struct bw_fixed min_dmif_size_in_time;
++ struct bw_fixed min_mcifwr_size_in_time;
++ struct bw_fixed total_requests_for_dmif_size;
++ struct bw_fixed peak_pte_request_to_eviction_ratio_limiting;
++ struct bw_fixed useful_pte_per_pte_request;
++ struct bw_fixed scatter_gather_pte_request_rows;
++ struct bw_fixed scatter_gather_row_height;
++ struct bw_fixed scatter_gather_pte_requests_in_vblank;
++ struct bw_fixed inefficient_linear_pitch_in_bytes;
++ struct bw_fixed inefficient_underlay_pitch_in_pixels;
++ struct bw_fixed minimum_underlay_pitch_padding_recommended_for_efficiency;
++ struct bw_fixed cursor_total_data;
++ struct bw_fixed cursor_total_request_groups;
++ struct bw_fixed scatter_gather_total_pte_requests;
++ struct bw_fixed scatter_gather_total_pte_request_groups;
++ struct bw_fixed tile_width_in_pixels;
++ struct bw_fixed dmif_total_number_of_data_request_page_close_open;
++ struct bw_fixed mcifwr_total_number_of_data_request_page_close_open;
++ struct bw_fixed bytes_per_page_close_open;
++ struct bw_fixed mcifwr_total_page_close_open_time;
++ struct bw_fixed total_requests_for_adjusted_dmif_size;
++ struct bw_fixed total_dmifmc_urgent_trips;
++ struct bw_fixed total_dmifmc_urgent_latency;
++ struct bw_fixed total_display_reads_required_data;
++ struct bw_fixed total_display_reads_required_dram_access_data;
++ struct bw_fixed total_display_writes_required_data;
++ struct bw_fixed total_display_writes_required_dram_access_data;
++ struct bw_fixed display_reads_required_data;
++ struct bw_fixed display_reads_required_dram_access_data;
++ struct bw_fixed dmif_total_page_close_open_time;
++ struct bw_fixed min_cursor_memory_interface_buffer_size_in_time;
++ struct bw_fixed min_read_buffer_size_in_time;
++ struct bw_fixed display_reads_time_for_data_transfer;
++ struct bw_fixed display_writes_time_for_data_transfer;
++ struct bw_fixed dmif_required_dram_bandwidth;
++ struct bw_fixed mcifwr_required_dram_bandwidth;
++ struct bw_fixed required_dmifmc_urgent_latency_for_page_close_open;
++ struct bw_fixed required_mcifmcwr_urgent_latency;
++ struct bw_fixed required_dram_bandwidth_gbyte_per_second;
++ struct bw_fixed dram_bandwidth;
++ struct bw_fixed dmif_required_sclk;
++ struct bw_fixed mcifwr_required_sclk;
++ struct bw_fixed required_sclk;
++ struct bw_fixed downspread_factor;
++ struct bw_fixed v_scaler_efficiency;
++ struct bw_fixed scaler_limits_factor;
++ struct bw_fixed display_pipe_pixel_throughput;
++ struct bw_fixed total_dispclk_required_with_ramping;
++ struct bw_fixed total_dispclk_required_without_ramping;
++ struct bw_fixed total_read_request_bandwidth;
++ struct bw_fixed total_write_request_bandwidth;
++ struct bw_fixed dispclk_required_for_total_read_request_bandwidth;
++ struct bw_fixed total_dispclk_required_with_ramping_with_request_bandwidth;
++ struct bw_fixed total_dispclk_required_without_ramping_with_request_bandwidth;
++ struct bw_fixed dispclk;
++ struct bw_fixed blackout_recovery_time;
++ struct bw_fixed min_pixels_per_data_fifo_entry;
++ struct bw_fixed sclk_deep_sleep;
++ struct bw_fixed chunk_request_time;
++ struct bw_fixed cursor_request_time;
++ struct bw_fixed line_source_pixels_transfer_time;
++ struct bw_fixed dmifdram_access_efficiency;
++ struct bw_fixed mcifwrdram_access_efficiency;
++ struct bw_fixed total_average_bandwidth_no_compression;
++ struct bw_fixed total_average_bandwidth;
++ struct bw_fixed total_stutter_cycle_duration;
++ struct bw_fixed stutter_burst_time;
++ struct bw_fixed time_in_self_refresh;
++ struct bw_fixed stutter_efficiency;
++ struct bw_fixed worst_number_of_trips_to_memory;
++ struct bw_fixed immediate_flip_time;
++ struct bw_fixed latency_for_non_dmif_clients;
++ struct bw_fixed latency_for_non_mcifwr_clients;
++ struct bw_fixed dmifmc_urgent_latency_supported_in_high_sclk_and_yclk;
++ struct bw_fixed nbp_state_dram_speed_change_margin;
++ struct bw_fixed display_reads_time_for_data_transfer_and_urgent_latency;
++ bool use_alpha[maximum_number_of_surfaces];
++ bool orthogonal_rotation[maximum_number_of_surfaces];
++ bool enable[maximum_number_of_surfaces];
++ bool access_one_channel_only[maximum_number_of_surfaces];
++ bool scatter_gather_enable_for_pipe[maximum_number_of_surfaces];
++ bool interlace_mode[maximum_number_of_surfaces];
++ struct bw_fixed bytes_per_pixel[maximum_number_of_surfaces];
++ struct bw_fixed h_total[maximum_number_of_surfaces];
++ struct bw_fixed pixel_rate[maximum_number_of_surfaces];
++ struct bw_fixed src_width[maximum_number_of_surfaces];
++ struct bw_fixed pitch_in_pixels[maximum_number_of_surfaces];
++ struct bw_fixed pitch_in_pixels_after_surface_type[maximum_number_of_surfaces];
++ struct bw_fixed src_height[maximum_number_of_surfaces];
++ struct bw_fixed scale_ratio[maximum_number_of_surfaces];
++ struct bw_fixed h_taps[maximum_number_of_surfaces];
++ struct bw_fixed v_taps[maximum_number_of_surfaces];
++ struct bw_fixed rotation_angle[maximum_number_of_surfaces];
++ struct bw_fixed lb_bpc[maximum_number_of_surfaces];
++ struct bw_fixed compression_rate[maximum_number_of_surfaces];
++ struct bw_fixed hsr[maximum_number_of_surfaces];
++ struct bw_fixed vsr[maximum_number_of_surfaces];
++ struct bw_fixed source_width_rounded_up_to_chunks[maximum_number_of_surfaces];
++ struct bw_fixed source_width_pixels[maximum_number_of_surfaces];
++ struct bw_fixed source_height_rounded_up_to_chunks[maximum_number_of_surfaces];
++ struct bw_fixed display_bandwidth[maximum_number_of_surfaces];
++ struct bw_fixed request_bandwidth[maximum_number_of_surfaces];
++ struct bw_fixed bytes_per_request[maximum_number_of_surfaces];
++ struct bw_fixed useful_bytes_per_request[maximum_number_of_surfaces];
++ struct bw_fixed lines_interleaved_in_mem_access[maximum_number_of_surfaces];
++ struct bw_fixed latency_hiding_lines[maximum_number_of_surfaces];
++ struct bw_fixed lb_partitions[maximum_number_of_surfaces];
++ struct bw_fixed lb_partitions_max[maximum_number_of_surfaces];
++ struct bw_fixed dispclk_required_with_ramping[maximum_number_of_surfaces];
++ struct bw_fixed dispclk_required_without_ramping[maximum_number_of_surfaces];
++ struct bw_fixed data_buffer_size[maximum_number_of_surfaces];
++ struct bw_fixed outstanding_chunk_request_limit[maximum_number_of_surfaces];
++ struct bw_fixed urgent_watermark[maximum_number_of_surfaces];
++ struct bw_fixed stutter_exit_watermark[maximum_number_of_surfaces];
++ struct bw_fixed nbp_state_change_watermark[maximum_number_of_surfaces];
++ struct bw_fixed v_filter_init[maximum_number_of_surfaces];
++ struct bw_fixed stutter_cycle_duration[maximum_number_of_surfaces];
++ struct bw_fixed average_bandwidth[maximum_number_of_surfaces];
++ struct bw_fixed average_bandwidth_no_compression[maximum_number_of_surfaces];
++ struct bw_fixed scatter_gather_pte_request_limit[maximum_number_of_surfaces];
++ struct bw_fixed lb_size_per_component[maximum_number_of_surfaces];
++ struct bw_fixed memory_chunk_size_in_bytes[maximum_number_of_surfaces];
++ struct bw_fixed pipe_chunk_size_in_bytes[maximum_number_of_surfaces];
++ struct bw_fixed number_of_trips_to_memory_for_getting_apte_row[maximum_number_of_surfaces];
++ struct bw_fixed adjusted_data_buffer_size[maximum_number_of_surfaces];
++ struct bw_fixed adjusted_data_buffer_size_in_memory[maximum_number_of_surfaces];
++ struct bw_fixed pixels_per_data_fifo_entry[maximum_number_of_surfaces];
++ struct bw_fixed scatter_gather_pte_requests_in_row[maximum_number_of_surfaces];
++ struct bw_fixed pte_request_per_chunk[maximum_number_of_surfaces];
++ struct bw_fixed scatter_gather_page_width[maximum_number_of_surfaces];
++ struct bw_fixed scatter_gather_page_height[maximum_number_of_surfaces];
++ struct bw_fixed lb_lines_in_per_line_out_in_beginning_of_frame[maximum_number_of_surfaces];
++ struct bw_fixed lb_lines_in_per_line_out_in_middle_of_frame[maximum_number_of_surfaces];
++ struct bw_fixed cursor_width_pixels[maximum_number_of_surfaces];
++ struct bw_fixed line_buffer_prefetch[maximum_number_of_surfaces];
++ struct bw_fixed minimum_latency_hiding[maximum_number_of_surfaces];
++ struct bw_fixed maximum_latency_hiding[maximum_number_of_surfaces];
++ struct bw_fixed minimum_latency_hiding_with_cursor[maximum_number_of_surfaces];
++ struct bw_fixed maximum_latency_hiding_with_cursor[maximum_number_of_surfaces];
++ struct bw_fixed src_pixels_for_first_output_pixel[maximum_number_of_surfaces];
++ struct bw_fixed src_pixels_for_last_output_pixel[maximum_number_of_surfaces];
++ struct bw_fixed src_data_for_first_output_pixel[maximum_number_of_surfaces];
++ struct bw_fixed src_data_for_last_output_pixel[maximum_number_of_surfaces];
++ struct bw_fixed active_time[maximum_number_of_surfaces];
++ struct bw_fixed horizontal_blank_and_chunk_granularity_factor[maximum_number_of_surfaces];
++ struct bw_fixed cursor_latency_hiding[maximum_number_of_surfaces];
++ struct bw_fixed dmif_burst_time[3][3];
++ struct bw_fixed mcifwr_burst_time[3][3];
++ struct bw_fixed line_source_transfer_time[maximum_number_of_surfaces][3][3];
++ struct bw_fixed dram_speed_change_margin[3][3];
++ struct bw_fixed dispclk_required_for_dram_speed_change[3][3];
++ struct bw_fixed blackout_duration_margin[3][3];
++ struct bw_fixed dispclk_required_for_blackout_duration[3][3];
++ struct bw_fixed dispclk_required_for_blackout_recovery[3][3];
++ struct bw_fixed dmif_required_sclk_for_urgent_latency[6];
++};
++
++struct bw_watermarks {
++ uint32_t a_mark;
++ uint32_t b_mark;
++};
++
++struct bw_calcs_output {
++ bool cpuc_state_change_enable;
++ bool cpup_state_change_enable;
++ bool stutter_mode_enable;
++ bool nbp_state_change_enable;
++ struct bw_watermarks urgent_watermark[4];
++ struct bw_watermarks stutter_exit_watermark[4];
++ struct bw_watermarks nbp_state_change_watermark[4];
++ uint32_t required_sclk;
++ uint32_t dispclk;
++};
++
++
++/**
++ * Initialize structures with data which will NOT change at runtime.
++ */
++void bw_calcs_init(
++ struct bw_calcs_input_dceip *bw_dceip,
++ struct bw_calcs_input_vbios *bw_vbios);
++
++/**
++ * Return:
++ * true - Display(s) configuration supported.
++ * In this case 'calcs_output' contains data for HW programming
++ * false - Display(s) configuration not supported (not enough bandwidth).
++ */
++bool bw_calcs(
++ struct dc_context *ctx,
++ const struct bw_calcs_input_dceip *dceip,
++ const struct bw_calcs_input_vbios *vbios,
++ const struct bw_calcs_input_mode_data *mode_data,
++ struct bw_calcs_output *calcs_output);
++
++
++#endif /* __BANDWIDTH_CALCS_H__ */
++
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/bw_fixed.h b/drivers/gpu/drm/amd/dal/dc/inc/bw_fixed.h
+new file mode 100644
+index 0000000..f9e267b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/bw_fixed.h
+@@ -0,0 +1,60 @@
++/*
++ * Copyright 2015 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 BW_FIXED_H_
++#define BW_FIXED_H_
++
++struct bw_fixed {
++ signed long long value;
++};
++
++struct bw_fixed bw_min3(struct bw_fixed v1, struct bw_fixed v2, struct bw_fixed v3);
++
++struct bw_fixed bw_max3(struct bw_fixed v1, struct bw_fixed v2, struct bw_fixed v3);
++
++struct bw_fixed int_to_fixed(long long value);
++
++struct bw_fixed frc_to_fixed(long long num, long long denum);
++
++struct bw_fixed fixed31_32_to_bw_fixed(long long raw);
++
++struct bw_fixed add(const struct bw_fixed arg1, const struct bw_fixed arg2);
++struct bw_fixed sub(const struct bw_fixed arg1, const struct bw_fixed arg2);
++struct bw_fixed mul(const struct bw_fixed arg1, const struct bw_fixed arg2);
++struct bw_fixed bw_div(const struct bw_fixed arg1, const struct bw_fixed arg2);
++
++struct bw_fixed bw_min(const struct bw_fixed arg1, const struct bw_fixed arg2);
++struct bw_fixed bw_max(const struct bw_fixed arg1, const struct bw_fixed arg2);
++struct bw_fixed bw_floor(const struct bw_fixed arg, const struct bw_fixed significance);
++struct bw_fixed bw_ceil(const struct bw_fixed arg, const struct bw_fixed significance);
++
++bool equ(const struct bw_fixed arg1, const struct bw_fixed arg2);
++bool neq(const struct bw_fixed arg1, const struct bw_fixed arg2);
++bool leq(const struct bw_fixed arg1, const struct bw_fixed arg2);
++bool geq(const struct bw_fixed arg1, const struct bw_fixed arg2);
++bool ltn(const struct bw_fixed arg1, const struct bw_fixed arg2);
++bool gtn(const struct bw_fixed arg1, const struct bw_fixed arg2);
++
++#endif //BW_FIXED_H_
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/compressor.h b/drivers/gpu/drm/amd/dal/dc/inc/compressor.h
+new file mode 100644
+index 0000000..4992ffd
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/compressor.h
+@@ -0,0 +1,140 @@
++/*
++ * 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_COMPRESSOR_H__
++#define __DAL_COMPRESSOR_H__
++
++#include "include/grph_object_id.h"
++
++enum fbc_compress_ratio {
++ FBC_COMPRESS_RATIO_INVALID = 0,
++ FBC_COMPRESS_RATIO_1TO1 = 1,
++ FBC_COMPRESS_RATIO_2TO1 = 2,
++ FBC_COMPRESS_RATIO_4TO1 = 4,
++ FBC_COMPRESS_RATIO_8TO1 = 8,
++};
++
++union fbc_physical_address {
++ struct {
++ uint32_t low_part;
++ int32_t high_part;
++ } addr;
++};
++
++struct compr_addr_and_pitch_params {
++ uint32_t inst;
++ uint32_t source_view_width;
++ uint32_t source_view_height;
++};
++
++struct fbc_lpt_config {
++ uint32_t mem_channels_num;
++ uint32_t banks_num;
++ uint32_t chan_interleave_size;
++ uint32_t row_size;
++};
++
++struct fbc_input_info {
++ bool dynamic_fbc_buffer_alloc;
++ uint32_t source_view_width;
++ uint32_t source_view_height;
++ uint32_t active_targets_num;
++ struct fbc_lpt_config lpt_config;
++};
++
++struct fbc_requested_compressed_size {
++ uint32_t preferred_size;
++ uint32_t preferred_size_alignment;
++ uint32_t min_size;
++ uint32_t min_size_alignment;
++ union {
++ struct {
++ /*Above preferred_size must be allocated in FB pool */
++ uint32_t PREFERRED_MUST_BE_FRAME_BUFFER_POOL:1;
++ /*Above min_size must be allocated in FB pool */
++ uint32_t MIN_MUST_BE_FRAME_BUFFER_POOL:1;
++ } flags;
++ uint32_t bits;
++ };
++};
++
++struct fbc_compressed_surface_info {
++ union fbc_physical_address compressed_surface_address;
++ uint32_t allocated_size;
++ union {
++ struct {
++ uint32_t FB_POOL:1; /*Allocated in FB Pool */
++ uint32_t DYNAMIC_ALLOC:1; /*Dynamic allocation */
++ } allocation_flags;
++ uint32_t bits;
++ };
++};
++
++enum fbc_hw_max_resolution_supported {
++ FBC_MAX_X = 3840,
++ FBC_MAX_Y = 2400
++};
++
++struct fbc_max_resolution_supported {
++ uint32_t source_view_width;
++ uint32_t source_view_height;
++};
++
++struct compressor {
++ struct dc_context *ctx;
++ uint32_t attached_inst;
++ bool is_enabled;
++
++ union {
++ uint32_t raw;
++ struct {
++ uint32_t FBC_SUPPORT:1;
++ uint32_t FB_POOL:1;
++ uint32_t DYNAMIC_ALLOC:1;
++ uint32_t LPT_SUPPORT:1;
++ uint32_t LPT_MC_CONFIG:1;
++ uint32_t DUMMY_BACKEND:1;
++ uint32_t CLK_GATING_DISABLED:1;
++
++ } bits;
++ } options;
++
++ union fbc_physical_address compr_surface_address;
++
++ uint32_t embedded_panel_h_size;
++ uint32_t embedded_panel_v_size;
++ uint32_t memory_bus_width;
++ uint32_t banks_num;
++ uint32_t raw_size;
++ uint32_t channel_interleave_size;
++ uint32_t dram_channels_num;
++
++ uint32_t allocated_size;
++ uint32_t preferred_requested_size;
++ uint32_t lpt_channels_num;
++ enum fbc_compress_ratio min_compress_ratio;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/core_dc.h b/drivers/gpu/drm/amd/dal/dc/inc/core_dc.h
+new file mode 100644
+index 0000000..dc246e8
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/core_dc.h
+@@ -0,0 +1,39 @@
++/*
++ * core_dc.h
++ *
++ * Created on: Nov 13, 2015
++ * Author: yonsun
++ */
++
++#ifndef __CORE_DC_H__
++#define __CORE_DC_H__
++
++#include "core_types.h"
++#include "hw_sequencer.h"
++
++
++struct dc {
++ struct dc_context *ctx;
++
++ /** link-related data - begin **/
++ uint8_t link_count;
++ struct core_link **links;
++ /** link-related data - end **/
++
++ /* TODO: determine max number of targets*/
++ struct validate_context current_context;
++ struct resource_pool res_pool;
++
++ /*Power State*/
++ enum dc_video_power_state previous_power_state;
++ enum dc_video_power_state current_power_state;
++
++ /* Inputs into BW and WM calculations. */
++ struct bw_calcs_input_dceip bw_dceip;
++ struct bw_calcs_input_vbios bw_vbios;
++
++ /* HW functions */
++ struct hw_sequencer_funcs hwss;
++};
++
++#endif /* __CORE_DC_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/core_status.h b/drivers/gpu/drm/amd/dal/dc/inc/core_status.h
+new file mode 100644
+index 0000000..9682cf8
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/core_status.h
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2015 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 _CORE_STATUS_H_
++#define _CORE_STATUS_H_
++
++enum dc_status {
++ DC_OK = 1,
++
++ DC_NO_CONTROLLER_RESOURCE,
++ DC_NO_STREAM_ENG_RESOURCE,
++ DC_NO_STREAM_AUDIO_RESOURCE,
++ DC_NO_CLOCK_SOURCE_RESOURCE,
++ DC_FAIL_CONTROLLER_VALIDATE,
++ DC_FAIL_ENC_VALIDATE,
++ DC_FAIL_ATTACH_SURFACES,
++ DC_NO_DP_LINK_BANDWIDTH,
++ DC_EXCEED_DONGLE_MAX_CLK,
++ DC_FAIL_BANDWIDTH_VALIDATE, /* BW and Watermark validation */
++
++ DC_ERROR_UNEXPECTED = -1
++};
++
++#endif /* _CORE_STATUS_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/core_types.h b/drivers/gpu/drm/amd/dal/dc/inc/core_types.h
+new file mode 100644
+index 0000000..22ab6cb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/core_types.h
+@@ -0,0 +1,308 @@
++/*
++ * Copyright 2015 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 _CORE_TYPES_H_
++#define _CORE_TYPES_H_
++
++#include "dc.h"
++#include "bandwidth_calcs.h"
++#include "ddc_service_types.h"
++
++struct core_stream;
++/********* core_target *************/
++
++#define CONST_DC_TARGET_TO_CORE(dc_target) \
++ container_of(dc_target, const struct core_target, public)
++#define DC_TARGET_TO_CORE(dc_target) \
++ container_of(dc_target, struct core_target, public)
++
++#define MAX_PIPES 6
++#define MAX_STREAMS 6
++#define MAX_CLOCK_SOURCES 4
++
++struct core_target {
++ struct dc_target public;
++ struct dc_target_status status;
++
++ struct core_stream *streams[MAX_STREAMS];
++ uint8_t stream_count;
++ struct dc_context *ctx;
++};
++
++/********* core_surface **********/
++#define DC_SURFACE_TO_CORE(dc_surface) \
++ container_of(dc_surface, struct core_surface, public)
++
++struct core_surface {
++ struct dc_surface public;
++ struct dc_surface_status status;
++ struct dc_context *ctx;
++};
++
++void enable_surface_flip_reporting(struct dc_surface *dc_surface,
++ uint32_t controller_id);
++
++/********* core_stream ************/
++#include "grph_object_id.h"
++#include "encoder_interface.h"
++#include "clock_source_interface.h"
++#include "audio_interface.h"
++
++#define DC_STREAM_TO_CORE(dc_stream) container_of( \
++ dc_stream, struct core_stream, public)
++
++#define PIXEL_CLOCK 27030
++
++struct core_stream {
++ struct dc_stream public;
++
++ /* field internal to DC */
++ const struct core_sink *sink;
++
++ struct clock_source *clock_source;
++
++ struct mem_input *mi;
++ struct input_pixel_processor *ipp;
++ struct transform *xfm;
++ struct output_pixel_processor *opp;
++ struct timing_generator *tg;
++ struct stream_encoder *stream_enc;
++ struct display_clock *dis_clk;
++
++ struct overscan_info overscan;
++ struct scaling_ratios ratios;
++ struct rect viewport;
++ struct scaling_taps taps;
++ enum pixel_format format;
++
++ uint8_t controller_idx;
++
++ struct audio *audio;
++
++ enum signal_type signal;
++
++ /* TODO: move these members into appropriate places (work in progress)*/
++ /* timing validation (HDMI only) */
++ uint32_t max_tmds_clk_from_edid_in_mhz;
++ /* maximum supported deep color depth for HDMI */
++ enum dc_color_depth max_hdmi_deep_color;
++ /* maximum supported pixel clock for HDMI */
++ uint32_t max_hdmi_pixel_clock;
++ /* end of TODO */
++
++ /*TODO: AUTO merge if possible*/
++ struct pixel_clk_params pix_clk_params;
++ struct pll_settings pll_settings;
++
++ /*fmt*/
++ /*TODO: AUTO new codepath in apply_context to hw to
++ * generate these bw unrelated/no fail params*/
++ struct bit_depth_reduction_params fmt_bit_depth;
++ struct clamping_and_pixel_encoding_params clamping;
++ struct hw_info_frame info_frame;
++ struct encoder_info_frame encoder_info_frame;
++
++ struct audio_output audio_output;
++ struct dc_context *ctx;
++};
++
++
++/************ core_sink *****************/
++
++#define DC_SINK_TO_CORE(dc_sink) \
++ container_of(dc_sink, struct core_sink, public)
++
++struct core_sink {
++ /** The public, read-only (for DM) area of sink. **/
++ struct dc_sink public;
++ /** End-of-public area. **/
++
++ /** The 'protected' area - read/write access, for use only inside DC **/
++ /* not used for now */
++ struct core_link *link;
++ struct dc_context *ctx;
++ uint32_t dongle_max_pix_clk;
++ bool converter_disable_audio;
++};
++
++/************ link *****************/
++#define DC_LINK_TO_CORE(dc_link) container_of(dc_link, struct core_link, public)
++
++struct link_init_data {
++ const struct dc *dc;
++ struct dc_context *ctx; /* TODO: remove 'dal' when DC is complete. */
++ uint32_t connector_index; /* this will be mapped to the HPD pins */
++ uint32_t link_index; /* this is mapped to DAL display_index
++ TODO: remove it when DC is complete. */
++ struct adapter_service *adapter_srv;
++};
++
++struct link_caps {
++ /* support for Spread Spectrum(SS) */
++ bool ss_supported;
++ /* DP link settings (laneCount, linkRate, Spread) */
++ uint32_t lane_count;
++ uint32_t rate;
++ uint32_t spread;
++ enum dpcd_revision dpcd_revision;
++};
++
++struct dpcd_caps {
++ union dpcd_rev dpcd_rev;
++ union max_lane_count max_ln_count;
++
++ /* dongle type (DP converter, CV smart dongle) */
++ enum display_dongle_type dongle_type;
++ /* Dongle's downstream count. */
++ union sink_count sink_count;
++ /* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
++ indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
++ bool is_dp_hdmi_s3d_converter;
++
++ bool allow_invalid_MSA_timing_param;
++ bool panel_mode_edp;
++ uint32_t sink_dev_id;
++ uint32_t branch_dev_id;
++ int8_t branch_dev_name[6];
++};
++
++union dp_wa {
++ struct {
++ /* keep DP receiver powered up on DisplayOutput */
++ uint32_t KEEP_RECEIVER_POWERED:1;
++
++ /* TODO: may add other member in.*/
++ } bits;
++ uint32_t raw;
++};
++
++struct core_link {
++ struct dc_link public;
++ const struct dc *dc;
++
++ struct dc_context *ctx; /* TODO: AUTO remove 'dal' when DC is complete*/
++
++ uint8_t connector_index; /* this will be mapped to the HPD pins */
++ uint8_t link_index; /* this is mapped to DAL display_index
++ TODO: #flip remove it as soon as possible. */
++
++ struct adapter_service *adapter_srv;
++ struct connector *connector;
++ struct link_encoder *link_enc;
++ struct ddc_service *ddc;
++ struct graphics_object_id link_id;
++ /* caps is the same as reported_link_cap. link_traing use
++ * reported_link_cap. Will clean up. TODO */
++ struct link_settings reported_link_cap;
++ struct link_settings verified_link_cap;
++ struct link_settings max_link_setting;
++ struct link_settings cur_link_settings;
++ struct lane_settings ln_setting;
++ struct dpcd_caps dpcd_caps;
++ unsigned int dpcd_sink_count;
++
++ enum edp_revision edp_revision;
++ union dp_wa dp_wa;
++};
++
++#define DC_LINK_TO_LINK(dc_link) container_of(dc_link, struct core_link, public)
++
++struct core_link *link_create(const struct link_init_data *init_params);
++void link_destroy(struct core_link **link);
++enum dc_status core_link_enable(struct core_stream *stream);
++
++enum dc_status core_link_disable(struct core_stream *stream);
++
++enum dc_status dc_link_validate_mode_timing(
++ const struct core_sink *sink,
++ struct core_link *link,
++ const struct dc_crtc_timing *timing);
++
++void core_link_resume(struct core_link *link);
++
++/********** DAL Core*********************/
++#include "display_clock_interface.h"
++
++struct resource_pool {
++ struct scaler_filter * scaler_filter;
++
++ struct mem_input *mis[MAX_PIPES];
++ struct input_pixel_processor *ipps[MAX_PIPES];
++ struct transform *transforms[MAX_PIPES];
++ struct output_pixel_processor *opps[MAX_PIPES];
++ struct timing_generator *timing_generators[MAX_STREAMS];
++ struct stream_encoder *stream_enc[MAX_STREAMS];
++
++ uint8_t controller_count;
++ uint8_t stream_enc_count;
++
++ union supported_stream_engines stream_engines;
++
++ struct clock_source *clock_sources[MAX_CLOCK_SOURCES];
++ uint8_t clk_src_count;
++
++ struct audio *audios[MAX_STREAMS];
++ uint8_t audio_count;
++
++ struct display_clock *display_clock;
++ struct adapter_service *adapter_srv;
++ struct irq_service *irqs;
++};
++
++struct controller_ctx {
++ struct core_surface *surface;
++ struct core_stream *stream;
++ struct flags {
++ bool unchanged;
++ bool timing_changed;
++ } flags;
++};
++
++struct resource_context {
++ struct resource_pool pool;
++ struct controller_ctx controller_ctx[MAX_PIPES];
++ union supported_stream_engines used_stream_engines;
++ bool is_stream_enc_acquired[MAX_STREAMS];
++ bool is_audio_acquired[MAX_STREAMS];
++ uint8_t clock_source_ref_count[MAX_CLOCK_SOURCES];
++ };
++
++struct target_flags {
++ bool unchanged;
++};
++struct validate_context {
++ struct core_target *targets[MAX_PIPES];
++ struct target_flags target_flags[MAX_PIPES];
++ uint8_t target_count;
++
++ struct resource_context res_ctx;
++
++ struct bw_calcs_input_mode_data bw_mode_data;
++ /* The output from BW and WM calculations. */
++ struct bw_calcs_output bw_results;
++};
++
++
++#endif /* _CORE_TYPES_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/dal/dc/inc/dc_link_dp.h
+new file mode 100644
+index 0000000..e3e4778
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/dc_link_dp.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright 2015 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_LINK_DP_H__
++#define __DC_LINK_DP_H__
++
++bool dp_hbr_verify_link_cap(
++ struct core_link *link,
++ struct link_settings *known_limit_link_setting);
++
++bool dp_validate_mode_timing(
++ struct core_link *link,
++ const struct dc_crtc_timing *timing);
++
++void decide_link_settings(
++ struct core_stream *stream,
++ struct link_settings *link_setting);
++
++bool perform_link_training(
++ struct core_link *link,
++ const struct link_settings *link_setting,
++ bool skip_video_pattern);
++
++/*dp mst functions*/
++bool is_mst_supported(struct core_link *link);
++
++void detect_dp_sink_caps(struct core_link *link);
++
++#endif /* __DC_LINK_DP_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/hw_sequencer.h b/drivers/gpu/drm/amd/dal/dc/inc/hw_sequencer.h
+new file mode 100644
+index 0000000..2c5738f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/hw_sequencer.h
+@@ -0,0 +1,170 @@
++/*
++ * Copyright 2015 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_HW_SEQUENCER_H__
++#define __DC_HW_SEQUENCER_H__
++#include "core_types.h"
++
++struct hw_sequencer_funcs {
++
++ enum dc_status (*apply_ctx_to_hw)(
++ const struct dc *dc,
++ struct validate_context *context);
++
++ void (*reset_hw_ctx)(struct dc *dc,
++ struct validate_context *context,
++ uint8_t target_count);
++
++ bool (*set_plane_config)(
++ struct core_surface *surface,
++ struct core_target *target);
++
++ bool (*update_plane_address)(
++ const struct core_surface *surface,
++ struct core_target *target);
++
++ bool (*enable_memory_requests)(struct timing_generator *tg);
++
++ bool (*disable_memory_requests)(struct timing_generator *tg);
++
++ bool (*transform_power_up)(struct transform *xfm);
++
++ bool (*cursor_set_attributes)(
++ struct input_pixel_processor *ipp,
++ const struct dc_cursor_attributes *attributes);
++
++ bool (*cursor_set_position)(
++ struct input_pixel_processor *ipp,
++ const struct dc_cursor_position *position);
++
++ bool (*set_gamma_ramp)(
++ struct input_pixel_processor *ipp,
++ struct output_pixel_processor *opp,
++ const struct gamma_ramp *ramp,
++ const struct gamma_parameters *params);
++
++ void (*power_down)(struct validate_context *context);
++
++ void (*enable_accelerated_mode)(struct validate_context *context);
++
++ void (*get_crtc_positions)(
++ struct timing_generator *tg,
++ int32_t *h_position,
++ int32_t *v_position);
++
++ uint32_t (*get_vblank_counter)(struct timing_generator *tg);
++
++ void (*enable_timing_synchronization)(
++ struct dc_context *dc_ctx,
++ uint32_t timing_generator_num,
++ struct timing_generator *tgs[]);
++
++ void (*disable_vga)(struct timing_generator *tg);
++
++
++
++ /* link encoder sequences */
++ struct link_encoder *(*encoder_create)(const struct encoder_init_data *init);
++
++ void (*encoder_destroy)(struct link_encoder **enc);
++
++ enum encoder_result (*encoder_power_up)(
++ struct link_encoder *enc);
++
++ enum encoder_result (*encoder_enable_output)(
++ struct link_encoder *enc,
++ const struct link_settings *link_settings,
++ enum engine_id engine,
++ enum clock_source_id clock_source,
++ enum signal_type signal,
++ enum dc_color_depth color_depth,
++ uint32_t pixel_clock);
++
++ enum encoder_result (*encoder_disable_output)(
++ struct link_encoder *enc,
++ enum signal_type signal);
++
++ void (*encoder_set_dp_phy_pattern)(
++ struct link_encoder *enc,
++ const struct encoder_set_dp_phy_pattern_param *param);
++
++ enum encoder_result (*encoder_dp_set_lane_settings)(
++ struct link_encoder *enc,
++ const struct link_training_settings *link_settings);
++
++ /* backlight control */
++ void (*encoder_set_lcd_backlight_level)(struct link_encoder *enc,
++ uint32_t level);
++
++
++ /* power management */
++ void (*clock_gating_power_up)(
++ struct dc_context *ctx,
++ bool enable);
++
++ void (*enable_display_pipe_clock_gating)(
++ struct dc_context *ctx,
++ bool clock_gating);
++
++ bool (*enable_display_power_gating)(
++ struct dc_context *ctx,
++ uint8_t controller_id,
++ struct bios_parser *bp,
++ enum pipe_gating_control power_gating);
++
++ void (*set_afmt_memory_power_state)(
++ const struct dc_context *ctx,
++ enum engine_id id,
++ bool enable);
++
++ /* resource management and validation*/
++ bool (*construct_resource_pool)(
++ struct adapter_service *adapter_serv,
++ struct dc *dc,
++ struct resource_pool *pool);
++
++ void (*destruct_resource_pool)(struct resource_pool *pool);
++
++ enum dc_status (*validate_with_context)(
++ const struct dc *dc,
++ const struct dc_validation_set set[],
++ uint8_t set_count,
++ struct validate_context *context);
++
++ enum dc_status (*validate_bandwidth)(
++ const struct dc *dc,
++ struct validate_context *context);
++ void (*program_bw)(
++ struct dc *dc,
++ struct validate_context *context);
++
++};
++
++bool dc_construct_hw_sequencer(
++ struct adapter_service *adapter_serv,
++ struct dc *dc);
++
++
++#endif /* __DC_HW_SEQUENCER_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/ipp.h b/drivers/gpu/drm/amd/dal/dc/inc/ipp.h
+new file mode 100644
+index 0000000..602b4cb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/ipp.h
+@@ -0,0 +1,66 @@
++/*
++ * Copyright 2015 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_IPP_H__
++#define __DAL_IPP_H__
++
++#include "include/plane_types.h"
++#include "include/grph_object_id.h"
++#include "include/grph_csc_types.h"
++#include "include/video_csc_types.h"
++#include "include/hw_sequencer_types.h"
++
++
++#define MAXTRIX_COEFFICIENTS_NUMBER 12
++#define MAXTRIX_COEFFICIENTS_WRAP_NUMBER (MAXTRIX_COEFFICIENTS_NUMBER + 4)
++#define MAX_OVL_MATRIX_COUNT 12
++
++/* IPP RELATED */
++struct input_pixel_processor {
++ struct dc_context *ctx;
++ uint32_t inst;
++};
++
++enum wide_gamut_degamma_mode {
++ /* 00 - BITS1:0 Bypass */
++ WIDE_GAMUT_DEGAMMA_MODE_GRAPHICS_BYPASS,
++ /* 0x1 - PWL gamma ROM A */
++ WIDE_GAMUT_DEGAMMA_MODE_GRAPHICS_PWL_ROM_A,
++ /* 0x2 - PWL gamma ROM B */
++ WIDE_GAMUT_DEGAMMA_MODE_GRAPHICS_PWL_ROM_B,
++ /* 00 - BITS5:4 Bypass */
++ WIDE_GAMUT_DEGAMMA_MODE_OVL_BYPASS,
++ /* 0x1 - PWL gamma ROM A */
++ WIDE_GAMUT_DEGAMMA_MODE_OVL_PWL_ROM_A,
++ /* 0x2 - PWL gamma ROM B */
++ WIDE_GAMUT_DEGAMMA_MODE_OVL_PWL_ROM_B,
++};
++
++struct dcp_video_matrix {
++ enum ovl_color_space color_space;
++ int32_t value[MAXTRIX_COEFFICIENTS_NUMBER];
++};
++
++#endif /* __DAL_IPP_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h
+new file mode 100644
+index 0000000..7110357
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/link_hwss.h
+@@ -0,0 +1,67 @@
++/*
++ * Copyright 2015 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_LINK_HWSS_H__
++#define __DC_LINK_HWSS_H__
++
++#include "inc/core_status.h"
++
++enum dc_status core_link_read_dpcd(
++ struct core_link* link,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size);
++
++enum dc_status core_link_write_dpcd(
++ struct core_link* link,
++ uint32_t address,
++ const uint8_t *data,
++ uint32_t size);
++
++enum dc_status dp_enable_link_phy(
++ struct core_link *link,
++ enum signal_type signal,
++ enum engine_id engine,
++ const struct link_settings *link_settings);
++
++void dp_receiver_power_ctrl(struct core_link *link, bool on);
++
++void dp_disable_link_phy(struct core_link *link, enum signal_type signal);
++
++bool dp_set_hw_training_pattern(
++ struct core_link *link,
++ enum hw_dp_training_pattern pattern);
++
++bool dp_set_hw_lane_settings(
++ struct core_link *link,
++ const struct link_training_settings *link_settings);
++
++void dp_set_hw_test_pattern(
++ struct core_link *link,
++ enum dp_test_pattern test_pattern);
++
++enum dp_panel_mode dp_get_panel_mode(struct core_link *link);
++
++#endif /* __DC_LINK_HWSS_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/mem_input.h b/drivers/gpu/drm/amd/dal/dc/inc/mem_input.h
+new file mode 100644
+index 0000000..458e7b5
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/mem_input.h
+@@ -0,0 +1,55 @@
++/*
++ * 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_MEM_INPUT_H__
++#define __DAL_MEM_INPUT_H__
++
++#include "include/plane_types.h"
++#include "include/grph_object_id.h"
++#include "dc.h"
++
++struct mem_input {
++ struct dc_context *ctx;
++ uint32_t inst;
++};
++
++enum stutter_mode_type {
++ STUTTER_MODE_LEGACY = 0X00000001,
++ STUTTER_MODE_ENHANCED = 0X00000002,
++ STUTTER_MODE_FID_NBP_STATE = 0X00000004,
++ STUTTER_MODE_WATERMARK_NBP_STATE = 0X00000008,
++ STUTTER_MODE_SINGLE_DISPLAY_MODEL = 0X00000010,
++ STUTTER_MODE_MIXED_DISPLAY_MODEL = 0X00000020,
++ STUTTER_MODE_DUAL_DMIF_BUFFER = 0X00000040,
++ STUTTER_MODE_NO_DMIF_BUFFER_ALLOCATION = 0X00000080,
++ STUTTER_MODE_NO_ADVANCED_REQUEST = 0X00000100,
++ STUTTER_MODE_NO_LB_RESET = 0X00000200,
++ STUTTER_MODE_DISABLED = 0X00000400,
++ STUTTER_MODE_AGGRESSIVE_MARKS = 0X00000800,
++ STUTTER_MODE_URGENCY = 0X00001000,
++ STUTTER_MODE_QUAD_DMIF_BUFFER = 0X00002000,
++ STUTTER_MODE_NOT_USED = 0X00008000
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/opp.h b/drivers/gpu/drm/amd/dal/dc/inc/opp.h
+new file mode 100644
+index 0000000..3293e3b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/opp.h
+@@ -0,0 +1,206 @@
++/*
++ * 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_OPP_H__
++#define __DAL_OPP_H__
++
++#include "dc_temp.h"
++#include "grph_object_id.h"
++#include "grph_csc_types.h"
++
++struct fixed31_32;
++
++/* TODO: Need cleanup */
++
++enum wide_gamut_regamma_mode {
++ /* 0x0 - BITS2:0 Bypass */
++ WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_BYPASS,
++ /* 0x1 - Fixed curve sRGB 2.4 */
++ WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_SRGB24,
++ /* 0x2 - Fixed curve xvYCC 2.22 */
++ WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_XYYCC22,
++ /* 0x3 - Programmable control A */
++ WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_MATRIX_A,
++ /* 0x4 - Programmable control B */
++ WIDE_GAMUT_REGAMMA_MODE_GRAPHICS_MATRIX_B,
++ /* 0x0 - BITS6:4 Bypass */
++ WIDE_GAMUT_REGAMMA_MODE_OVL_BYPASS,
++ /* 0x1 - Fixed curve sRGB 2.4 */
++ WIDE_GAMUT_REGAMMA_MODE_OVL_SRGB24,
++ /* 0x2 - Fixed curve xvYCC 2.22 */
++ WIDE_GAMUT_REGAMMA_MODE_OVL_XYYCC22,
++ /* 0x3 - Programmable control A */
++ WIDE_GAMUT_REGAMMA_MODE_OVL_MATRIX_A,
++ /* 0x4 - Programmable control B */
++ WIDE_GAMUT_REGAMMA_MODE_OVL_MATRIX_B
++};
++
++struct pwl_result_data {
++ struct fixed31_32 red;
++ struct fixed31_32 green;
++ struct fixed31_32 blue;
++
++ struct fixed31_32 delta_red;
++ struct fixed31_32 delta_green;
++ struct fixed31_32 delta_blue;
++
++ uint32_t red_reg;
++ uint32_t green_reg;
++ uint32_t blue_reg;
++
++ uint32_t delta_red_reg;
++ uint32_t delta_green_reg;
++ uint32_t delta_blue_reg;
++};
++
++struct gamma_pixel {
++ struct fixed31_32 r;
++ struct fixed31_32 g;
++ struct fixed31_32 b;
++};
++
++struct gamma_curve {
++ uint32_t offset;
++ uint32_t segments_num;
++};
++
++struct curve_points {
++ struct fixed31_32 x;
++ struct fixed31_32 y;
++ struct fixed31_32 offset;
++ struct fixed31_32 slope;
++
++ uint32_t custom_float_x;
++ uint32_t custom_float_y;
++ uint32_t custom_float_offset;
++ uint32_t custom_float_slope;
++};
++
++enum channel_name {
++ CHANNEL_NAME_RED,
++ CHANNEL_NAME_GREEN,
++ CHANNEL_NAME_BLUE
++};
++
++struct custom_float_format {
++ uint32_t mantissa_bits;
++ uint32_t exponenta_bits;
++ bool sign;
++};
++
++struct custom_float_value {
++ uint32_t mantissa;
++ uint32_t exponenta;
++ uint32_t value;
++ bool negative;
++};
++
++struct hw_x_point {
++ uint32_t custom_float_x;
++ uint32_t custom_float_x_adjusted;
++ struct fixed31_32 x;
++ struct fixed31_32 adjusted_x;
++ struct fixed31_32 regamma_y_red;
++ struct fixed31_32 regamma_y_green;
++ struct fixed31_32 regamma_y_blue;
++
++};
++
++struct pwl_float_data_ex {
++ struct fixed31_32 r;
++ struct fixed31_32 g;
++ struct fixed31_32 b;
++ struct fixed31_32 delta_r;
++ struct fixed31_32 delta_g;
++ struct fixed31_32 delta_b;
++};
++
++enum hw_point_position {
++ /* hw point sits between left and right sw points */
++ HW_POINT_POSITION_MIDDLE,
++ /* hw point lays left from left (smaller) sw point */
++ HW_POINT_POSITION_LEFT,
++ /* hw point lays stays from right (bigger) sw point */
++ HW_POINT_POSITION_RIGHT
++};
++
++struct gamma_point {
++ int32_t left_index;
++ int32_t right_index;
++ enum hw_point_position pos;
++ struct fixed31_32 coeff;
++};
++
++struct pixel_gamma_point {
++ struct gamma_point r;
++ struct gamma_point g;
++ struct gamma_point b;
++};
++
++struct gamma_coefficients {
++ struct fixed31_32 a0[3];
++ struct fixed31_32 a1[3];
++ struct fixed31_32 a2[3];
++ struct fixed31_32 a3[3];
++ struct fixed31_32 user_gamma[3];
++ struct fixed31_32 user_contrast;
++ struct fixed31_32 user_brightness;
++};
++
++struct csc_adjustments {
++ struct fixed31_32 contrast;
++ struct fixed31_32 saturation;
++ struct fixed31_32 brightness;
++ struct fixed31_32 hue;
++};
++
++struct pwl_float_data {
++ struct fixed31_32 r;
++ struct fixed31_32 g;
++ struct fixed31_32 b;
++};
++
++
++/* TODO: Use when we redefine the OPP interface */
++enum opp_regamma {
++ OPP_REGAMMA_BYPASS = 0,
++ OPP_REGAMMA_SRGB,
++ OPP_REGAMMA_3_6,
++ OPP_REGAMMA_PQ,
++ OPP_REGAMMA_PQ_INTERIM,
++};
++
++struct output_pixel_processor {
++ struct dc_context *ctx;
++ uint32_t inst;
++};
++
++enum fmt_stereo_action {
++ FMT_STEREO_ACTION_ENABLE = 0,
++ FMT_STEREO_ACTION_DISABLE,
++ FMT_STEREO_ACTION_UPDATE_POLARITY
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/resource.h b/drivers/gpu/drm/amd/dal/dc/inc/resource.h
+new file mode 100644
+index 0000000..0e0ba47
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/resource.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright 2015 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 DRIVERS_GPU_DRM_AMD_DAL_DEV_DC_INC_RESOURCE_H_
++#define DRIVERS_GPU_DRM_AMD_DAL_DEV_DC_INC_RESOURCE_H_
++
++#include "core_types.h"
++#include "core_status.h"
++#include "core_dc.h"
++
++void build_scaling_params(
++ const struct dc_surface *surface,
++ struct core_stream *stream);
++
++void build_scaling_params_for_context(
++ const struct dc *dc,
++ struct validate_context *context);
++
++void unreference_clock_source(
++ struct resource_context *res_ctx,
++ struct clock_source *clock_source);
++
++void reference_clock_source(
++ struct resource_context *res_ctx,
++ struct clock_source *clock_source);
++
++bool is_same_timing(
++ const struct dc_crtc_timing *timing1,
++ const struct dc_crtc_timing *timing2);
++
++struct clock_source *find_used_clk_src_for_sharing(
++ struct validate_context *context,
++ struct core_stream *stream);
++
++bool logical_attach_surfaces_to_target(
++ struct dc_surface *surfaces[],
++ uint8_t surface_count,
++ struct dc_target *dc_target);
++
++#endif /* DRIVERS_GPU_DRM_AMD_DAL_DEV_DC_INC_RESOURCE_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/dc/inc/transform.h b/drivers/gpu/drm/amd/dal/dc/inc/transform.h
+new file mode 100644
+index 0000000..8e111ce
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/inc/transform.h
+@@ -0,0 +1,81 @@
++/*
++ * 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_TRANSFORM_H__
++#define __DAL_TRANSFORM_H__
++
++#include "include/scaler_types.h"
++#include "calcs/scaler_filter.h"
++#include "grph_object_id.h"
++
++enum scaling_type {
++ SCALING_TYPE_NO_SCALING = 0,
++ SCALING_TYPE_UPSCALING,
++ SCALING_TYPE_DOWNSCALING
++};
++
++struct transform {
++ struct dc_context *ctx;
++ uint32_t inst;
++ struct scaler_filter *filter;
++};
++
++struct scaler_taps_and_ratio {
++ uint32_t h_tap;
++ uint32_t v_tap;
++ uint32_t lo_ratio;
++ uint32_t hi_ratio;
++};
++
++struct scaler_taps {
++ uint32_t h_tap;
++ uint32_t v_tap;
++};
++
++struct sclv_ratios_inits {
++ uint32_t chroma_enable;
++ uint32_t h_int_scale_ratio_luma;
++ uint32_t h_int_scale_ratio_chroma;
++ uint32_t v_int_scale_ratio_luma;
++ uint32_t v_int_scale_ratio_chroma;
++ struct init_int_and_frac h_init_luma;
++ struct init_int_and_frac h_init_chroma;
++ struct init_int_and_frac v_init_luma;
++ struct init_int_and_frac v_init_chroma;
++ struct init_int_and_frac h_init_lumabottom;
++ struct init_int_and_frac h_init_chromabottom;
++ struct init_int_and_frac v_init_lumabottom;
++ struct init_int_and_frac v_init_chromabottom;
++};
++
++enum lb_pixel_depth {
++ /* do not change the values because it is used as bit vector */
++ LB_PIXEL_DEPTH_18BPP = 1,
++ LB_PIXEL_DEPTH_24BPP = 2,
++ LB_PIXEL_DEPTH_30BPP = 4,
++ LB_PIXEL_DEPTH_36BPP = 8
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/irq/Makefile b/drivers/gpu/drm/amd/dal/dc/irq/Makefile
+new file mode 100644
+index 0000000..f1c5faf
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/irq/Makefile
+@@ -0,0 +1,21 @@
++#
++# Makefile for the 'audio' sub-component of DAL.
++# It provides the control and status of HW adapter resources,
++# that are global for the ASIC and sharable between pipes.
++
++IRQ = irq_service.o
++
++AMD_DAL_IRQ = $(addprefix $(AMDDALPATH)/dc/irq/,$(IRQ))
++
++AMD_DAL_FILES += $(AMD_DAL_IRQ)
++
++###############################################################################
++# DCE 11x
++###############################################################################
++ifdef CONFIG_DRM_AMD_DAL_DCE11_0
++IRQ_DCE11 = irq_service_dce110.o
++
++AMD_DAL_IRQ_DCE11 = $(addprefix $(AMDDALPATH)/dc/irq/dce110/,$(IRQ_DCE11))
++
++AMD_DAL_FILES += $(AMD_DAL_IRQ_DCE11)
++endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/irq/dce110/irq_service_dce110.c b/drivers/gpu/drm/amd/dal/dc/irq/dce110/irq_service_dce110.c
+new file mode 100644
+index 0000000..2a4f14c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/irq/dce110/irq_service_dce110.c
+@@ -0,0 +1,389 @@
++/*
++ * 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 "dal_services.h"
++
++#include "include/logger_interface.h"
++
++#include "irq_service_dce110.h"
++
++#include "dce/dce_11_0_d.h"
++#include "dce/dce_11_0_sh_mask.h"
++#include "ivsrcid/ivsrcid_vislands30.h"
++
++static bool hpd_ack(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info)
++{
++ uint32_t addr = info->status_reg;
++ uint32_t value = dal_read_reg(irq_service->ctx, addr);
++ uint32_t current_status =
++ get_reg_field_value(
++ value,
++ DC_HPD_INT_STATUS,
++ DC_HPD_SENSE_DELAYED);
++
++ dal_irq_service_ack_generic(irq_service, info);
++
++ value = dal_read_reg(irq_service->ctx, info->enable_reg);
++
++ set_reg_field_value(
++ value,
++ current_status ? 0 : 1,
++ DC_HPD_INT_CONTROL,
++ DC_HPD_INT_POLARITY);
++
++ dal_write_reg(irq_service->ctx, info->enable_reg, value);
++
++ return true;
++}
++
++static const struct irq_source_info_funcs hpd_irq_info_funcs = {
++ .set = NULL,
++ .ack = hpd_ack
++};
++
++static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
++ .set = NULL,
++ .ack = NULL
++};
++
++static const struct irq_source_info_funcs pflip_irq_info_funcs = {
++ .set = NULL,
++ .ack = NULL
++};
++
++static const struct irq_source_info_funcs vblank_irq_info_funcs = {
++ .set = NULL,
++ .ack = NULL
++};
++
++#define hpd_int_entry(reg_num)\
++ [DC_IRQ_SOURCE_HPD1 + reg_num] = {\
++ .enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
++ .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\
++ .enable_value = {\
++ DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK,\
++ ~DC_HPD_INT_CONTROL__DC_HPD_INT_EN_MASK\
++ },\
++ .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
++ .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\
++ .ack_value = DC_HPD_INT_CONTROL__DC_HPD_INT_ACK_MASK,\
++ .status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\
++ .funcs = &hpd_irq_info_funcs\
++ }
++
++#define hpd_rx_int_entry(reg_num)\
++ [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\
++ .enable_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
++ .enable_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\
++ .enable_value = {\
++ DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK,\
++ ~DC_HPD_INT_CONTROL__DC_HPD_RX_INT_EN_MASK },\
++ .ack_reg = mmHPD ## reg_num ## _DC_HPD_INT_CONTROL,\
++ .ack_mask = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\
++ .ack_value = DC_HPD_INT_CONTROL__DC_HPD_RX_INT_ACK_MASK,\
++ .status_reg = mmHPD ## reg_num ## _DC_HPD_INT_STATUS,\
++ .funcs = &hpd_rx_irq_info_funcs\
++ }
++#define pflip_int_entry(reg_num)\
++ [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
++ .enable_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_CONTROL,\
++ .enable_mask =\
++ GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
++ .enable_value = {\
++ GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK,\
++ ~GRPH_INTERRUPT_CONTROL__GRPH_PFLIP_INT_MASK_MASK},\
++ .ack_reg = mmDCP ## reg_num ## _GRPH_INTERRUPT_STATUS,\
++ .ack_mask = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
++ .ack_value = GRPH_INTERRUPT_STATUS__GRPH_PFLIP_INT_CLEAR_MASK,\
++ .status_reg = mmDCP ## reg_num ##_GRPH_INTERRUPT_STATUS,\
++ .funcs = &pflip_irq_info_funcs\
++ }
++
++#define vsync_int_entry(reg_num) \
++ [DC_IRQ_SOURCE_CRTC ## reg_num ## VSYNC] = dummy_irq_entry()
++
++#define vupdate_int_entry(reg_num)\
++ [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
++ .enable_reg = mmCRTC ## reg_num ## _CRTC_INTERRUPT_CONTROL,\
++ .enable_mask =\
++ CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
++ .enable_value = {\
++ CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK,\
++ ~CRTC_INTERRUPT_CONTROL__CRTC_V_UPDATE_INT_MSK_MASK},\
++ .ack_reg = mmCRTC ## reg_num ## _CRTC_V_UPDATE_INT_STATUS,\
++ .ack_mask =\
++ CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
++ .ack_value =\
++ CRTC_V_UPDATE_INT_STATUS__CRTC_V_UPDATE_INT_CLEAR_MASK,\
++ .funcs = &vblank_irq_info_funcs\
++ }
++
++#define dummy_irq_entry() \
++ {\
++ .funcs = &dummy_irq_info_funcs\
++ }
++
++#define i2c_int_entry(reg_num) \
++ [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
++
++#define azalia_int_entry(reg_num) \
++ [DC_IRQ_SOURCE_AZALIA ## reg_num] = dummy_irq_entry()
++
++#define dp_sink_int_entry(reg_num) \
++ [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
++
++#define gpio_pad_int_entry(reg_num) \
++ [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
++
++#define dc_underflow_int_entry(reg_num) \
++ [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
++
++static bool dummy_set(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info,
++ bool enable)
++{
++ dal_logger_write(
++ irq_service->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_IRQ_SERVICE,
++ "%s: called for non-implemented irq source\n",
++ __func__);
++ return false;
++}
++
++static bool dummy_ack(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info)
++{
++ dal_logger_write(
++ irq_service->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_IRQ_SERVICE,
++ "%s: called for non-implemented irq source\n",
++ __func__);
++ return false;
++}
++
++static const struct irq_source_info_funcs dummy_irq_info_funcs = {
++ .set = dummy_set,
++ .ack = dummy_ack
++};
++
++static const struct irq_source_info
++irq_source_info_dce110[DAL_IRQ_SOURCES_NUMBER] = {
++ [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
++ hpd_int_entry(0),
++ hpd_int_entry(1),
++ hpd_int_entry(2),
++ hpd_int_entry(3),
++ hpd_int_entry(4),
++ hpd_int_entry(5),
++ hpd_rx_int_entry(0),
++ hpd_rx_int_entry(1),
++ hpd_rx_int_entry(2),
++ hpd_rx_int_entry(3),
++ hpd_rx_int_entry(4),
++ hpd_rx_int_entry(5),
++ i2c_int_entry(1),
++ i2c_int_entry(2),
++ i2c_int_entry(3),
++ i2c_int_entry(4),
++ i2c_int_entry(5),
++ i2c_int_entry(6),
++ azalia_int_entry(0),
++ azalia_int_entry(1),
++ azalia_int_entry(2),
++ azalia_int_entry(3),
++ azalia_int_entry(4),
++ azalia_int_entry(5),
++ dp_sink_int_entry(1),
++ dp_sink_int_entry(2),
++ dp_sink_int_entry(3),
++ dp_sink_int_entry(4),
++ dp_sink_int_entry(5),
++ dp_sink_int_entry(6),
++ vsync_int_entry(1),
++ vsync_int_entry(2),
++ vsync_int_entry(3),
++ vsync_int_entry(3),
++ vsync_int_entry(4),
++ vsync_int_entry(5),
++ [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
++ pflip_int_entry(0),
++ pflip_int_entry(1),
++ pflip_int_entry(2),
++ pflip_int_entry(3),
++ pflip_int_entry(4),
++ pflip_int_entry(5),
++ [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
++ gpio_pad_int_entry(0),
++ gpio_pad_int_entry(1),
++ gpio_pad_int_entry(2),
++ gpio_pad_int_entry(3),
++ gpio_pad_int_entry(4),
++ gpio_pad_int_entry(5),
++ gpio_pad_int_entry(6),
++ gpio_pad_int_entry(7),
++ gpio_pad_int_entry(8),
++ gpio_pad_int_entry(9),
++ gpio_pad_int_entry(10),
++ gpio_pad_int_entry(11),
++ gpio_pad_int_entry(12),
++ gpio_pad_int_entry(13),
++ gpio_pad_int_entry(14),
++ gpio_pad_int_entry(15),
++ gpio_pad_int_entry(16),
++ gpio_pad_int_entry(17),
++ gpio_pad_int_entry(18),
++ gpio_pad_int_entry(19),
++ gpio_pad_int_entry(20),
++ gpio_pad_int_entry(21),
++ gpio_pad_int_entry(22),
++ gpio_pad_int_entry(23),
++ gpio_pad_int_entry(24),
++ gpio_pad_int_entry(25),
++ gpio_pad_int_entry(26),
++ gpio_pad_int_entry(27),
++ gpio_pad_int_entry(28),
++ gpio_pad_int_entry(29),
++ gpio_pad_int_entry(30),
++ dc_underflow_int_entry(1),
++ dc_underflow_int_entry(2),
++ dc_underflow_int_entry(3),
++ dc_underflow_int_entry(4),
++ dc_underflow_int_entry(5),
++ dc_underflow_int_entry(6),
++ [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
++ [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
++ vupdate_int_entry(0),
++ vupdate_int_entry(1),
++ vupdate_int_entry(2),
++ vupdate_int_entry(3),
++ vupdate_int_entry(4),
++ vupdate_int_entry(5),
++};
++
++static enum dc_irq_source to_dal_irq_source(
++ struct irq_service *irq_service,
++ uint32_t src_id,
++ uint32_t ext_id)
++{
++ switch (src_id) {
++ case VISLANDS30_IV_SRCID_D1_V_UPDATE_INT:
++ return DC_IRQ_SOURCE_VUPDATE1;
++ case VISLANDS30_IV_SRCID_D2_V_UPDATE_INT:
++ return DC_IRQ_SOURCE_VUPDATE2;
++ case VISLANDS30_IV_SRCID_D3_V_UPDATE_INT:
++ return DC_IRQ_SOURCE_VUPDATE3;
++ case VISLANDS30_IV_SRCID_D4_V_UPDATE_INT:
++ return DC_IRQ_SOURCE_VUPDATE4;
++ case VISLANDS30_IV_SRCID_D5_V_UPDATE_INT:
++ return DC_IRQ_SOURCE_VUPDATE5;
++ case VISLANDS30_IV_SRCID_D6_V_UPDATE_INT:
++ return DC_IRQ_SOURCE_VUPDATE6;
++ case VISLANDS30_IV_SRCID_D1_GRPH_PFLIP:
++ return DC_IRQ_SOURCE_PFLIP1;
++ case VISLANDS30_IV_SRCID_D2_GRPH_PFLIP:
++ return DC_IRQ_SOURCE_PFLIP2;
++ case VISLANDS30_IV_SRCID_D3_GRPH_PFLIP:
++ return DC_IRQ_SOURCE_PFLIP3;
++ case VISLANDS30_IV_SRCID_D4_GRPH_PFLIP:
++ return DC_IRQ_SOURCE_PFLIP4;
++ case VISLANDS30_IV_SRCID_D5_GRPH_PFLIP:
++ return DC_IRQ_SOURCE_PFLIP5;
++ case VISLANDS30_IV_SRCID_D6_GRPH_PFLIP:
++ return DC_IRQ_SOURCE_PFLIP6;
++
++ case VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A:
++ /* generic src_id for all HPD and HPDRX interrupts */
++ switch (ext_id) {
++ case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_A:
++ return DC_IRQ_SOURCE_HPD1;
++ case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_B:
++ return DC_IRQ_SOURCE_HPD2;
++ case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_C:
++ return DC_IRQ_SOURCE_HPD3;
++ case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_D:
++ return DC_IRQ_SOURCE_HPD4;
++ case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_E:
++ return DC_IRQ_SOURCE_HPD5;
++ case VISLANDS30_IV_EXTID_HOTPLUG_DETECT_F:
++ return DC_IRQ_SOURCE_HPD6;
++ case VISLANDS30_IV_EXTID_HPD_RX_A:
++ return DC_IRQ_SOURCE_HPD1RX;
++ case VISLANDS30_IV_EXTID_HPD_RX_B:
++ return DC_IRQ_SOURCE_HPD2RX;
++ case VISLANDS30_IV_EXTID_HPD_RX_C:
++ return DC_IRQ_SOURCE_HPD3RX;
++ case VISLANDS30_IV_EXTID_HPD_RX_D:
++ return DC_IRQ_SOURCE_HPD4RX;
++ case VISLANDS30_IV_EXTID_HPD_RX_E:
++ return DC_IRQ_SOURCE_HPD5RX;
++ case VISLANDS30_IV_EXTID_HPD_RX_F:
++ return DC_IRQ_SOURCE_HPD6RX;
++ default:
++ return DC_IRQ_SOURCE_INVALID;
++ }
++ break;
++
++ default:
++ return DC_IRQ_SOURCE_INVALID;
++ }
++}
++
++static const struct irq_service_funcs irq_service_funcs_dce110 = {
++ .to_dal_irq_source = to_dal_irq_source
++};
++
++bool construct(
++ struct irq_service *irq_service,
++ struct irq_service_init_data *init_data)
++{
++ if (!dal_irq_service_construct(irq_service, init_data))
++ return false;
++
++ irq_service->info = irq_source_info_dce110;
++ irq_service->funcs = &irq_service_funcs_dce110;
++
++ return true;
++}
++
++struct irq_service *dal_irq_service_dce110_create(
++ struct irq_service_init_data *init_data)
++{
++ struct irq_service *irq_service = dc_service_alloc(init_data->ctx, sizeof(*irq_service));
++
++ if (!irq_service)
++ return NULL;
++
++ if (construct(irq_service, init_data))
++ return irq_service;
++
++ dc_service_free(init_data->ctx, irq_service);
++ return NULL;
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/irq/dce110/irq_service_dce110.h b/drivers/gpu/drm/amd/dal/dc/irq/dce110/irq_service_dce110.h
+new file mode 100644
+index 0000000..d6c28e9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/irq/dce110/irq_service_dce110.h
+@@ -0,0 +1,34 @@
++/*
++ * 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_IRQ_SERVICE_DCE110_H__
++#define __DAL_IRQ_SERVICE_DCE110_H__
++
++#include "../irq_service.h"
++
++struct irq_service *dal_irq_service_dce110_create(
++ struct irq_service_init_data *init_data);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
+new file mode 100644
+index 0000000..0c7429c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.c
+@@ -0,0 +1,173 @@
++/*
++ * 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 "dal_services.h"
++
++#include "include/irq_service_interface.h"
++#include "include/logger_interface.h"
++
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++#include "dce110/irq_service_dce110.h"
++#endif
++
++#include "irq_service.h"
++
++bool dal_irq_service_construct(
++ struct irq_service *irq_service,
++ struct irq_service_init_data *init_data)
++{
++ if (!init_data || !init_data->ctx)
++ return false;
++
++ irq_service->ctx = init_data->ctx;
++ return true;
++}
++
++struct irq_service *dal_irq_service_create(
++ enum dce_version version,
++ struct irq_service_init_data *init_data)
++{
++ switch (version) {
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ case DCE_VERSION_11_0:
++ return dal_irq_service_dce110_create(init_data);
++#endif
++ default:
++ return NULL;
++ }
++}
++
++void dal_irq_service_destroy(struct irq_service **irq_service)
++{
++ if (!irq_service || !*irq_service) {
++ BREAK_TO_DEBUGGER();
++ return;
++ }
++
++ dc_service_free((*irq_service)->ctx, *irq_service);
++
++ *irq_service = NULL;
++}
++
++const struct irq_source_info *find_irq_source_info(
++ struct irq_service *irq_service,
++ enum dc_irq_source source)
++{
++ if (source > DAL_IRQ_SOURCES_NUMBER || source < DC_IRQ_SOURCE_INVALID)
++ return NULL;
++
++ return &irq_service->info[source];
++}
++
++void dal_irq_service_set_generic(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info,
++ bool enable)
++{
++ uint32_t addr = info->enable_reg;
++ uint32_t value = dal_read_reg(irq_service->ctx, addr);
++
++ value = (value & ~info->enable_mask) |
++ (info->enable_value[enable ? 0 : 1] & info->enable_mask);
++ dal_write_reg(irq_service->ctx, addr, value);
++}
++
++bool dal_irq_service_set(
++ struct irq_service *irq_service,
++ enum dc_irq_source source,
++ bool enable)
++{
++ const struct irq_source_info *info =
++ find_irq_source_info(irq_service, source);
++
++ if (!info) {
++ dal_logger_write(
++ irq_service->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_IRQ_SERVICE,
++ "%s: cannot find irq info table entry for %d\n",
++ __func__,
++ source);
++ return false;
++ }
++
++ dal_irq_service_ack(irq_service, source);
++
++ if (info->funcs->set)
++ return info->funcs->set(irq_service, info, enable);
++
++ dal_irq_service_set_generic(irq_service, info, enable);
++
++ return true;
++}
++
++void dal_irq_service_ack_generic(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info)
++{
++ uint32_t addr = info->ack_reg;
++ uint32_t value = dal_read_reg(irq_service->ctx, addr);
++
++ value = (value & ~info->ack_mask) |
++ (info->ack_value & info->ack_mask);
++ dal_write_reg(irq_service->ctx, addr, value);
++}
++
++bool dal_irq_service_ack(
++ struct irq_service *irq_service,
++ enum dc_irq_source source)
++{
++ const struct irq_source_info *info =
++ find_irq_source_info(irq_service, source);
++
++ if (!info) {
++ dal_logger_write(
++ irq_service->ctx->logger,
++ LOG_MAJOR_ERROR,
++ LOG_MINOR_COMPONENT_IRQ_SERVICE,
++ "%s: cannot find irq info table entry for %d\n",
++ __func__,
++ source);
++ return false;
++ }
++
++ if (info->funcs->ack)
++ return info->funcs->ack(irq_service, info);
++
++ dal_irq_service_ack_generic(irq_service, info);
++
++ return true;
++}
++
++enum dc_irq_source dal_irq_service_to_irq_source(
++ struct irq_service *irq_service,
++ uint32_t src_id,
++ uint32_t ext_id)
++{
++ return irq_service->funcs->to_dal_irq_source(
++ irq_service,
++ src_id,
++ ext_id);
++}
+diff --git a/drivers/gpu/drm/amd/dal/dc/irq/irq_service.h b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.h
+new file mode 100644
+index 0000000..a2a2d69
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/irq/irq_service.h
+@@ -0,0 +1,85 @@
++/*
++ * 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_IRQ_SERVICE_H__
++#define __DAL_IRQ_SERVICE_H__
++
++#include "include/irq_service_interface.h"
++
++#include "irq_types.h"
++
++struct irq_service;
++struct irq_source_info;
++
++struct irq_source_info_funcs {
++ bool (*set)(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info,
++ bool enable);
++ bool (*ack)(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info);
++};
++
++struct irq_source_info {
++ uint32_t src_id;
++ uint32_t ext_id;
++ uint32_t enable_reg;
++ uint32_t enable_mask;
++ uint32_t enable_value[2];
++ uint32_t ack_reg;
++ uint32_t ack_mask;
++ uint32_t ack_value;
++ uint32_t status_reg;
++ const struct irq_source_info_funcs *funcs;
++};
++
++struct irq_service_funcs {
++ enum dc_irq_source (*to_dal_irq_source)(
++ struct irq_service *irq_service,
++ uint32_t src_id,
++ uint32_t ext_id);
++};
++
++struct irq_service {
++ struct dc_context *ctx;
++ const struct irq_source_info *info;
++ const struct irq_service_funcs *funcs;
++};
++
++bool dal_irq_service_construct(
++ struct irq_service *irq_service,
++ struct irq_service_init_data *init_data);
++
++void dal_irq_service_ack_generic(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info);
++
++void dal_irq_service_set_generic(
++ struct irq_service *irq_service,
++ const struct irq_source_info *info,
++ bool enable);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/dc/irq_types.h b/drivers/gpu/drm/amd/dal/dc/irq_types.h
+new file mode 100644
+index 0000000..051a1f6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/dc/irq_types.h
+@@ -0,0 +1,199 @@
++/*
++ * 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_IRQ_TYPES_H__
++#define __DAL_IRQ_TYPES_H__
++
++struct dc_context;
++
++typedef void (*interrupt_handler)(void *);
++
++typedef void *irq_handler_idx;
++#define DAL_INVALID_IRQ_HANDLER_IDX NULL
++
++
++/* The order of the IRQ sources is important and MUST match the one's
++of base driver */
++enum dc_irq_source {
++ /* Use as mask to specify invalid irq source */
++ DC_IRQ_SOURCE_INVALID = 0,
++
++ DC_IRQ_SOURCE_HPD1,
++ DC_IRQ_SOURCE_HPD2,
++ DC_IRQ_SOURCE_HPD3,
++ DC_IRQ_SOURCE_HPD4,
++ DC_IRQ_SOURCE_HPD5,
++ DC_IRQ_SOURCE_HPD6,
++
++ DC_IRQ_SOURCE_HPD1RX,
++ DC_IRQ_SOURCE_HPD2RX,
++ DC_IRQ_SOURCE_HPD3RX,
++ DC_IRQ_SOURCE_HPD4RX,
++ DC_IRQ_SOURCE_HPD5RX,
++ DC_IRQ_SOURCE_HPD6RX,
++
++ DC_IRQ_SOURCE_I2C_DDC1,
++ DC_IRQ_SOURCE_I2C_DDC2,
++ DC_IRQ_SOURCE_I2C_DDC3,
++ DC_IRQ_SOURCE_I2C_DDC4,
++ DC_IRQ_SOURCE_I2C_DDC5,
++ DC_IRQ_SOURCE_I2C_DDC6,
++
++ DC_IRQ_SOURCE_AZALIA0,
++ DC_IRQ_SOURCE_AZALIA1,
++ DC_IRQ_SOURCE_AZALIA2,
++ DC_IRQ_SOURCE_AZALIA3,
++ DC_IRQ_SOURCE_AZALIA4,
++ DC_IRQ_SOURCE_AZALIA5,
++
++ DC_IRQ_SOURCE_DPSINK1,
++ DC_IRQ_SOURCE_DPSINK2,
++ DC_IRQ_SOURCE_DPSINK3,
++ DC_IRQ_SOURCE_DPSINK4,
++ DC_IRQ_SOURCE_DPSINK5,
++ DC_IRQ_SOURCE_DPSINK6,
++
++ DC_IRQ_SOURCE_CRTC1VSYNC,
++ DC_IRQ_SOURCE_CRTC2VSYNC,
++ DC_IRQ_SOURCE_CRTC3VSYNC,
++ DC_IRQ_SOURCE_CRTC4VSYNC,
++ DC_IRQ_SOURCE_CRTC5VSYNC,
++ DC_IRQ_SOURCE_CRTC6VSYNC,
++ DC_IRQ_SOURCE_TIMER,
++
++ DC_IRQ_SOURCE_PFLIP_FIRST,
++ DC_IRQ_SOURCE_PFLIP1 = DC_IRQ_SOURCE_PFLIP_FIRST,
++ DC_IRQ_SOURCE_PFLIP2,
++ DC_IRQ_SOURCE_PFLIP3,
++ DC_IRQ_SOURCE_PFLIP4,
++ DC_IRQ_SOURCE_PFLIP5,
++ DC_IRQ_SOURCE_PFLIP6,
++ DC_IRQ_SOURCE_PFLIP_UNDERLAY0,
++ DC_IRQ_SOURCE_PFLIP_LAST = DC_IRQ_SOURCE_PFLIP_UNDERLAY0,
++
++ DC_IRQ_SOURCE_GPIOPAD0,
++ DC_IRQ_SOURCE_GPIOPAD1,
++ DC_IRQ_SOURCE_GPIOPAD2,
++ DC_IRQ_SOURCE_GPIOPAD3,
++ DC_IRQ_SOURCE_GPIOPAD4,
++ DC_IRQ_SOURCE_GPIOPAD5,
++ DC_IRQ_SOURCE_GPIOPAD6,
++ DC_IRQ_SOURCE_GPIOPAD7,
++ DC_IRQ_SOURCE_GPIOPAD8,
++ DC_IRQ_SOURCE_GPIOPAD9,
++ DC_IRQ_SOURCE_GPIOPAD10,
++ DC_IRQ_SOURCE_GPIOPAD11,
++ DC_IRQ_SOURCE_GPIOPAD12,
++ DC_IRQ_SOURCE_GPIOPAD13,
++ DC_IRQ_SOURCE_GPIOPAD14,
++ DC_IRQ_SOURCE_GPIOPAD15,
++ DC_IRQ_SOURCE_GPIOPAD16,
++ DC_IRQ_SOURCE_GPIOPAD17,
++ DC_IRQ_SOURCE_GPIOPAD18,
++ DC_IRQ_SOURCE_GPIOPAD19,
++ DC_IRQ_SOURCE_GPIOPAD20,
++ DC_IRQ_SOURCE_GPIOPAD21,
++ DC_IRQ_SOURCE_GPIOPAD22,
++ DC_IRQ_SOURCE_GPIOPAD23,
++ DC_IRQ_SOURCE_GPIOPAD24,
++ DC_IRQ_SOURCE_GPIOPAD25,
++ DC_IRQ_SOURCE_GPIOPAD26,
++ DC_IRQ_SOURCE_GPIOPAD27,
++ DC_IRQ_SOURCE_GPIOPAD28,
++ DC_IRQ_SOURCE_GPIOPAD29,
++ DC_IRQ_SOURCE_GPIOPAD30,
++
++ DC_IRQ_SOURCE_DC1UNDERFLOW,
++ DC_IRQ_SOURCE_DC2UNDERFLOW,
++ DC_IRQ_SOURCE_DC3UNDERFLOW,
++ DC_IRQ_SOURCE_DC4UNDERFLOW,
++ DC_IRQ_SOURCE_DC5UNDERFLOW,
++ DC_IRQ_SOURCE_DC6UNDERFLOW,
++
++ DC_IRQ_SOURCE_DMCU_SCP,
++ DC_IRQ_SOURCE_VBIOS_SW,
++
++ DC_IRQ_SOURCE_VUPDATE1,
++ DC_IRQ_SOURCE_VUPDATE2,
++ DC_IRQ_SOURCE_VUPDATE3,
++ DC_IRQ_SOURCE_VUPDATE4,
++ DC_IRQ_SOURCE_VUPDATE5,
++ DC_IRQ_SOURCE_VUPDATE6,
++
++ DAL_IRQ_SOURCES_NUMBER
++};
++
++enum irq_type
++{
++ IRQ_TYPE_PFLIP = DC_IRQ_SOURCE_PFLIP1,
++ IRQ_TYPE_VUPDATE = DC_IRQ_SOURCE_VUPDATE1,
++};
++
++#define DAL_VALID_IRQ_SRC_NUM(src) \
++ ((src) <= DAL_IRQ_SOURCES_NUMBER && (src) > DC_IRQ_SOURCE_INVALID)
++
++/* Number of Page Flip IRQ Sources. */
++#define DAL_PFLIP_IRQ_SRC_NUM \
++ (DC_IRQ_SOURCE_PFLIP_LAST - DC_IRQ_SOURCE_PFLIP_FIRST + 1)
++
++/* the number of contexts may be expanded in the future based on needs */
++enum dc_interrupt_context {
++ INTERRUPT_LOW_IRQ_CONTEXT = 0,
++ INTERRUPT_HIGH_IRQ_CONTEXT,
++ INTERRUPT_CONTEXT_NUMBER
++};
++
++enum dc_interrupt_porlarity {
++ INTERRUPT_POLARITY_DEFAULT = 0,
++ INTERRUPT_POLARITY_LOW = INTERRUPT_POLARITY_DEFAULT,
++ INTERRUPT_POLARITY_HIGH,
++ INTERRUPT_POLARITY_BOTH
++};
++
++#define DC_DECODE_INTERRUPT_POLARITY(int_polarity) \
++ (int_polarity == INTERRUPT_POLARITY_LOW) ? "Low" : \
++ (int_polarity == INTERRUPT_POLARITY_HIGH) ? "High" : \
++ (int_polarity == INTERRUPT_POLARITY_BOTH) ? "Both" : "Invalid"
++
++struct dc_timer_interrupt_params {
++ uint64_t micro_sec_interval;
++ enum dc_interrupt_context int_context;
++};
++
++struct dc_interrupt_params {
++ /* The polarity *change* which will trigger an interrupt.
++ * If 'requested_polarity == INTERRUPT_POLARITY_BOTH', then
++ * 'current_polarity' must be initialised. */
++ enum dc_interrupt_porlarity requested_polarity;
++ /* If 'requested_polarity == INTERRUPT_POLARITY_BOTH',
++ * 'current_polarity' should contain the current state, which means
++ * the interrupt will be triggered when state changes from what is,
++ * in 'current_polarity'. */
++ enum dc_interrupt_porlarity current_polarity;
++ enum dc_irq_source irq_source;
++ enum dc_interrupt_context int_context;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/adapter_service_interface.h b/drivers/gpu/drm/amd/dal/include/adapter_service_interface.h
+new file mode 100644
+index 0000000..aa503a8
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/adapter_service_interface.h
+@@ -0,0 +1,628 @@
++/*
++ * 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_ADAPTER_SERVICE_INTERFACE_H__
++#define __DAL_ADAPTER_SERVICE_INTERFACE_H__
++
++#include "grph_object_ctrl_defs.h"
++#include "gpio_interface.h"
++#include "ddc_interface.h"
++#include "irq_interface.h"
++#include "bios_parser_interface.h"
++#include "adapter_service_types.h"
++#include "dal_types.h"
++#include "asic_capability_types.h"
++
++/* forward declaration */
++struct bios_parser;
++struct i2caux;
++struct adapter_service;
++
++
++/*
++ * enum adapter_feature_id
++ *
++ * Definition of all adapter features
++ *
++ * The enumeration defines the IDs of all the adapter features. The enum
++ * organizes all the features into several feature sets. The range of feature
++ * set N is from ((N-1)*32+1) to (N*32). Because there may be three value-type
++ * feature, boolean-type, unsigned char-type and unsinged int-type, the number
++ * of features should be 32, 4 and 1 in the feature set accordingly.
++ *
++ * In a boolean-type feature set N, the enumeration value of the feature should
++ * be ((N-1)*32+1), ((N-1)*32+2), ..., (N*32).
++ *
++ * In an unsigned char-type feature set N, the enumeration value of the
++ * feature should be ((N-1)*32+1), ((N-1)*32+8), ((N-1)*32+16) and (N*32).
++ *
++ * In an unsigned int-type feature set N, the enumeration value of the feature
++ * should be ((N-1)*32+1)
++ */
++enum adapter_feature_id {
++ FEATURE_UNKNOWN = 0,
++
++ /* Boolean set, up to 32 entries */
++ FEATURE_ENABLE_HW_EDID_POLLING = 1,
++ FEATURE_SET_01_START = FEATURE_ENABLE_HW_EDID_POLLING,
++ FEATURE_DP_SINK_DETECT_POLL_DATA_PIN,
++ FEATURE_UNDERFLOW_INTERRUPT,
++ FEATURE_ALLOW_WATERMARK_ADJUSTMENT,
++ FEATURE_LIGHT_SLEEP,
++ FEATURE_DCP_DITHER_FRAME_RANDOM_ENABLE,
++ FEATURE_DCP_DITHER_RGB_RANDOM_ENABLE,
++ FEATURE_DCP_DITHER_HIGH_PASS_RANDOM_ENABLE,
++ FEATURE_DETECT_REQUIRE_HPD_HIGH,
++ FEATURE_LINE_BUFFER_ENHANCED_PIXEL_DEPTH, /* 10th */
++ FEATURE_MAXIMIZE_URGENCY_WATERMARKS,
++ FEATURE_MAXIMIZE_STUTTER_MARKS,
++ FEATURE_MAXIMIZE_NBP_MARKS,
++ FEATURE_RESTORE_USAGE_I2C_SW_ENGINE,
++ FEATURE_USE_MAX_DISPLAY_CLK,
++ FEATURE_ALLOW_EDP_RESOURCE_SHARING,
++ FEATURE_SUPPORT_DP_YUV,
++ FEATURE_SUPPORT_DP_Y_ONLY,
++ FEATURE_DISABLE_DP_GTC_SYNC,
++ FEATURE_NO_HPD_LOW_POLLING_VCC_OFF, /* 20th */
++ FEATURE_ENABLE_DFS_BYPASS,
++ FEATURE_LB_HIGH_RESOLUTION,
++ FEATURE_DP_DISPLAY_FORCE_SS_ENABLE,
++ FEATURE_REPORT_CE_MODE_ONLY,
++ FEATURE_ALLOW_OPTIMIZED_MODE_AS_DEFAULT,
++ FEATURE_DDC_READ_FORCE_REPEATED_START,
++ FEATURE_FORCE_TIMING_RESYNC,
++ FEATURE_TMDS_DISABLE_DITHERING,
++ FEATURE_HDMI_DISABLE_DITHERING,
++ FEATURE_DP_DISABLE_DITHERING, /* 30th */
++ FEATURE_EMBEDDED_DISABLE_DITHERING,
++ FEATURE_DISABLE_AZ_CLOCK_GATING, /* 32th. This set is full */
++ FEATURE_SET_01_END = FEATURE_SET_01_START + 31,
++
++ /* Boolean set, up to 32 entries */
++ FEATURE_WIRELESS_ENABLE = FEATURE_SET_01_END + 1,
++ FEATURE_SET_02_START = FEATURE_WIRELESS_ENABLE,
++ FEATURE_WIRELESS_FULL_TIMING_ADJUSTMENT,
++ FEATURE_WIRELESS_LIMIT_720P,
++ FEATURE_WIRELESS_ENABLE_COMPRESSED_AUDIO,
++ FEATURE_WIRELESS_INCLUDE_UNVERIFIED_TIMINGS,
++ FEATURE_MODIFY_TIMINGS_FOR_WIRELESS,
++ FEATURE_ALLOW_SELF_REFRESH,
++ FEATURE_ALLOW_DYNAMIC_PIXEL_ENCODING_CHANGE,
++ FEATURE_ALLOW_HSYNC_VSYNC_ADJUSTMENT,
++ FEATURE_FORCE_PSR, /* 10th */
++ FEATURE_PREFER_3D_TIMING,
++ FEATURE_VARI_BRIGHT_ENABLE,
++ FEATURE_PSR_ENABLE,
++ FEATURE_EDID_STRESS_READ,
++ FEATURE_DP_FRAME_PACK_STEREO3D,
++ FEATURE_ALLOW_HDMI_WITHOUT_AUDIO,
++ FEATURE_RESTORE_USAGE_I2C_SW_ENGING,
++ FEATURE_ABM_2_0,
++ FEATURE_SUPPORT_MIRABILIS,
++ FEATURE_LOAD_DMCU_FIRMWARE, /* 20th */
++ FEATURE_ENABLE_GPU_SCALING,
++ FEATURE_DONGLE_SINK_COUNT_CHECK,
++ FEATURE_INSTANT_UP_SCALE_DOWN_SCALE,
++ FEATURE_TILED_DISPLAY,
++ FEATURE_CHANGE_I2C_SPEED_CONTROL,
++ FEATURE_REPORT_SINGLE_SELECTED_TIMING,
++ FEATURE_ALLOW_HDMI_HIGH_CLK_DP_DONGLE,
++ FEATURE_SUPPORT_EXTERNAL_PANEL_DRR,
++ FEATURE_SUPPORT_SMOOTH_BRIGHTNESS,
++ FEATURE_ALLOW_DIRECT_MEMORY_ACCESS_TRIG, /* 30th */
++ FEATURE_POWER_GATING_LB_PORTION, /* 31nd. One more left. */
++ FEATURE_SET_02_END = FEATURE_SET_02_START + 31,
++
++ /* UInt set, 1 entry: DCP Bit Depth Reduction Mode */
++ FEATURE_DCP_BIT_DEPTH_REDUCTION_MODE = FEATURE_SET_02_END + 1,
++ FEATURE_SET_03_START = FEATURE_DCP_BIT_DEPTH_REDUCTION_MODE,
++ FEATURE_SET_03_END = FEATURE_SET_03_START + 31,
++
++ /* UInt set, 1 entry: DCP Dither Mode */
++ FEATURE_DCP_DITHER_MODE = FEATURE_SET_03_END + 1,
++ FEATURE_SET_04_START = FEATURE_DCP_DITHER_MODE,
++ FEATURE_SET_04_END = FEATURE_SET_04_START + 31,
++
++ /* UInt set, 1 entry: DCP Programming WA(workaround) */
++ FEATURE_DCP_PROGRAMMING_WA = FEATURE_SET_04_END + 1,
++ FEATURE_SET_06_START = FEATURE_DCP_PROGRAMMING_WA,
++ FEATURE_SET_06_END = FEATURE_SET_06_START + 31,
++
++ /* UInt set, 1 entry: Maximum co-functional non-DP displays */
++ FEATURE_MAX_COFUNC_NON_DP_DISPLAYS = FEATURE_SET_06_END + 1,
++ FEATURE_SET_07_START = FEATURE_MAX_COFUNC_NON_DP_DISPLAYS,
++ FEATURE_SET_07_END = FEATURE_SET_07_START + 31,
++
++ /* UInt set, 1 entry: Number of supported HDMI connection */
++ FEATURE_SUPPORTED_HDMI_CONNECTION_NUM = FEATURE_SET_07_END + 1,
++ FEATURE_SET_08_START = FEATURE_SUPPORTED_HDMI_CONNECTION_NUM,
++ FEATURE_SET_08_END = FEATURE_SET_08_START + 31,
++
++ /* UInt set, 1 entry: Maximum number of controllers */
++ FEATURE_MAX_CONTROLLER_NUM = FEATURE_SET_08_END + 1,
++ FEATURE_SET_09_START = FEATURE_MAX_CONTROLLER_NUM,
++ FEATURE_SET_09_END = FEATURE_SET_09_START + 31,
++
++ /* UInt set, 1 entry: Type of DRR support */
++ FEATURE_DRR_SUPPORT = FEATURE_SET_09_END + 1,
++ FEATURE_SET_10_START = FEATURE_DRR_SUPPORT,
++ FEATURE_SET_10_END = FEATURE_SET_10_START + 31,
++
++ /* UInt set, 1 entry: Stutter mode support */
++ FEATURE_STUTTER_MODE = FEATURE_SET_10_END + 1,
++ FEATURE_SET_11_START = FEATURE_STUTTER_MODE,
++ FEATURE_SET_11_END = FEATURE_SET_11_START + 31,
++
++ /* UInt set, 1 entry: Measure PSR setup time */
++ FEATURE_PSR_SETUP_TIME_TEST = FEATURE_SET_11_END + 1,
++ FEATURE_SET_12_START = FEATURE_PSR_SETUP_TIME_TEST,
++ FEATURE_SET_12_END = FEATURE_SET_12_START + 31,
++
++ /* Boolean set, up to 32 entries */
++ FEATURE_POWER_GATING_PIPE_IN_TILE = FEATURE_SET_12_END + 1,
++ FEATURE_SET_13_START = FEATURE_POWER_GATING_PIPE_IN_TILE,
++ FEATURE_USE_PPLIB,
++ FEATURE_DISABLE_LPT_SUPPORT,
++ FEATURE_DUMMY_FBC_BACKEND,
++ FEATURE_DISABLE_FBC_COMP_CLK_GATE,
++ FEATURE_DPMS_AUDIO_ENDPOINT_CONTROL,
++ FEATURE_PIXEL_PERFECT_OUTPUT,
++ FEATURE_8BPP_SUPPORTED,
++ FEATURE_SET_13_END = FEATURE_SET_13_START + 31,
++
++ /* UInt set, 1 entry: Display preferred view
++ * 0: no preferred view
++ * 1: native and preferred timing of embedded display will have high
++ * priority, so other displays will support it always
++ */
++ FEATURE_DISPLAY_PREFERRED_VIEW = FEATURE_SET_13_END + 1,
++ FEATURE_SET_15_START = FEATURE_DISPLAY_PREFERRED_VIEW,
++ FEATURE_SET_15_END = FEATURE_SET_15_START + 31,
++
++ /* UInt set, 1 entry: DAL optimization */
++ FEATURE_OPTIMIZATION = FEATURE_SET_15_END + 1,
++ FEATURE_SET_16_START = FEATURE_OPTIMIZATION,
++ FEATURE_SET_16_END = FEATURE_SET_16_START + 31,
++
++ /* UInt set, 1 entry: Performance measurement */
++ FEATURE_PERF_MEASURE = FEATURE_SET_16_END + 1,
++ FEATURE_SET_17_START = FEATURE_PERF_MEASURE,
++ FEATURE_SET_17_END = FEATURE_SET_17_START + 31,
++
++ /* UInt set, 1 entry: Minimum backlight value [0-255] */
++ FEATURE_MIN_BACKLIGHT_LEVEL = FEATURE_SET_17_END + 1,
++ FEATURE_SET_18_START = FEATURE_MIN_BACKLIGHT_LEVEL,
++ FEATURE_SET_18_END = FEATURE_SET_18_START + 31,
++
++ /* UInt set, 1 entry: Maximum backlight value [0-255] */
++ FEATURE_MAX_BACKLIGHT_LEVEL = FEATURE_SET_18_END + 1,
++ FEATURE_SET_19_START = FEATURE_MAX_BACKLIGHT_LEVEL,
++ FEATURE_SET_19_END = FEATURE_SET_19_START + 31,
++
++ /* UInt set, 1 entry: AMB setting
++ *
++ * Each byte will control the ABM configuration to use for a specific
++ * ABM level.
++ *
++ * HW team provided 12 different ABM min/max reduction pairs to choose
++ * between for each ABM level.
++ *
++ * ABM level Byte Setting
++ * 1 0 Default = 0 (setting 3), can be override to 1-12
++ * 2 1 Default = 0 (setting 7), can be override to 1-12
++ * 3 2 Default = 0 (setting 8), can be override to 1-12
++ * 4 3 Default = 0 (setting 10), can be override to 1-12
++ *
++ * For example,
++ * FEATURE_PREFERRED_ABM_CONFIG_SET = 0x0C060500, this represents:
++ * ABM level 1 use default setting (setting 3)
++ * ABM level 2 uses setting 5
++ * ABM level 3 uses setting 6
++ * ABM level 4 uses setting 12
++ * Internal use only!
++ */
++ FEATURE_PREFERRED_ABM_CONFIG_SET = FEATURE_SET_19_END + 1,
++ FEATURE_SET_20_START = FEATURE_PREFERRED_ABM_CONFIG_SET,
++ FEATURE_SET_20_END = FEATURE_SET_20_START + 31,
++
++ /* UInt set, 1 entry: Change SW I2C speed */
++ FEATURE_CHANGE_SW_I2C_SPEED = FEATURE_SET_20_END + 1,
++ FEATURE_SET_21_START = FEATURE_CHANGE_SW_I2C_SPEED,
++ FEATURE_SET_21_END = FEATURE_SET_21_START + 31,
++
++ /* UInt set, 1 entry: Change HW I2C speed */
++ FEATURE_CHANGE_HW_I2C_SPEED = FEATURE_SET_21_END + 1,
++ FEATURE_SET_22_START = FEATURE_CHANGE_HW_I2C_SPEED,
++ FEATURE_SET_22_END = FEATURE_SET_22_START + 31,
++
++ /* UInt set, 1 entry:
++ * When PSR issue occurs, it is sometimes hard to debug since the
++ * failure occurs immediately at boot. Use this setting to skip or
++ * postpone PSR functionality and re-enable through DSAT. */
++ FEATURE_DEFAULT_PSR_LEVEL = FEATURE_SET_22_END + 1,
++ FEATURE_SET_23_START = FEATURE_DEFAULT_PSR_LEVEL,
++ FEATURE_SET_23_END = FEATURE_SET_23_START + 31,
++
++ /* UInt set, 1 entry: Allowed pixel clock range for LVDS */
++ FEATURE_LVDS_SAFE_PIXEL_CLOCK_RANGE = FEATURE_SET_23_END + 1,
++ FEATURE_SET_24_START = FEATURE_LVDS_SAFE_PIXEL_CLOCK_RANGE,
++ FEATURE_SET_24_END = FEATURE_SET_24_START + 31,
++
++ /* UInt set, 1 entry: Max number of clock sources */
++ FEATURE_MAX_CLOCK_SOURCE_NUM = FEATURE_SET_24_END + 1,
++ FEATURE_SET_25_START = FEATURE_MAX_CLOCK_SOURCE_NUM,
++ FEATURE_SET_25_END = FEATURE_SET_25_START + 31,
++
++ /* UInt set, 1 entry: Select the ABM configuration to use.
++ *
++ * This feature set is used to allow packaging option to be defined
++ * to allow OEM to select between the default ABM configuration or
++ * alternative predefined configurations that may be more aggressive.
++ *
++ * Note that this regkey is meant for external use to select the
++ * configuration OEM wants. Whereas the other PREFERRED_ABM_CONFIG_SET
++ * key is only used for internal use and allows full reconfiguration.
++ */
++ FEATURE_ABM_CONFIG = FEATURE_SET_25_END + 1,
++ FEATURE_SET_26_START = FEATURE_ABM_CONFIG,
++ FEATURE_SET_26_END = FEATURE_SET_26_START + 31,
++
++ /* UInt set, 1 entry: Select the default speed in which smooth
++ * brightness feature should converge towards target backlight level.
++ *
++ * For example, a setting of 500 means it takes 500ms to transition
++ * from current backlight level to the new requested backlight level.
++ */
++ FEATURE_SMOOTH_BRTN_ADJ_TIME_IN_MS = FEATURE_SET_26_END + 1,
++ FEATURE_SET_27_START = FEATURE_SMOOTH_BRTN_ADJ_TIME_IN_MS,
++ FEATURE_SET_27_END = FEATURE_SET_27_START + 31,
++
++ /* Set 28: UInt set, 1 entry: Allow runtime parameter to force specific
++ * Static Screen Event triggers for test purposes. */
++ FEATURE_FORCE_STATIC_SCREEN_EVENT_TRIGGERS = FEATURE_SET_27_END + 1,
++ FEATURE_SET_28_START = FEATURE_FORCE_STATIC_SCREEN_EVENT_TRIGGERS,
++ FEATURE_SET_28_END = FEATURE_SET_28_START + 31,
++
++ FEATURE_MAXIMUM
++};
++
++/* Adapter Service type of DRR support*/
++enum as_drr_support {
++ AS_DRR_SUPPORT_DISABLED = 0x0,
++ AS_DRR_SUPPORT_ENABLED = 0x1,
++ AS_DRR_SUPPORT_MIN_FORCED_FPS = 0xA
++};
++
++/* Adapter service initialize data structure*/
++struct as_init_data {
++ struct hw_asic_id hw_init_data;
++ struct bp_init_data bp_init_data;
++ struct dc_context *ctx;
++ struct bdf_info bdf_info;
++ const struct dal_override_parameters *display_param;
++};
++
++/* Create adapter service */
++struct adapter_service *dal_adapter_service_create(
++ struct as_init_data *init_data);
++
++/* Destroy adapter service and objects it contains */
++void dal_adapter_service_destroy(
++ struct adapter_service **as);
++
++/* Get the DCE version of current ASIC */
++enum dce_version dal_adapter_service_get_dce_version(
++ const struct adapter_service *as);
++
++/* Get firmware information from BIOS */
++bool dal_adapter_service_get_firmware_info(
++ struct adapter_service *as,
++ struct firmware_info *info);
++
++
++/* functions to get a total number of objects of specific type */
++uint8_t dal_adapter_service_get_connectors_num(
++ struct adapter_service *as);
++
++/* Get number of controllers */
++uint8_t dal_adapter_service_get_controllers_num(
++ struct adapter_service *as);
++
++/* Get number of clock sources */
++uint8_t dal_adapter_service_get_clock_sources_num(
++ struct adapter_service *as);
++
++/* Get number of controllers */
++uint8_t dal_adapter_service_get_func_controllers_num(
++ struct adapter_service *as);
++
++/* Get number of stream engines */
++uint8_t dal_adapter_service_get_stream_engines_num(
++ struct adapter_service *as);
++
++/* functions to get object id based on object index */
++struct graphics_object_id dal_adapter_service_get_connector_obj_id(
++ struct adapter_service *as,
++ uint8_t connector_index);
++
++/* Get number of spread spectrum entries from BIOS */
++uint32_t dal_adapter_service_get_ss_info_num(
++ struct adapter_service *as,
++ enum as_signal_type signal);
++
++/* Get spread spectrum info from BIOS */
++bool dal_adapter_service_get_ss_info(
++ struct adapter_service *as,
++ enum as_signal_type signal,
++ uint32_t idx,
++ struct spread_spectrum_info *info);
++
++/* Check if DFS bypass is enabled */
++bool dal_adapter_service_is_dfs_bypass_enabled(struct adapter_service *as);
++
++/* Get memory controller latency */
++uint32_t dal_adapter_service_get_mc_latency(
++ struct adapter_service *as);
++
++/* Get the video RAM bit width set on the ASIC */
++uint32_t dal_adapter_service_get_asic_vram_bit_width(
++ struct adapter_service *as);
++
++/* Get the bug flags set on this ASIC */
++struct asic_bugs dal_adapter_service_get_asic_bugs(
++ struct adapter_service *as);
++
++/* Get efficiency of DRAM */
++uint32_t dal_adapter_service_get_dram_bandwidth_efficiency(
++ struct adapter_service *as);
++
++/* Get multiplier for the memory type */
++uint32_t dal_adapter_service_get_memory_type_multiplier(
++ struct adapter_service *as);
++
++/* Get parameters for bandwidth tuning */
++bool dal_adapter_service_get_bandwidth_tuning_params(
++ struct adapter_service *as,
++ union bandwidth_tuning_params *params);
++
++/* Get integrated information on BIOS */
++bool dal_adapter_service_get_integrated_info(
++ struct adapter_service *as,
++ struct integrated_info *info);
++
++/* Return if a given feature is supported by the ASIC */
++bool dal_adapter_service_is_feature_supported(
++ enum adapter_feature_id feature_id);
++
++/* Get the cached value of a given feature */
++bool dal_adapter_service_get_feature_value(
++ const enum adapter_feature_id feature_id,
++ void *data,
++ uint32_t size);
++
++/* Get a copy of ASIC feature flags */
++struct asic_feature_flags dal_adapter_service_get_feature_flags(
++ struct adapter_service *as);
++
++/* Obtain DDC */
++struct ddc *dal_adapter_service_obtain_ddc(
++ struct adapter_service *as,
++ struct graphics_object_id id);
++
++/* Release DDC */
++void dal_adapter_service_release_ddc(
++ struct adapter_service *as,
++ struct ddc *ddc);
++
++/* Obtain HPD interrupt request */
++struct irq *dal_adapter_service_obtain_hpd_irq(
++ struct adapter_service *as,
++ struct graphics_object_id id);
++
++/* Release interrupt request */
++void dal_adapter_service_release_irq(
++ struct adapter_service *as,
++ struct irq *irq);
++
++/* Obtain GPIO */
++struct gpio *dal_adapter_service_obtain_gpio(
++ struct adapter_service *as,
++ enum gpio_id id,
++ uint32_t en);
++
++/* Obtain GPIO for stereo3D*/
++struct gpio *dal_adapter_service_obtain_stereo_gpio(struct adapter_service *as);
++
++/* Release GPIO */
++void dal_adapter_service_release_gpio(
++ struct adapter_service *as,
++ struct gpio *gpio);
++
++/* Get SW I2C speed */
++uint32_t dal_adapter_service_get_sw_i2c_speed(struct adapter_service *as);
++
++/* Get HW I2C speed */
++uint32_t dal_adapter_service_get_hw_i2c_speed(struct adapter_service *as);
++
++/* Get line buffer size */
++uint32_t dal_adapter_service_get_line_buffer_size(struct adapter_service *as);
++
++/* Get information on audio support */
++union audio_support dal_adapter_service_get_audio_support(
++ struct adapter_service *as);
++
++/* Get I2C information from BIOS */
++bool dal_adapter_service_get_i2c_info(
++ struct adapter_service *as,
++ struct graphics_object_id id,
++ struct graphics_object_i2c_info *i2c_info);
++
++/* Get bios parser handler */
++struct bios_parser *dal_adapter_service_get_bios_parser(
++ struct adapter_service *as);
++
++/* Get i2c aux handler */
++struct i2caux *dal_adapter_service_get_i2caux(
++ struct adapter_service *as);
++
++struct dal_asic_runtime_flags dal_adapter_service_get_asic_runtime_flags(
++ struct adapter_service *as);
++
++bool dal_adapter_service_initialize_hw_data(
++ struct adapter_service *as);
++
++struct graphics_object_id dal_adapter_service_enum_fake_path_resource(
++ struct adapter_service *as,
++ uint32_t index);
++
++struct graphics_object_id dal_adapter_service_enum_stereo_sync_object(
++ struct adapter_service *as,
++ uint32_t index);
++
++struct graphics_object_id dal_adapter_service_enum_sync_output_object(
++ struct adapter_service *as,
++ uint32_t index);
++
++struct graphics_object_id dal_adapter_service_enum_audio_object(
++ struct adapter_service *as,
++ uint32_t index);
++
++void dal_adapter_service_update_audio_connectivity(
++ struct adapter_service *as,
++ uint32_t number_of_audio_capable_display_path);
++
++bool dal_adapter_service_has_embedded_display_connector(
++ struct adapter_service *as);
++
++bool dal_adapter_service_get_embedded_panel_info(
++ struct adapter_service *as,
++ struct embedded_panel_info *info);
++
++bool dal_adapter_service_enum_embedded_panel_patch_mode(
++ struct adapter_service *as,
++ uint32_t index,
++ struct embedded_panel_patch_mode *mode);
++
++bool dal_adapter_service_get_faked_edid_len(
++ struct adapter_service *as,
++ uint32_t *len);
++
++bool dal_adapter_service_get_faked_edid_buf(
++ struct adapter_service *as,
++ uint8_t *buf,
++ uint32_t len);
++
++uint32_t dal_adapter_service_get_max_cofunc_non_dp_displays(void);
++
++uint32_t dal_adapter_service_get_single_selected_timing_signals(void);
++
++bool dal_adapter_service_get_device_tag(
++ struct adapter_service *as,
++ struct graphics_object_id connector_object_id,
++ uint32_t device_tag_index,
++ struct connector_device_tag_info *info);
++
++bool dal_adapter_service_is_device_id_supported(
++ struct adapter_service *as,
++ struct device_id id);
++
++bool dal_adapter_service_is_meet_underscan_req(struct adapter_service *as);
++
++bool dal_adapter_service_underscan_for_hdmi_only(struct adapter_service *as);
++
++uint32_t dal_adapter_service_get_src_num(
++ struct adapter_service *as,
++ struct graphics_object_id id);
++
++struct graphics_object_id dal_adapter_service_get_src_obj(
++ struct adapter_service *as,
++ struct graphics_object_id id,
++ uint32_t index);
++
++/* Is this Fusion ASIC */
++bool dal_adapter_service_is_fusion(struct adapter_service *as);
++
++/* Is this ASIC support dynamic DFSbypass switch */
++bool dal_adapter_service_is_dfsbyass_dynamic(struct adapter_service *as);
++
++/* Reports whether driver settings allow requested optimization */
++bool dal_adapter_service_should_optimize(
++ struct adapter_service *as, enum optimization_feature feature);
++
++/* Determine if driver is in accelerated mode */
++bool dal_adapter_service_is_in_accelerated_mode(struct adapter_service *as);
++
++struct ddc *dal_adapter_service_obtain_ddc_from_i2c_info(
++ struct adapter_service *as,
++ struct graphics_object_i2c_info *info);
++
++struct bdf_info dal_adapter_service_get_adapter_info(
++ struct adapter_service *as);
++
++
++/* Determine if this ASIC needs to wait on PLL lock bit */
++bool dal_adapter_service_should_psr_skip_wait_for_pll_lock(
++ struct adapter_service *as);
++
++#define SIZEOF_BACKLIGHT_LUT 101
++#define ABSOLUTE_BACKLIGHT_MAX 255
++#define DEFAULT_MIN_BACKLIGHT 12
++#define DEFAULT_MAX_BACKLIGHT 255
++#define BACKLIGHT_CURVE_COEFFB 100
++#define BACKLIGHT_CURVE_COEFFA_FACTOR 10000
++#define BACKLIGHT_CURVE_COEFFB_FACTOR 100
++
++struct panel_backlight_levels {
++ uint32_t ac_level_percentage;
++ uint32_t dc_level_percentage;
++};
++
++bool dal_adapter_service_is_lid_open(struct adapter_service *as);
++
++bool dal_adapter_service_get_panel_backlight_default_levels(
++ struct adapter_service *as,
++ struct panel_backlight_levels *levels);
++
++bool dal_adapter_service_get_panel_backlight_boundaries(
++ struct adapter_service *as,
++ struct panel_backlight_boundaries *boundaries);
++
++uint32_t dal_adapter_service_get_view_port_pixel_granularity(
++ struct adapter_service *as);
++
++uint32_t dal_adapter_service_get_num_of_path_per_dp_mst_connector(
++ struct adapter_service *as);
++
++uint32_t dal_adapter_service_get_num_of_underlays(
++ struct adapter_service *as);
++
++bool dal_adapter_service_get_encoder_cap_info(
++ struct adapter_service *as,
++ struct graphics_object_id id,
++ struct graphics_object_encoder_cap_info *info);
++
++bool dal_adapter_service_is_mc_tuning_req(struct adapter_service *as);
++
++#endif /* __DAL_ADAPTER_SERVICE_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/adapter_service_types.h b/drivers/gpu/drm/amd/dal/include/adapter_service_types.h
+new file mode 100644
+index 0000000..fb47ef3
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/adapter_service_types.h
+@@ -0,0 +1,70 @@
++/*
++ * 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_ADAPTER_SERVICE_TYPES_H__
++#define __DAL_ADAPTER_SERVICE_TYPES_H__
++
++enum as_signal_type {
++ AS_SIGNAL_TYPE_NONE = 0L, /* no signal */
++ AS_SIGNAL_TYPE_DVI,
++ AS_SIGNAL_TYPE_HDMI,
++ AS_SIGNAL_TYPE_LVDS,
++ AS_SIGNAL_TYPE_DISPLAY_PORT,
++ AS_SIGNAL_TYPE_GPU_PLL,
++ AS_SIGNAL_TYPE_UNKNOWN
++};
++
++/*
++ * Struct used for algorithm of Bandwidth tuning parameters
++ * the sequence of the fields is binded with runtime parameter.
++ */
++union bandwidth_tuning_params {
++ struct bandwidth_tuning_params_struct {
++ uint32_t read_delay_stutter_off_usec;
++ uint32_t ignore_hblank_time;/*bool*/
++ uint32_t extra_reordering_latency_usec;
++ uint32_t extra_mc_latency_usec;
++ uint32_t data_return_bandwidth_eff;/*in %*/
++ uint32_t dmif_request_bandwidth_eff;/*in %*/
++ uint32_t sclock_latency_multiplier;/*in unit of 0.01*/
++ uint32_t mclock_latency_multiplier;/*in unit of 0.01*/
++ uint32_t fix_latency_multiplier;/*in unit of 0.01*/
++ /*in unit represent in watermark*/
++ uint32_t use_urgency_watermark_offset;
++ } tuning_info;
++ uint32_t arr_info[sizeof(struct bandwidth_tuning_params_struct)
++ / sizeof(uint32_t)];
++};
++
++union audio_support {
++ struct {
++ uint32_t DP_AUDIO:1;
++ uint32_t HDMI_AUDIO_ON_DONGLE:1;
++ uint32_t HDMI_AUDIO_NATIVE:1;
++ } bits;
++ uint32_t raw;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/adjustment_interface.h b/drivers/gpu/drm/amd/dal/include/adjustment_interface.h
+new file mode 100644
+index 0000000..64a9f9f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/adjustment_interface.h
+@@ -0,0 +1,230 @@
++/*
++ * 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_ADJUSTMENT_INTERFACE_H__
++#define __DAL_ADJUSTMENT_INTERFACE_H__
++
++#include "include/display_service_types.h"
++#include "include/adjustment_types.h"
++#include "include/overlay_types.h"
++#include "include/display_path_interface.h"
++
++struct ds_underscan_desc;
++struct adj_container;
++struct info_frame;
++struct ds_dispatch;
++struct hw_adjustment_set;
++struct path_mode;
++struct hw_path_mode;
++
++enum build_path_set_reason;
++
++bool dal_ds_dispatch_is_adjustment_supported(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ enum adjustment_id adjust_id);
++
++enum ds_return dal_ds_dispatch_get_type(
++ struct ds_dispatch *adj,
++ enum adjustment_id adjust_id,
++ enum adjustment_data_type *type);
++
++enum ds_return dal_ds_dispatch_get_property(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ enum adjustment_id adjust_id,
++ union adjustment_property *property);
++
++enum ds_return dal_ds_dispatch_set_adjustment(
++ struct ds_dispatch *ds,
++ const uint32_t display_index,
++ enum adjustment_id adjust_id,
++ int32_t value);
++
++enum ds_return dal_ds_dispatch_get_adjustment_current_value(
++ struct ds_dispatch *ds,
++ struct adj_container *container,
++ struct adjustment_info *info,
++ enum adjustment_id id,
++ bool fall_back_to_default);
++
++enum ds_return dal_ds_dispatch_get_adjustment_value(
++ struct ds_dispatch *ds,
++ struct display_path *disp_path,
++ enum adjustment_id adj_id,
++ bool fall_back_to_default,
++ int32_t *value);
++
++const struct raw_gamma_ramp *dal_ds_dispatch_get_current_gamma(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ enum adjustment_id adjust_id);
++
++const struct raw_gamma_ramp *dal_ds_dispatch_get_default_gamma(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ enum adjustment_id adjust_id);
++
++enum ds_return dal_ds_dispatch_set_current_gamma(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ enum adjustment_id adjust_id,
++ const struct raw_gamma_ramp *gamma);
++
++enum ds_return dal_ds_dispatch_set_gamma(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ enum adjustment_id adjust_id,
++ const struct raw_gamma_ramp *gamma);
++
++bool dal_ds_dispatch_get_underscan_info(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ struct ds_underscan_info *info);
++
++bool dal_ds_dispatch_get_underscan_mode(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ struct ds_underscan_desc *desc);
++
++bool dal_ds_dispatch_set_underscan_mode(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ struct ds_underscan_desc *desc);
++
++bool dal_ds_dispatch_setup_overlay(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ struct overlay_data *data);
++
++struct adj_container *dal_ds_dispatch_get_adj_container_for_path(
++ const struct ds_dispatch *ds,
++ uint32_t display_index);
++
++void dal_ds_dispatch_set_applicable_adj(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ const struct adj_container *applicable);
++
++enum ds_return dal_ds_dispatch_set_color_gamut(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ const struct ds_set_gamut_data *data);
++
++enum ds_return dal_ds_dispatch_get_color_gamut(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ const struct ds_gamut_reference_data *ref,
++ struct ds_get_gamut_data *data);
++
++enum ds_return dal_ds_dispatch_get_color_gamut_info(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ const struct ds_gamut_reference_data *ref,
++ struct ds_gamut_info *data);
++
++enum ds_return dal_ds_dispatch_get_regamma_lut(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ struct ds_regamma_lut *data);
++
++enum ds_return dal_ds_dispatch_set_regamma_lut(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ struct ds_regamma_lut *data);
++
++enum ds_return dal_ds_dispatch_set_info_packets(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ const struct info_frame *info_frames);
++
++enum ds_return dal_ds_dispatch_get_info_packets(
++ struct ds_dispatch *adj,
++ uint32_t display_index,
++ struct info_frame *info_frames);
++
++bool dal_ds_dispatch_initialize_adjustment(struct ds_dispatch *ds);
++
++void dal_ds_dispatch_cleanup_adjustment(struct ds_dispatch *ds);
++
++bool dal_ds_dispatch_build_post_set_mode_adj(
++ struct ds_dispatch *ds,
++ const struct path_mode *mode,
++ struct display_path *display_path,
++ struct hw_adjustment_set *set);
++
++bool dal_ds_dispatch_build_color_control_adj(
++ struct ds_dispatch *ds,
++ const struct path_mode *mode,
++ struct display_path *display_path,
++ struct hw_adjustment_set *set);
++
++bool dal_ds_dispatch_build_include_adj(
++ struct ds_dispatch *ds,
++ const struct path_mode *mode,
++ struct display_path *display_path,
++ struct hw_path_mode *hw_mode,
++ struct hw_adjustment_set *set);
++
++bool dal_ds_dispatch_apply_scaling(
++ struct ds_dispatch *ds,
++ const struct path_mode *mode,
++ struct adj_container *adj_container,
++ enum build_path_set_reason reason,
++ struct hw_path_mode *hw_mode);
++
++void dal_ds_dispatch_update_adj_container_for_path_with_mode_info(
++ struct ds_dispatch *ds,
++ struct display_path *display_path,
++ const struct path_mode *path_mode);
++
++enum ds_return dal_ds_dispatch_get_adjustment_info(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ enum adjustment_id adjust_id,
++ struct adjustment_info *adj_info);
++
++bool dal_ds_dispatch_include_adjustment(
++ struct ds_dispatch *ds,
++ struct display_path *disp_path,
++ struct ds_adj_id_value adj,
++ struct hw_adjustment_set *set);
++
++enum ds_return dal_ds_dispatch_set_gamma_adjustment(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ enum adjustment_id ad_id,
++ const struct raw_gamma_ramp *gamma);
++
++void dal_ds_dispatch_update_adj_container_for_path_with_color_space(
++ struct ds_dispatch *ds,
++ uint32_t display_index,
++ enum ds_color_space color_space);
++
++void dal_ds_dispatch_setup_default_regamma(
++ struct ds_dispatch *ds,
++ struct ds_regamma_lut *regamma);
++
++#endif /* __DAL_ADJUSTMENT_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/adjustment_types.h b/drivers/gpu/drm/amd/dal/include/adjustment_types.h
+new file mode 100644
+index 0000000..f6c0d61
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/adjustment_types.h
+@@ -0,0 +1,420 @@
++/*
++ * 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_ADJUSTMENT_TYPES_H__
++#define __DAL_ADJUSTMENT_TYPES_H__
++
++#include "dal_services.h"
++
++/* make sure to update this when updating adj_global_info_array */
++#define CURRENT_ADJUSTMENT_NUM 12
++#define MAX_ADJUSTMENT_NUM (ADJ_ID_END - ADJ_ID_BEGIN)
++#define REGAMMA_VALUE 256
++#define REGAMMA_RANGE (REGAMMA_VALUE*3)
++#define ADJUST_DIVIDER 100
++#define GAMUT_DIVIDER 10000
++
++
++enum adjustment_id {
++
++ /*this useful type when i need to indicate unknown adjustment and code
++ look if not the specific type*/
++ ADJ_ID_INVALID,
++
++ ADJ_ID_CONTRAST,
++ ADJ_ID_BRIGHTNESS,
++ ADJ_ID_HUE,
++ ADJ_ID_SATURATION,
++ ADJ_ID_GAMMA_RAMP,
++ ADJ_ID_GAMMA_RAMP_REGAMMA_UPDATE,
++ ADJ_ID_TEMPERATURE,
++ ADJ_ID_NOMINAL_RANGE_RGB_LIMITED,
++
++ ADJ_ID_LP_FILTER_DEFLICKER,
++ ADJ_ID_HP_FILTER_DEFLICKER,
++ ADJ_ID_SHARPNESS_GAIN, /*0 - 10*/
++
++ ADJ_ID_REDUCED_BLANKING,
++ ADJ_ID_COHERENT,
++ ADJ_ID_MULTIMEDIA_PASS_THROUGH,
++
++ ADJ_ID_VERTICAL_POSITION,
++ ADJ_ID_HORIZONTA_LPOSITION,
++ ADJ_ID_VERTICAL_SIZE,
++ ADJ_ID_HORIZONTAL_SIZE,
++ ADJ_ID_VERTICAL_SYNC,
++ ADJ_ID_HORIZONTAL_SYNC,
++ ADJ_ID_OVERSCAN,
++ ADJ_ID_COMPOSITE_SYNC,
++
++ ADJ_ID_BIT_DEPTH_REDUCTION,/*CWDDEDI_DISPLAY_ADJINFOTYPE_BITVECTOR*/
++ ADJ_ID_UNDERSCAN,/*CWDDEDI_DISPLAY_ADJINFOTYPE_RANGE*/
++ ADJ_ID_UNDERSCAN_TYPE,/*CWDDEDI_DISPLAY_ADJINFOTYPE_RANGE*/
++ ADJ_ID_TEMPERATURE_SOURCE,/*CWDDEDI_DISPLAY_ADJINFOTYPE_BITVECTOR*/
++
++ ADJ_ID_OVERLAY_BRIGHTNESS,
++ ADJ_ID_OVERLAY_CONTRAST,
++ ADJ_ID_OVERLAY_SATURATION,
++ ADJ_ID_OVERLAY_HUE,
++ ADJ_ID_OVERLAY_GAMMA,
++ ADJ_ID_OVERLAY_ALPHA,
++ ADJ_ID_OVERLAY_ALPHA_PER_PIX,
++ ADJ_ID_OVERLAY_INV_GAMMA,
++ ADJ_ID_OVERLAY_TEMPERATURE,/*done ,but code is commented*/
++ ADJ_ID_OVERLAY_NOMINAL_RANGE_RGB_LIMITED,
++
++
++ ADJ_ID_UNDERSCAN_TV_INTERNAL,/*internal usage only for HDMI*/
++ /*custom TV modes*/
++ ADJ_ID_DRIVER_REQUESTED_GAMMA,/*used to get current gamma*/
++ ADJ_ID_GAMUT_SOURCE_GRPH,/*logical adjustment visible for DS and CDB*/
++ ADJ_ID_GAMUT_SOURCE_OVL,/*logical adjustment visible for DS and CDB*/
++ ADJ_ID_GAMUT_DESTINATION,/*logical adjustment visible for DS and CDB*/
++ ADJ_ID_REGAMMA,/*logical adjustment visible for DS and CDB*/
++ ADJ_ID_ITC_ENABLE,/*ITC flag enable by default*/
++ ADJ_ID_CNC_CONTENT,/*display image content*/
++ /*internal adjustment, in order to provide backward compatibility
++ gamut with color temperature*/
++
++ /* Backlight Adjustment Group*/
++ ADJ_ID_BACKLIGHT,
++ ADJ_ID_BACKLIGHT_OPTIMIZATION,
++
++ /* flag the first and last*/
++ ADJ_ID_BEGIN = ADJ_ID_CONTRAST,
++ ADJ_ID_END = ADJ_ID_BACKLIGHT_OPTIMIZATION,
++};
++
++enum adjustment_data_type {
++ ADJ_RANGED,
++ ADJ_BITVECTOR,
++ ADJ_LUT /* not handled currently */
++};
++
++union adjustment_property {
++ uint32_t u32all;
++ struct {
++ /*per mode adjustment*/
++ uint32_t SAVED_WITHMODE:1;
++ /*per edid adjustment*/
++ uint32_t SAVED_WITHEDID:1;
++ /*adjustment not visible to HWSS*/
++ uint32_t CALCULATE:1;
++ /*explisit adjustment applied by HWSS*/
++ uint32_t INC_IN_SET_MODE:1;
++ /*adjustment requires set mode to be applied*/
++ uint32_t SETMODE_REQ:1;
++ /*adjustment is applied at the end of set mode*/
++ uint32_t POST_SET:1;
++/*when adjustment is applied its value should be stored
++in place and not wait for flush call*/
++ uint32_t SAVE_IN_PLACE:1;
++ /*adjustment is always apply*/
++ uint32_t FORCE_SET:1;
++ /*this adjustment is specific to individual display path.*/
++ uint32_t SAVED_WITH_DISPLAY_IDX:1;
++ uint32_t RESERVED_23:23;
++ } bits;
++};
++
++enum adjustment_state {
++ ADJUSTMENT_STATE_INVALID,
++ ADJUSTMENT_STATE_VALID,
++ ADJUSTMENT_STATE_REQUESTED,
++ ADJUSTMENT_STATE_COMMITTED_TO_HW,
++};
++
++/* AdjustmentInfo structure - it keeps either ranged data or discrete*/
++struct adjustment_info {
++ enum adjustment_data_type adj_data_type;
++ union adjustment_property adj_prop;
++ enum adjustment_state adj_state;
++ enum adjustment_id adj_id;
++
++ union data {
++ struct ranged {
++ int32_t min;
++ int32_t max;
++ int32_t def;
++ int32_t step;
++ int32_t cur;
++ } ranged;
++ struct bit_vector {
++ int32_t system_supported;
++ int32_t current_supported;
++ int32_t default_val;
++ } bit_vector;
++ } adj_data;
++};
++
++/* adjustment category
++this should be a MASK struct with the bitfileds!!!
++since it could be crt and cv and dfp!!!
++the only fit is for overlay!!!*/
++enum adjustment_category {
++ CAT_ALL,
++ CAT_CRT,
++ CAT_DFP,
++ CAT_LCD,
++ CAT_OVERLAY,
++ CAT_INVALID
++};
++
++enum raw_gamma_ramp_type {
++ GAMMA_RAMP_TYPE_UNINITIALIZED,
++ GAMMA_RAMP_TYPE_DEFAULT,
++ GAMMA_RAMP_TYPE_RGB256,
++ GAMMA_RAMP_TYPE_FIXED_POINT
++};
++
++struct raw_gamma_ramp_rgb {
++ uint32_t red;
++ uint32_t green;
++ uint32_t blue;
++};
++
++#define NUM_OF_RAW_GAMMA_RAMP_RGB_256 256
++struct raw_gamma_ramp {
++ enum raw_gamma_ramp_type type;
++ struct raw_gamma_ramp_rgb rgb_256[NUM_OF_RAW_GAMMA_RAMP_RGB_256];
++ uint32_t size;
++};
++
++struct ds_underscan_info {
++ uint32_t default_width;
++ uint32_t default_height;
++ uint32_t max_width;
++ uint32_t max_height;
++ uint32_t min_width;
++ uint32_t min_height;
++ uint32_t h_step;
++ uint32_t v_step;
++ uint32_t default_x_pos;
++ uint32_t default_y_pos;
++};
++
++struct ds_overscan {
++ uint32_t left;
++ uint32_t right;
++ uint32_t top;
++ uint32_t bottom;
++};
++
++enum ds_color_space {
++ DS_COLOR_SPACE_UNKNOWN = 0,
++ DS_COLOR_SPACE_SRGB_FULLRANGE = 1,
++ DS_COLOR_SPACE_SRGB_LIMITEDRANGE,
++ DS_COLOR_SPACE_YPBPR601,
++ DS_COLOR_SPACE_YPBPR709,
++ DS_COLOR_SPACE_YCBCR601,
++ DS_COLOR_SPACE_YCBCR709,
++ DS_COLOR_SPACE_NMVPU_SUPERAA,
++ DS_COLOR_SPACE_YCBCR601_YONLY,
++ DS_COLOR_SPACE_YCBCR709_YONLY/*same as YCbCr, but Y in Full range*/
++};
++
++enum ds_underscan_options {
++ DS_UNDERSCAN_OPTION_DEFAULT = 0,
++ DS_UNDERSCAN_OPTION_USECEA861D
++};
++
++enum dpms_state {
++ DPMS_NONE = 0,
++ DPMS_ON,
++ DPMS_OFF,
++};
++
++enum ds_gamut_reference {
++ DS_GAMUT_REFERENCE_DESTINATION = 0,
++ DS_GAMUT_REFERENCE_SOURCE,
++};
++
++enum ds_gamut_content {
++ DS_GAMUT_CONTENT_GRAPHICS = 0,
++ DS_GAMUT_CONTENT_VIDEO,
++};
++
++struct ds_gamut_reference_data {
++ enum ds_gamut_reference gamut_ref;
++ enum ds_gamut_content gamut_content;
++};
++
++union ds_custom_gamut_type {
++ uint32_t u32all;
++ struct {
++ uint32_t CUSTOM_WHITE_POINT:1;
++ uint32_t CUSTOM_GAMUT_SPACE:1;
++ uint32_t reserved:30;
++ } bits;
++};
++
++union ds_gamut_spaces {
++ uint32_t u32all;
++ struct {
++ uint32_t GAMUT_SPACE_CCIR709:1;
++ uint32_t GAMUT_SPACE_CCIR601:1;
++ uint32_t GAMUT_SPACE_ADOBERGB:1;
++ uint32_t GAMUT_SPACE_CIERGB:1;
++ uint32_t GAMUT_SPACE_CUSTOM:1;
++ uint32_t reserved:27;
++ } bits;
++};
++
++union ds_gamut_white_point {
++ uint32_t u32all;
++ struct {
++ uint32_t GAMUT_WHITE_POINT_5000:1;
++ uint32_t GAMUT_WHITE_POINT_6500:1;
++ uint32_t GAMUT_WHITE_POINT_7500:1;
++ uint32_t GAMUT_WHITE_POINT_9300:1;
++ uint32_t GAMUT_WHITE_POINT_CUSTOM:1;
++ uint32_t reserved:27;
++ } bits;
++};
++
++struct ds_gamut_space_coordinates {
++ int32_t red_x;
++ int32_t red_y;
++ int32_t green_x;
++ int32_t green_y;
++ int32_t blue_x;
++ int32_t blue_y;
++
++};
++
++struct ds_white_point_coordinates {
++ int32_t white_x;
++ int32_t white_y;
++};
++
++struct ds_gamut_data {
++ union ds_custom_gamut_type feature;
++ union {
++ uint32_t predefined;
++ struct ds_white_point_coordinates custom;
++
++ } white_point;
++
++ union {
++ uint32_t predefined;
++ struct ds_gamut_space_coordinates custom;
++
++ } gamut;
++};
++
++struct ds_set_gamut_data {
++ struct ds_gamut_reference_data ref;
++ struct ds_gamut_data gamut;
++
++};
++
++struct ds_get_gamut_data {
++ struct ds_gamut_data gamut;
++};
++
++struct ds_gamut_info {
++/*mask of supported predefined gamuts ,started from DI_GAMUT_SPACE_CCIR709 ...*/
++ union ds_gamut_spaces gamut_space;
++/*mask of supported predefined white points,started from DI_WHITE_POINT_5000K */
++ union ds_gamut_white_point white_point;
++
++};
++
++union ds_regamma_flags {
++ uint32_t u32all;
++ struct {
++ /*custom/user gamam array is in use*/
++ uint32_t GAMMA_RAMP_ARRAY:1;
++ /*gamma from edid is in use*/
++ uint32_t GAMMA_FROM_EDID:1;
++ /*gamma from edid is in use , but only for Display Id 1.2*/
++ uint32_t GAMMA_FROM_EDID_EX:1;
++ /*user custom gamma is in use*/
++ uint32_t GAMMA_FROM_USER:1;
++ /*coeff. A0-A3 from user is in use*/
++ uint32_t COEFF_FROM_USER:1;
++ /*coeff. A0-A3 from edid is in use only for Display Id 1.2*/
++ uint32_t COEFF_FROM_EDID:1;
++ /*which ROM to choose for graphics*/
++ uint32_t GRAPHICS_DEGAMMA_SRGB:1;
++ /*which ROM to choose for video overlay*/
++ uint32_t OVERLAY_DEGAMMA_SRGB:1;
++ /*apply degamma removal in driver*/
++ uint32_t APPLY_DEGAMMA:1;
++
++ uint32_t reserved:23;
++ } bits;
++};
++
++struct ds_regamma_ramp {
++ uint16_t gamma[256 * 3]; /* gamma ramp packed as RGB */
++
++};
++
++struct ds_regamma_coefficients_ex {
++ int32_t gamma[3];/*2400 use divider 1 000*/
++ int32_t coeff_a0[3];/*31308 divider 10 000 000,0-red, 1-green, 2-blue*/
++ int32_t coeff_a1[3];/*12920 use divider 1 000*/
++ int32_t coeff_a2[3];/*55 use divider 1 000*/
++ int32_t coeff_a3[3];/*55 use divider 1 000*/
++};
++
++struct ds_regamma_lut {
++ union ds_regamma_flags flags;
++ union {
++ struct ds_regamma_ramp gamma;
++ struct ds_regamma_coefficients_ex coeff;
++ };
++};
++
++enum ds_backlight_optimization {
++ DS_BACKLIGHT_OPTIMIZATION_DISABLE = 0,
++ DS_BACKLIGHT_OPTIMIZATION_DESKTOP,
++ DS_BACKLIGHT_OPTIMIZATION_DYNAMIC,
++ DS_BACKLIGHT_OPTIMIZATION_DIMMED
++};
++
++struct ds_adj_id_value {
++ enum adjustment_id adj_id;
++ enum adjustment_data_type adj_type;
++ union adjustment_property adj_prop;
++ int32_t value;
++};
++
++struct gamut_data {
++ union ds_custom_gamut_type option;
++ union {
++ union ds_gamut_white_point predefined;
++ struct ds_white_point_coordinates custom;
++
++ } white_point;
++
++ union {
++ union ds_gamut_spaces predefined;
++ struct ds_gamut_space_coordinates custom;
++
++ } gamut;
++};
++#endif /* __DAL_ADJUSTMENT_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/asic_capability_interface.h b/drivers/gpu/drm/amd/dal/include/asic_capability_interface.h
+new file mode 100644
+index 0000000..bdeaaf9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/asic_capability_interface.h
+@@ -0,0 +1,58 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of enc 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 enc 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_ASIC_CAPABILITY_INTERFACE_H__
++#define __DAL_ASIC_CAPABILITY_INTERFACE_H__
++
++/* Include */
++#include "include/asic_capability_types.h"
++
++/* Forward declaration */
++struct hw_asic_id;
++
++
++/* ASIC capability */
++struct asic_capability {
++ struct dc_context *ctx;
++ struct asic_caps caps;
++ struct asic_stereo_3d_caps stereo_3d_caps;
++ struct asic_bugs bugs;
++ struct dal_asic_runtime_flags runtime_flags;
++ uint32_t data[ASIC_DATA_MAX_NUMBER];
++};
++
++
++/**
++ * Interfaces
++ */
++
++/* Create and initialize ASIC capability */
++struct asic_capability *dal_asic_capability_create(struct hw_asic_id *init,
++ struct dc_context *ctx);
++
++/* Destroy ASIC capability and free memory space */
++void dal_asic_capability_destroy(struct asic_capability **cap);
++
++#endif /* __DAL_ASIC_CAPABILITY_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/asic_capability_types.h b/drivers/gpu/drm/amd/dal/include/asic_capability_types.h
+new file mode 100644
+index 0000000..1cb9776
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/asic_capability_types.h
+@@ -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
++ *
++ */
++#ifndef __DAL_ASIC_CAPABILITY_TYPES_H__
++#define __DAL_ASIC_CAPABILITY_TYPES_H__
++
++/*
++ * ASIC Capabilities
++ */
++struct asic_caps {
++ bool CONSUMER_SINGLE_SELECTED_TIMING:1;
++ bool UNDERSCAN_ADJUST:1;
++ bool DELTA_SIGMA_SUPPORT:1;
++ bool PANEL_SELF_REFRESH_SUPPORTED:1;
++ bool IS_FUSION:1;
++ bool DP_MST_SUPPORTED:1;
++ bool UNDERSCAN_FOR_HDMI_ONLY:1;
++ bool DVI_CLOCK_SHARE_CAPABILITY:1;
++ bool SUPPORT_CEA861E_FINAL:1;
++ bool MIRABILIS_SUPPORTED:1;
++ bool MIRABILIS_ENABLED_BY_DEFAULT:1;
++ bool DEVICE_TAG_REMAP_SUPPORTED:1;
++ bool HEADLESS_NO_OPM_SUPPORTED:1;
++ bool WIRELESS_LIMIT_TO_720P:1;
++ bool WIRELESS_FULL_TIMING_ADJUSTMENT:1;
++ bool WIRELESS_TIMING_ADJUSTMENT:1;
++ bool WIRELESS_COMPRESSED_AUDIO:1;
++ bool VCE_SUPPORTED:1;
++ bool HPD_CHECK_FOR_EDID:1;
++ bool NO_VCC_OFF_HPD_POLLING:1;
++ bool NEED_MC_TUNING:1;
++ bool SKIP_PSR_WAIT_FOR_PLL_LOCK_BIT:1;
++ bool DFSBYPASS_DYNAMIC_SUPPORT:1;
++ bool SUPPORT_8BPP:1;
++};
++
++
++/*
++ * ASIC Stereo 3D Caps
++ */
++struct asic_stereo_3d_caps {
++ bool SUPPORTED:1;
++ bool DISPLAY_BASED_ON_WS:1;
++ bool HDMI_FRAME_PACK:1;
++ bool INTERLACE_FRAME_PACK:1;
++ bool DISPLAYPORT_FRAME_PACK:1;
++ bool DISPLAYPORT_FRAME_ALT:1;
++ bool INTERLEAVE:1;
++};
++
++
++/*
++ * ASIC Bugs
++ */
++struct asic_bugs {
++ bool MST_SYMBOL_MISALIGNMENT:1;
++ bool PSR_2X_LANE_GANGING:1;
++ bool LB_WA_IS_SUPPORTED:1;
++ bool ROM_REGISTER_ACCESS:1;
++ bool PSR_WA_OVERSCAN_CRC_ERROR:1;
++};
++
++
++/*
++ * ASIC Data
++ */
++enum asic_data {
++ ASIC_DATA_FIRST = 0,
++ ASIC_DATA_CONTROLLERS_NUM = ASIC_DATA_FIRST,
++ ASIC_DATA_FUNCTIONAL_CONTROLLERS_NUM,
++ ASIC_DATA_DCE_VERSION,
++ ASIC_DATA_DCE_VERSION_MINOR,
++ ASIC_DATA_VRAM_TYPE,
++ ASIC_DATA_VRAM_BITWIDTH,
++ ASIC_DATA_FEATURE_FLAGS,
++ ASIC_DATA_LINEBUFFER_NUM,
++ ASIC_DATA_LINEBUFFER_SIZE,
++ ASIC_DATA_DRAM_BANDWIDTH_EFFICIENCY,
++ ASIC_DATA_MC_LATENCY,
++ ASIC_DATA_MC_LATENCY_SLOW,
++ ASIC_DATA_CLOCKSOURCES_NUM,
++ ASIC_DATA_MEMORYTYPE_MULTIPLIER,
++ ASIC_DATA_STUTTERMODE,
++ ASIC_DATA_PATH_NUM_PER_DPMST_CONNECTOR,
++ ASIC_DATA_MAX_COFUNC_NONDP_DISPLAYS,
++ ASIC_DATA_REVISION_ID,
++ ASIC_DATA_MAX_UNDERSCAN_PERCENTAGE,
++ ASIC_DATA_VIEWPORT_PIXEL_GRANULARITY,
++ ASIC_DATA_DIGFE_NUM,
++ ASIC_DATA_SUPPORTED_HDMI_CONNECTION_NUM,
++ ASIC_DATA_MIN_DISPCLK_FOR_UNDERSCAN,
++ ASIC_DATA_NUM_OF_VIDEO_PLANES,
++ ASIC_DATA_DEFAULT_I2C_SPEED_IN_KHZ,
++ ASIC_DATA_MAX_NUMBER /* end of enum */
++};
++
++
++/*
++ * ASIC Feature Flags
++ */
++struct asic_feature_flags {
++ union {
++ uint32_t raw;
++ struct {
++ uint32_t LEGACY_CLIENT:1;
++ uint32_t PACKED_PIXEL_FORMAT:1;
++ uint32_t WORKSTATION_STEREO:1;
++ uint32_t WORKSTATION:1;
++ } bits;
++ };
++};
++
++#endif /* __DAL_ASIC_CAPABILITY_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/audio_interface.h b/drivers/gpu/drm/amd/dal/include/audio_interface.h
+new file mode 100644
+index 0000000..bf21762
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/audio_interface.h
+@@ -0,0 +1,184 @@
++/*
++ * 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_AUDIO_INTERFACE_H__
++#define __DAL_AUDIO_INTERFACE_H__
++
++#include "audio_types.h"
++#include "adapter_service_interface.h"
++#include "signal_types.h"
++#include "link_service_types.h"
++
++/* forward declaration */
++struct audio;
++struct dal_adapter_service;
++
++/***** audio initialization data *****/
++/*
++ * by audio, it means audio endpoint id. ASIC may have many endpoints.
++ * upper sw layer will create one audio object instance for each endpoints.
++ * ASIC support internal audio only. So enum number is used to differ
++ * each endpoint
++ */
++struct audio_init_data {
++ struct adapter_service *as;
++ struct graphics_object_id audio_stream_id;
++ struct dc_context *ctx;
++};
++
++enum audio_result {
++ AUDIO_RESULT_OK,
++ AUDIO_RESULT_ERROR,
++};
++
++/****** audio object create, destroy ******/
++struct audio *dal_audio_create(
++ const struct audio_init_data *init_data);
++
++void dal_audio_destroy(
++ struct audio **audio);
++
++/****** graphics object interface ******/
++const struct graphics_object_id dal_audio_get_graphics_object_id(
++ const struct audio *audio);
++
++/* Enumerate Graphics Object supported Input/Output Signal Types */
++uint32_t dal_audio_enumerate_input_signals(
++ struct audio *audio);
++
++uint32_t dal_audio_enumerate_output_signals(
++ struct audio *audio);
++
++/* Check if signal supported by GraphicsObject */
++bool dal_audio_is_input_signal_supported(
++ struct audio *audio,
++ enum signal_type signal);
++
++bool dal_audio_is_output_signal_supported(
++ struct audio *audio,
++ enum signal_type signal);
++
++
++/***** programming interface *****/
++
++/* perform power up sequence (boot up, resume, recovery) */
++enum audio_result dal_audio_power_up(
++ struct audio *audio);
++
++/* perform power down (shut down, stand by) */
++enum audio_result dal_audio_power_down(
++ struct audio *audio);
++
++/* setup audio */
++enum audio_result dal_audio_setup(
++ struct audio *audio,
++ struct audio_output *output,
++ struct audio_info *info);
++
++/* enable audio */
++enum audio_result dal_audio_enable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal);
++
++/* disable audio */
++enum audio_result dal_audio_disable_output(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal);
++
++/* enable azalia audio endpoint */
++enum audio_result dal_audio_enable_azalia_audio_jack_presence(
++ struct audio *audio,
++ enum engine_id engine_id);
++
++/* disable azalia audio endpoint */
++enum audio_result dal_audio_disable_azalia_audio_jack_presence(
++ struct audio *audio,
++ enum engine_id engine_id);
++
++/* unmute audio */
++enum audio_result dal_audio_unmute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal);
++
++/* mute audio */
++enum audio_result dal_audio_mute(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal);
++
++
++/***** information interface *****/
++
++struct audio_feature_support dal_audio_get_supported_features(
++ struct audio *audio);
++
++/* get audio bandwidth information */
++void dal_audio_check_audio_bandwidth(
++ struct audio *audio,
++ const struct audio_crtc_info *info,
++ uint32_t channel_count,
++ enum signal_type signal,
++ union audio_sample_rates *sample_rates);
++
++/* Enable multi channel split */
++void dal_audio_enable_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ enum signal_type signal,
++ const struct audio_channel_associate_info *audio_mapping,
++ bool enable);
++
++/* get current multi channel split. */
++enum audio_result dal_audio_get_channel_splitting_mapping(
++ struct audio *audio,
++ enum engine_id engine_id,
++ struct audio_channel_associate_info *audio_mapping);
++
++/* set payload value for the unsolicited response */
++void dal_audio_set_unsolicited_response_payload(
++ struct audio *audio,
++ enum audio_payload payload);
++
++/*Assign GTC group and enable GTC value embedding*/
++void dal_audio_enable_gtc_embedding_with_group(
++ struct audio *audio,
++ uint32_t group_num,
++ uint32_t audio_latency);
++
++/* Disable GTC value embedding */
++void dal_audio_disable_gtc_embedding(
++ struct audio *audio);
++
++/* Update audio wall clock source */
++void dal_audio_setup_audio_wall_dto(
++ struct audio *audio,
++ enum signal_type signal,
++ const struct audio_crtc_info *crtc_info,
++ const struct audio_pll_info *pll_info);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/audio_types.h b/drivers/gpu/drm/amd/dal/include/audio_types.h
+new file mode 100644
+index 0000000..e9c2ab3
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/audio_types.h
+@@ -0,0 +1,275 @@
++/*
++ * 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 __AUDIO_TYPES_H__
++#define __AUDIO_TYPES_H__
++
++#include "grph_object_defs.h"
++#include "signal_types.h"
++
++#define AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS 20
++#define MAX_HW_AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS 18
++#define MULTI_CHANNEL_SPLIT_NO_ASSO_INFO 0xFFFFFFFF
++
++
++struct audio_pll_hw_settings {
++ uint32_t feed_back_divider;
++ uint32_t step_size_integer;
++ uint32_t step_size_fraction;
++ uint32_t step_range;
++};
++
++struct audio_clock_info {
++ /* pixel clock frequency*/
++ uint32_t pixel_clock_in_10khz;
++ /* N - 32KHz audio */
++ uint32_t n_32khz;
++ /* CTS - 32KHz audio*/
++ uint32_t cts_32khz;
++ uint32_t n_44khz;
++ uint32_t cts_44khz;
++ uint32_t n_48khz;
++ uint32_t cts_48khz;
++};
++
++struct azalia_clock_info {
++ uint32_t pixel_clock_in_10khz;
++ uint32_t audio_dto_phase;
++ uint32_t audio_dto_module;
++ uint32_t audio_dto_wall_clock_ratio;
++};
++
++enum audio_dto_source {
++ DTO_SOURCE_UNKNOWN = 0,
++ DTO_SOURCE_ID0,
++ DTO_SOURCE_ID1,
++ DTO_SOURCE_ID2,
++ DTO_SOURCE_ID3,
++ DTO_SOURCE_ID4,
++ DTO_SOURCE_ID5
++};
++
++union audio_sample_rates {
++ struct sample_rates {
++ uint8_t RATE_32:1;
++ uint8_t RATE_44_1:1;
++ uint8_t RATE_48:1;
++ uint8_t RATE_88_2:1;
++ uint8_t RATE_96:1;
++ uint8_t RATE_176_4:1;
++ uint8_t RATE_192:1;
++ } rate;
++
++ uint8_t all;
++};
++
++enum audio_format_code {
++ AUDIO_FORMAT_CODE_FIRST = 1,
++ AUDIO_FORMAT_CODE_LINEARPCM = AUDIO_FORMAT_CODE_FIRST,
++
++ AUDIO_FORMAT_CODE_AC3,
++ /*Layers 1 & 2 */
++ AUDIO_FORMAT_CODE_MPEG1,
++ /*MPEG1 Layer 3 */
++ AUDIO_FORMAT_CODE_MP3,
++ /*multichannel */
++ AUDIO_FORMAT_CODE_MPEG2,
++ AUDIO_FORMAT_CODE_AAC,
++ AUDIO_FORMAT_CODE_DTS,
++ AUDIO_FORMAT_CODE_ATRAC,
++ AUDIO_FORMAT_CODE_1BITAUDIO,
++ AUDIO_FORMAT_CODE_DOLBYDIGITALPLUS,
++ AUDIO_FORMAT_CODE_DTS_HD,
++ AUDIO_FORMAT_CODE_MAT_MLP,
++ AUDIO_FORMAT_CODE_DST,
++ AUDIO_FORMAT_CODE_WMAPRO,
++ AUDIO_FORMAT_CODE_LAST,
++ AUDIO_FORMAT_CODE_COUNT =
++ AUDIO_FORMAT_CODE_LAST - AUDIO_FORMAT_CODE_FIRST
++};
++
++struct audio_mode {
++ /* ucData[0] [6:3] */
++ enum audio_format_code format_code;
++ /* ucData[0] [2:0] */
++ uint8_t channel_count;
++ /* ucData[1] */
++ union audio_sample_rates sample_rates;
++ union {
++ /* for LPCM */
++ uint8_t sample_size;
++ /* for Audio Formats 2-8 (Max bit rate divided by 8 kHz) */
++ uint8_t max_bit_rate;
++ /* for Audio Formats 9-15 */
++ uint8_t vendor_specific;
++ };
++};
++
++struct audio_info_flags {
++
++ union {
++
++ struct audio_speaker_flags {
++ uint32_t FL_FR:1;
++ uint32_t LFE:1;
++ uint32_t FC:1;
++ uint32_t RL_RR:1;
++ uint32_t RC:1;
++ uint32_t FLC_FRC:1;
++ uint32_t RLC_RRC:1;
++ uint32_t SUPPORT_AI:1;
++ } speaker_flags;
++
++ struct audio_speaker_info {
++ uint32_t ALLSPEAKERS:7;
++ uint32_t SUPPORT_AI:1;
++ } info;
++
++ uint8_t all;
++ };
++};
++
++
++/*struct audio_info_flags {
++ struct audio_speaker_flags {
++ uint32_t FL_FR:1;
++ uint32_t LFE:1;
++ uint32_t FC:1;
++ uint32_t RL_RR:1;
++ uint32_t RC:1;
++ uint32_t FLC_FRC:1;
++ uint32_t RLC_RRC:1;
++ uint32_t SUPPORT_AI:1;
++ };
++
++ struct audio_speaker_info {
++ uint32_t ALLSPEAKERS:7;
++ uint32_t SUPPORT_AI:1;
++ };
++
++ union {
++ struct audio_speaker_flags speaker_flags;
++ struct audio_speaker_info info;
++ };
++};
++*/
++
++union audio_cea_channels {
++ uint8_t all;
++ struct audio_cea_channels_bits {
++ uint32_t FL:1;
++ uint32_t FR:1;
++ uint32_t LFE:1;
++ uint32_t FC:1;
++ uint32_t RL_RC:1;
++ uint32_t RR:1;
++ uint32_t RC_RLC_FLC:1;
++ uint32_t RRC_FRC:1;
++ } channels;
++};
++
++struct audio_info {
++ struct audio_info_flags flags;
++ uint32_t video_latency;
++ uint32_t audio_latency;
++ uint32_t display_index;
++ uint8_t display_name[AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS];
++ uint32_t manufacture_id;
++ uint32_t product_id;
++ /* PortID used for ContainerID when defined */
++ uint32_t port_id[2];
++ uint32_t mode_count;
++ /* this field must be last in this struct */
++ struct audio_mode modes[DC_MAX_AUDIO_DESC_COUNT];
++};
++
++struct audio_crtc_info {
++ uint32_t h_total;
++ uint32_t h_active;
++ uint32_t v_active;
++ uint32_t pixel_repetition;
++ uint32_t requested_pixel_clock; /* in KHz */
++ uint32_t calculated_pixel_clock; /* in KHz */
++ uint32_t refresh_rate;
++ enum dc_color_depth color_depth;
++ bool interlaced;
++};
++
++/* PLL information required for AZALIA DTO calculation */
++
++struct audio_pll_info {
++ uint32_t dp_dto_source_clock_in_khz;
++ uint32_t feed_back_divider;
++ enum audio_dto_source dto_source;
++ bool ss_enabled;
++ uint32_t ss_percentage;
++ uint32_t ss_percentage_divider;
++};
++
++struct audio_channel_associate_info {
++ union {
++ struct {
++ uint32_t ALL_CHANNEL_FL:4;
++ uint32_t ALL_CHANNEL_FR:4;
++ uint32_t ALL_CHANNEL_FC:4;
++ uint32_t ALL_CHANNEL_Sub:4;
++ uint32_t ALL_CHANNEL_SL:4;
++ uint32_t ALL_CHANNEL_SR:4;
++ uint32_t ALL_CHANNEL_BL:4;
++ uint32_t ALL_CHANNEL_BR:4;
++ } bits;
++ uint32_t u32all;
++ };
++};
++
++struct audio_output {
++ /* Front DIG id. */
++ enum engine_id engine_id;
++ /* encoder output signal */
++ enum signal_type signal;
++ /* video timing */
++ struct audio_crtc_info crtc_info;
++ /* PLL for audio */
++ struct audio_pll_info pll_info;
++};
++
++struct audio_feature_support {
++ /* supported engines*/
++ uint32_t ENGINE_DIGA:1;
++ uint32_t ENGINE_DIGB:1;
++ uint32_t ENGINE_DIGC:1;
++ uint32_t ENGINE_DIGD:1;
++ uint32_t ENGINE_DIGE:1;
++ uint32_t ENGINE_DIGF:1;
++ uint32_t ENGINE_DIGG:1;
++ uint32_t ENGINE_DVO:1;
++ uint32_t MULTISTREAM_AUDIO:1;
++};
++
++enum audio_payload {
++ CHANNEL_SPLIT_MAPPINGCHANG = 0x9,
++};
++
++#endif /* __AUDIO_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/bios_parser_interface.h b/drivers/gpu/drm/amd/dal/include/bios_parser_interface.h
+new file mode 100644
+index 0000000..6269164
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/bios_parser_interface.h
+@@ -0,0 +1,294 @@
++/*
++ * 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_BIOS_PARSER_INTERFACE_H__
++#define __DAL_BIOS_PARSER_INTERFACE_H__
++
++#include "bios_parser_types.h"
++#include "adapter_service_types.h"
++#include "gpio_types.h"
++
++struct adapter_service;
++struct bios_parser;
++
++struct bp_gpio_cntl_info {
++ uint32_t id;
++ enum gpio_pin_output_state state;
++};
++
++enum bp_result {
++ BP_RESULT_OK = 0, /* There was no error */
++ BP_RESULT_BADINPUT, /*Bad input parameter */
++ BP_RESULT_BADBIOSTABLE, /* Bad BIOS table */
++ BP_RESULT_UNSUPPORTED, /* BIOS Table is not supported */
++ BP_RESULT_NORECORD, /* Record can't be found */
++ BP_RESULT_FAILURE
++};
++
++struct bp_init_data {
++ struct dc_context *ctx;
++ uint8_t *bios;
++};
++
++struct bios_parser *dal_bios_parser_create(
++ struct bp_init_data *init,
++ struct adapter_service *as);
++void dal_bios_parser_destroy(
++ struct bios_parser **bp);
++void dal_bios_parser_power_down(
++ struct bios_parser *bp);
++void dal_bios_parser_power_up(
++ struct bios_parser *bp);
++
++uint8_t dal_bios_parser_get_encoders_number(
++ struct bios_parser *bp);
++uint8_t dal_bios_parser_get_connectors_number(
++ struct bios_parser *bp);
++uint32_t dal_bios_parser_get_oem_ddc_lines_number(
++ struct bios_parser *bp);
++struct graphics_object_id dal_bios_parser_get_encoder_id(
++ struct bios_parser *bp,
++ uint32_t i);
++struct graphics_object_id dal_bios_parser_get_connector_id(
++ struct bios_parser *bp,
++ uint8_t connector_index);
++uint32_t dal_bios_parser_get_src_number(
++ struct bios_parser *bp,
++ struct graphics_object_id id);
++uint32_t dal_bios_parser_get_dst_number(
++ struct bios_parser *bp,
++ struct graphics_object_id id);
++uint32_t dal_bios_parser_get_gpio_record(
++ struct bios_parser *bp,
++ struct graphics_object_id id,
++ struct bp_gpio_cntl_info *gpio_record,
++ uint32_t record_size);
++enum bp_result dal_bios_parser_get_src_obj(
++ struct bios_parser *bp,
++ struct graphics_object_id object_id, uint32_t index,
++ struct graphics_object_id *src_object_id);
++enum bp_result dal_bios_parser_get_dst_obj(
++ struct bios_parser *bp,
++ struct graphics_object_id object_id, uint32_t index,
++ struct graphics_object_id *dest_object_id);
++enum bp_result dal_bios_parser_get_i2c_info(
++ struct bios_parser *bp,
++ struct graphics_object_id id,
++ struct graphics_object_i2c_info *info);
++enum bp_result dal_bios_parser_get_oem_ddc_info(
++ struct bios_parser *bp,
++ uint32_t index,
++ struct graphics_object_i2c_info *info);
++enum bp_result dal_bios_parser_get_voltage_ddc_info(
++ struct bios_parser *bp,
++ uint32_t index,
++ struct graphics_object_i2c_info *info);
++enum bp_result dal_bios_parser_get_thermal_ddc_info(
++ struct bios_parser *bp,
++ uint32_t i2c_channel_id,
++ struct graphics_object_i2c_info *info);
++enum bp_result dal_bios_parser_get_hpd_info(
++ struct bios_parser *bp,
++ struct graphics_object_id id,
++ struct graphics_object_hpd_info *info);
++enum bp_result dal_bios_parser_get_device_tag(
++ struct bios_parser *bp,
++ struct graphics_object_id connector_object_id,
++ uint32_t device_tag_index,
++ struct connector_device_tag_info *info);
++enum bp_result dal_bios_parser_get_firmware_info(
++ struct bios_parser *bp,
++ struct firmware_info *info);
++enum bp_result dal_bios_parser_get_spread_spectrum_info(
++ struct bios_parser *bp,
++ enum as_signal_type signal,
++ uint32_t index,
++ struct spread_spectrum_info *ss_info);
++uint32_t dal_bios_parser_get_ss_entry_number(
++ struct bios_parser *bp,
++ enum as_signal_type signal);
++enum bp_result dal_bios_parser_get_embedded_panel_info(
++ struct bios_parser *bp,
++ struct embedded_panel_info *info);
++enum bp_result dal_bios_parser_enum_embedded_panel_patch_mode(
++ struct bios_parser *bp,
++ uint32_t index,
++ struct embedded_panel_patch_mode *mode);
++enum bp_result dal_bios_parser_get_gpio_pin_info(
++ struct bios_parser *bp,
++ uint32_t gpio_id,
++ struct gpio_pin_info *info);
++enum bp_result dal_bios_parser_get_embedded_panel_info(
++ struct bios_parser *bp,
++ struct embedded_panel_info *info);
++enum bp_result dal_bios_parser_get_gpio_pin_info(
++ struct bios_parser *bp,
++ uint32_t gpio_id,
++ struct gpio_pin_info *info);
++enum bp_result dal_bios_parser_get_faked_edid_len(
++ struct bios_parser *bp,
++ uint32_t *len);
++enum bp_result dal_bios_parser_get_faked_edid_buf(
++ struct bios_parser *bp,
++ uint8_t *buff,
++ uint32_t len);
++enum bp_result dal_bios_parser_get_encoder_cap_info(
++ struct bios_parser *bp,
++ struct graphics_object_id object_id,
++ struct bp_encoder_cap_info *info);
++enum bp_result dal_bios_parser_get_din_connector_info(
++ struct bios_parser *bp,
++ struct graphics_object_id id,
++ struct din_connector_info *info);
++
++bool dal_bios_parser_is_lid_open(
++ struct bios_parser *bp);
++bool dal_bios_parser_is_lid_status_changed(
++ struct bios_parser *bp);
++bool dal_bios_parser_is_display_config_changed(
++ struct bios_parser *bp);
++bool dal_bios_parser_is_accelerated_mode(
++ struct bios_parser *bp);
++void dal_bios_parser_set_scratch_lcd_scale(
++ struct bios_parser *bp,
++ enum lcd_scale scale);
++enum lcd_scale dal_bios_parser_get_scratch_lcd_scale(
++ struct bios_parser *bp);
++void dal_bios_parser_get_bios_event_info(
++ struct bios_parser *bp,
++ struct bios_event_info *info);
++void dal_bios_parser_update_requested_backlight_level(
++ struct bios_parser *bp,
++ uint32_t backlight_8bit);
++uint32_t dal_bios_parser_get_requested_backlight_level(
++ struct bios_parser *bp);
++void dal_bios_parser_take_backlight_control(
++ struct bios_parser *bp,
++ bool cntl);
++bool dal_bios_parser_is_active_display(
++ struct bios_parser *bp,
++ enum signal_type signal,
++ const struct connector_device_tag_info *device_tag);
++enum controller_id dal_bios_parser_get_embedded_display_controller_id(
++ struct bios_parser *bp);
++uint32_t dal_bios_parser_get_embedded_display_refresh_rate(
++ struct bios_parser *bp);
++void dal_bios_parser_set_scratch_connected(
++ struct bios_parser *bp,
++ struct graphics_object_id connector_id,
++ bool connected,
++ const struct connector_device_tag_info *device_tag);
++void dal_bios_parser_prepare_scratch_active_and_requested(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ enum signal_type signal,
++ const struct connector_device_tag_info *device_tag);
++void dal_bios_parser_set_scratch_active_and_requested(
++ struct bios_parser *bp);
++void dal_bios_parser_set_scratch_critical_state(
++ struct bios_parser *bp,
++ bool state);
++void dal_bios_parser_set_scratch_acc_mode_change(
++ struct bios_parser *bp);
++
++bool dal_bios_parser_is_device_id_supported(
++ struct bios_parser *bp,
++ struct device_id id);
++
++/* COMMANDS */
++
++enum bp_result dal_bios_parser_encoder_control(
++ struct bios_parser *bp,
++ struct bp_encoder_control *cntl);
++enum bp_result dal_bios_parser_transmitter_control(
++ struct bios_parser *bp,
++ struct bp_transmitter_control *cntl);
++enum bp_result dal_bios_parser_crt_control(
++ struct bios_parser *bp,
++ enum engine_id engine_id,
++ bool enable,
++ uint32_t pixel_clock);
++enum bp_result dal_bios_parser_dvo_encoder_control(
++ struct bios_parser *bp,
++ struct bp_dvo_encoder_control *cntl);
++enum bp_result dal_bios_parser_enable_crtc(
++ struct bios_parser *bp,
++ enum controller_id id,
++ bool enable);
++enum bp_result dal_bios_parser_adjust_pixel_clock(
++ struct bios_parser *bp,
++ struct bp_adjust_pixel_clock_parameters *bp_params);
++enum bp_result dal_bios_parser_set_pixel_clock(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++enum bp_result dal_bios_parser_enable_spread_spectrum_on_ppll(
++ struct bios_parser *bp,
++ struct bp_spread_spectrum_parameters *bp_params,
++ bool enable);
++enum bp_result dal_bios_parser_program_crtc_timing(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_timing_parameters *bp_params);
++enum bp_result dal_bios_parser_blank_crtc(
++ struct bios_parser *bp,
++ struct bp_blank_crtc_parameters *bp_params,
++ bool blank);
++enum bp_result dal_bios_parser_set_overscan(
++ struct bios_parser *bp,
++ struct bp_hw_crtc_overscan_parameters *bp_params);
++enum bp_result dal_bios_parser_crtc_source_select(
++ struct bios_parser *bp,
++ struct bp_crtc_source_select *bp_params);
++enum bp_result dal_bios_parser_program_display_engine_pll(
++ struct bios_parser *bp,
++ struct bp_pixel_clock_parameters *bp_params);
++enum bp_result dal_bios_parser_get_divider_for_target_display_clock(
++ struct bios_parser *bp,
++ struct bp_display_clock_parameters *bp_params);
++enum signal_type dal_bios_parser_dac_load_detect(
++ struct bios_parser *bp,
++ struct graphics_object_id encoder,
++ struct graphics_object_id connector,
++ enum signal_type display_signal);
++enum bp_result dal_bios_parser_enable_memory_requests(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ bool enable);
++enum bp_result dal_bios_parser_external_encoder_control(
++ struct bios_parser *bp,
++ struct bp_external_encoder_control *cntl);
++enum bp_result dal_bios_parser_enable_disp_power_gating(
++ struct bios_parser *bp,
++ enum controller_id controller_id,
++ enum bp_pipe_control_action action);
++
++void dal_bios_parser_post_init(struct bios_parser *bp);
++
++/* Parse integrated BIOS info */
++struct integrated_info *dal_bios_parser_create_integrated_info(
++ struct bios_parser *bp);
++
++/* Destroy provided integrated info */
++void dal_bios_parser_destroy_integrated_info(struct dc_context *ctx, struct integrated_info **info);
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/bios_parser_types.h b/drivers/gpu/drm/amd/dal/include/bios_parser_types.h
+new file mode 100644
+index 0000000..da7d5f2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/bios_parser_types.h
+@@ -0,0 +1,305 @@
++/*
++ * 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_BIOS_PARSER_TYPES_H__
++#define __DAL_BIOS_PARSER_TYPES_H__
++
++#include "include/signal_types.h"
++#include "include/grph_object_ctrl_defs.h"
++#include "link_service_types.h"
++
++enum bp_encoder_control_action {
++ /* direct VBIOS translation! Just to simplify the translation */
++ ENCODER_CONTROL_DISABLE = 0,
++ ENCODER_CONTROL_ENABLE,
++ ENCODER_CONTROL_SETUP,
++ ENCODER_CONTROL_INIT
++};
++
++enum bp_transmitter_control_action {
++ /* direct VBIOS translation! Just to simplify the translation */
++ TRANSMITTER_CONTROL_DISABLE = 0,
++ TRANSMITTER_CONTROL_ENABLE,
++ TRANSMITTER_CONTROL_BACKLIGHT_OFF,
++ TRANSMITTER_CONTROL_BACKLIGHT_ON,
++ TRANSMITTER_CONTROL_BACKLIGHT_BRIGHTNESS,
++ TRANSMITTER_CONTROL_LCD_SETF_TEST_START,
++ TRANSMITTER_CONTROL_LCD_SELF_TEST_STOP,
++ TRANSMITTER_CONTROL_INIT,
++ TRANSMITTER_CONTROL_DEACTIVATE,
++ TRANSMITTER_CONTROL_ACTIAVATE,
++ TRANSMITTER_CONTROL_SETUP,
++ TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS,
++ /* ATOM_TRANSMITTER_ACTION_POWER_ON. This action is for eDP only
++ * (power up the panel)
++ */
++ TRANSMITTER_CONTROL_POWER_ON,
++ /* ATOM_TRANSMITTER_ACTION_POWER_OFF. This action is for eDP only
++ * (power down the panel)
++ */
++ TRANSMITTER_CONTROL_POWER_OFF
++};
++
++enum bp_external_encoder_control_action {
++ EXTERNAL_ENCODER_CONTROL_DISABLE = 0,
++ EXTERNAL_ENCODER_CONTROL_ENABLE = 1,
++ EXTERNAL_ENCODER_CONTROL_INIT = 0x7,
++ EXTERNAL_ENCODER_CONTROL_SETUP = 0xf,
++ EXTERNAL_ENCODER_CONTROL_UNBLANK = 0x10,
++ EXTERNAL_ENCODER_CONTROL_BLANK = 0x11,
++ EXTERNAL_ENCODER_CONTROL_DAC_LOAD_DETECT = 0x12
++};
++
++enum bp_pipe_control_action {
++ ASIC_PIPE_DISABLE = 0,
++ ASIC_PIPE_ENABLE,
++ ASIC_PIPE_INIT
++};
++
++struct bp_encoder_control {
++ enum bp_encoder_control_action action;
++ enum engine_id engine_id;
++ enum transmitter transmitter;
++ enum signal_type signal;
++ enum lane_count lanes_number;
++ enum dc_color_depth color_depth;
++ bool enable_dp_audio;
++ uint32_t pixel_clock; /* khz */
++};
++
++struct bp_external_encoder_control {
++ enum bp_external_encoder_control_action action;
++ enum engine_id engine_id;
++ enum link_rate link_rate;
++ enum lane_count lanes_number;
++ enum signal_type signal;
++ enum dc_color_depth color_depth;
++ bool coherent;
++ struct graphics_object_id encoder_id;
++ struct graphics_object_id connector_obj_id;
++ uint32_t pixel_clock; /* in KHz */
++};
++
++struct bp_crtc_source_select {
++ enum engine_id engine_id;
++ enum controller_id controller_id;
++ /* from GPU Tx aka asic_signal */
++ enum signal_type signal;
++ /* sink_signal may differ from asicSignal if Translator encoder */
++ enum signal_type sink_signal;
++ enum display_output_bit_depth display_output_bit_depth;
++ bool enable_dp_audio;
++};
++
++struct bp_transmitter_control {
++ enum bp_transmitter_control_action action;
++ enum engine_id engine_id;
++ enum transmitter transmitter; /* PhyId */
++ enum lane_count lanes_number;
++ enum clock_source_id pll_id; /* needed for DCE 4.0 */
++ enum signal_type signal;
++ enum dc_color_depth color_depth; /* not used for DCE6.0 */
++ enum hpd_source_id hpd_sel; /* ucHPDSel, used for DCe6.0 */
++ struct graphics_object_id connector_obj_id;
++ /* symClock; in 10kHz, pixel clock, in HDMI deep color mode, it should
++ * be pixel clock * deep_color_ratio (in KHz)
++ */
++ uint32_t pixel_clock;
++ uint32_t lane_select;
++ uint32_t lane_settings;
++ bool coherent;
++ bool multi_path;
++ bool single_pll_mode;
++};
++
++enum dvo_encoder_memory_rate {
++ DVO_ENCODER_MEMORY_RATE_DDR,
++ DVO_ENCODER_MEMORY_RATE_SDR
++};
++
++enum dvo_encoder_interface_width {
++ DVO_ENCODER_INTERFACE_WIDTH_LOW12BIT,
++ DVO_ENCODER_INTERFACE_WIDTH_HIGH12BIT,
++ DVO_ENCODER_INTERFACE_WIDTH_FULL24BIT
++};
++
++struct bp_dvo_encoder_control {
++ enum bp_encoder_control_action action;
++ enum dvo_encoder_memory_rate memory_rate;
++ enum dvo_encoder_interface_width interface_width;
++ uint32_t pixel_clock; /* in KHz */
++};
++
++struct bp_blank_crtc_parameters {
++ enum controller_id controller_id;
++ uint32_t black_color_rcr;
++ uint32_t black_color_gy;
++ uint32_t black_color_bcb;
++};
++
++struct bp_hw_crtc_timing_parameters {
++ enum controller_id controller_id;
++ /* horizontal part */
++ uint32_t h_total;
++ uint32_t h_addressable;
++ uint32_t h_overscan_left;
++ uint32_t h_overscan_right;
++ uint32_t h_sync_start;
++ uint32_t h_sync_width;
++
++ /* vertical part */
++ uint32_t v_total;
++ uint32_t v_addressable;
++ uint32_t v_overscan_top;
++ uint32_t v_overscan_bottom;
++ uint32_t v_sync_start;
++ uint32_t v_sync_width;
++
++ struct timing_flags {
++ uint32_t INTERLACE:1;
++ uint32_t PIXEL_REPETITION:4;
++ uint32_t HSYNC_POSITIVE_POLARITY:1;
++ uint32_t VSYNC_POSITIVE_POLARITY:1;
++ uint32_t HORZ_COUNT_BY_TWO:1;
++ } flags;
++};
++
++struct bp_hw_crtc_overscan_parameters {
++ enum controller_id controller_id;
++ uint32_t h_overscan_left;
++ uint32_t h_overscan_right;
++ uint32_t v_overscan_top;
++ uint32_t v_overscan_bottom;
++};
++
++struct bp_adjust_pixel_clock_parameters {
++ /* Input: Signal Type - to be converted to Encoder mode */
++ enum signal_type signal_type;
++ /* Input: required by V3, display pll configure parameter defined as
++ * following DISPPLL_CONFIG_XXXX */
++ enum disp_pll_config display_pll_config;
++ /* Input: Encoder object id */
++ struct graphics_object_id encoder_object_id;
++ /* Input: Pixel Clock (requested Pixel clock based on Video timing
++ * standard used) in KHz
++ */
++ uint32_t pixel_clock;
++ union {
++ /* Input: If DVO, need passing link rate and output 12bit low or
++ * 24bit to VBIOS Exec table */
++ uint32_t dvo_config;
++ /* Input: If non DVO, not defined yet */
++ uint32_t non_dvo_undefined;
++ };
++ /* Output: Adjusted Pixel Clock (after VBIOS exec table) in KHz */
++ uint32_t adjusted_pixel_clock;
++ /* Output: If non-zero, this refDiv value should be used to calculate
++ * other ppll params */
++ uint32_t reference_divider;
++ /* Output: If non-zero, this postDiv value should be used to calculate
++ * other ppll params */
++ uint32_t pixel_clock_post_divider;
++ /* Input: Enable spread spectrum */
++ bool ss_enable;
++};
++
++struct bp_pixel_clock_parameters {
++ enum controller_id controller_id; /* (Which CRTC uses this PLL) */
++ enum clock_source_id pll_id; /* Clock Source Id */
++ /* signal_type -> Encoder Mode - needed by VBIOS Exec table */
++ enum signal_type signal_type;
++ /* Adjusted Pixel Clock (after VBIOS exec table)
++ * that becomes Target Pixel Clock (KHz) */
++ uint32_t target_pixel_clock;
++ /* Calculated Reference divider of Display PLL */
++ uint32_t reference_divider;
++ /* Calculated Feedback divider of Display PLL */
++ uint32_t feedback_divider;
++ /* Calculated Fractional Feedback divider of Display PLL */
++ uint32_t fractional_feedback_divider;
++ /* Calculated Pixel Clock Post divider of Display PLL */
++ uint32_t pixel_clock_post_divider;
++ struct graphics_object_id encoder_object_id; /* Encoder object id */
++ /* If DVO, need passing link rate and output 12bit low or
++ * 24bit to VBIOS Exec table */
++ uint32_t dvo_config;
++ /* VBIOS returns a fixed display clock when DFS-bypass feature
++ * is enabled (KHz) */
++ uint32_t dfs_bypass_display_clock;
++ struct program_pixel_clock_flags {
++ uint32_t FORCE_PROGRAMMING_OF_PLL:1;
++ /* Use Engine Clock as source for Display Clock when
++ * programming PLL */
++ uint32_t USE_E_CLOCK_AS_SOURCE_FOR_D_CLOCK:1;
++ /* Use external reference clock (refDivSrc for PLL) */
++ uint32_t SET_EXTERNAL_REF_DIV_SRC:1;
++ } flags;
++};
++
++struct bp_display_clock_parameters {
++ uint32_t target_display_clock; /* KHz */
++ /* Actual Display Clock set due to clock divider granularity KHz */
++ uint32_t actual_display_clock;
++ /* Actual Post Divider ID used to generate the actual clock */
++ uint32_t actual_post_divider_id;
++};
++
++struct spread_spectrum_flags {
++ /* 1 = Center Spread; 0 = down spread */
++ uint32_t CENTER_SPREAD:1;
++ /* 1 = external; 0 = internal */
++ uint32_t EXTERNAL_SS:1;
++ /* 1 = delta-sigma type parameter; 0 = ver1 */
++ uint32_t DS_TYPE:1;
++};
++
++struct bp_spread_spectrum_parameters {
++ enum clock_source_id pll_id;
++ uint32_t percentage;
++ uint32_t ds_frac_amount;
++
++ union {
++ struct {
++ uint32_t step;
++ uint32_t delay;
++ uint32_t range; /* In Hz unit */
++ } ver1;
++ struct {
++ uint32_t feedback_amount;
++ uint32_t nfrac_amount;
++ uint32_t ds_frac_size;
++ } ds;
++ };
++
++ struct spread_spectrum_flags flags;
++};
++
++struct bp_encoder_cap_info {
++ uint32_t DP_HBR2_CAP:1;
++ uint32_t DP_HBR2_EN:1;
++ uint32_t RESERVED:30;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/bit_set.h b/drivers/gpu/drm/amd/dal/include/bit_set.h
+new file mode 100644
+index 0000000..3cd8d32
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/bit_set.h
+@@ -0,0 +1,61 @@
++/*
++ * 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_BIT_SET_H__
++#define __DAL_BIT_SET_H__
++
++struct bit_set_iterator_32 {
++ uint32_t value;
++};
++
++static inline uint32_t least_significant_bit(uint32_t bs32_container)
++{
++ return bs32_container & (0 - bs32_container);
++}
++/* iterates over bit_set_iterator by means of least significant bit purge*/
++static inline uint32_t get_next_significant_bit(
++ struct bit_set_iterator_32 *bs32)
++{
++ uint32_t lsb = least_significant_bit(bs32->value);
++
++ bs32->value &= ~lsb;
++ return lsb;
++}
++
++static inline void bit_set_iterator_reset_to_mask(
++ struct bit_set_iterator_32 *bs32,
++ uint32_t mask)
++{
++ bs32->value = mask;
++}
++
++static inline void bit_set_iterator_construct(
++ struct bit_set_iterator_32 *bs32,
++ uint32_t mask)
++{
++ bit_set_iterator_reset_to_mask(bs32, mask);
++}
++
++#endif /* __DAL_BIT_SET_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/clock_source_interface.h b/drivers/gpu/drm/amd/dal/include/clock_source_interface.h
+new file mode 100644
+index 0000000..bea4c2b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/clock_source_interface.h
+@@ -0,0 +1,89 @@
++/*
++ * 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_CLOCK_SOURCE_INTERFACE__
++#define __DAL_CLOCK_SOURCE_INTERFACE__
++
++#include "include/clock_source_types.h"
++
++struct clock_source;
++struct clock_source_init_data {
++ struct adapter_service *as;
++ struct graphics_object_id clk_src_id;
++ struct dc_context *ctx;
++};
++
++struct clock_source *dal_clock_source_create(struct clock_source_init_data *);
++
++void dal_clock_source_destroy(struct clock_source **clk_src);
++
++enum clock_source_id dal_clock_source_get_id(
++ const struct clock_source *clk_src);
++
++bool dal_clock_source_is_clk_src_with_fixed_freq(
++ const struct clock_source *clk_src);
++
++const struct graphics_object_id dal_clock_source_get_graphics_object_id(
++ const struct clock_source *clk_src);
++
++enum clock_sharing_level dal_clock_souce_get_clk_sharing_lvl(
++ const struct clock_source *clk_src);
++
++uint32_t dal_clock_source_get_pix_clk_dividers(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings);
++
++bool dal_clock_source_program_pix_clk(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ struct pll_settings *pll_settings);
++
++bool dal_clock_source_adjust_pxl_clk_by_ref_pixel_rate(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ uint32_t pix_clk_hz);
++
++bool dal_clock_source_adjust_pxl_clk_by_pix_amount(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params,
++ int32_t pix_num);
++
++uint32_t dal_clock_source_retreive_pix_rate_hz(
++ struct clock_source *clk_src,
++ struct pixel_clk_params *pix_clk_params);
++
++bool dal_clock_source_power_down_pll(struct clock_source *clk_src,
++ enum controller_id);
++
++bool dal_clock_source_is_clk_in_reset(struct clock_source *clk_src);
++
++bool dal_clock_source_is_gen_lock_capable(struct clock_source *clk_src);
++
++bool dal_clock_source_is_output_signal_supported(
++ const struct clock_source *clk_src,
++ enum signal_type signal_type);
++
++#endif /*__DAL_CLOCK_SOURCE_INTERFACE__*/
+diff --git a/drivers/gpu/drm/amd/dal/include/clock_source_types.h b/drivers/gpu/drm/amd/dal/include/clock_source_types.h
+new file mode 100644
+index 0000000..3883216
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/clock_source_types.h
+@@ -0,0 +1,118 @@
++/*
++ * 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_CLOCK_SOURCE_TYPES_H__
++#define __DAL_CLOCK_SOURCE_TYPES_H__
++
++#include "include/signal_types.h"
++#include "include/grph_object_ctrl_defs.h"
++
++/**
++ * ClockSharingLevel
++ * Enumeration for clock sharing support.
++ * Level <x> means sharing supported on all levels below and including <x>
++ */
++enum clock_sharing_level {
++ CLOCK_SHARING_LEVEL_NOT_SHAREABLE = 0,
++ CLOCK_SHARING_LEVEL_DP_MST_SHAREABLE,
++ CLOCK_SHARING_LEVEL_DISPLAY_PORT_SHAREABLE
++};
++
++/**
++ * Display Port HW De spread of Reference Clock related Parameters structure
++ * Store it once at boot for later usage
++ */
++struct csdp_ref_clk_ds_params {
++ bool hw_dso_n_dp_ref_clk;
++/* Flag for HW De Spread enabled (if enabled SS on DP Reference Clock)*/
++ uint32_t avg_dp_ref_clk_khz;
++/* Average DP Reference clock (in KHz)*/
++ uint32_t ss_percentage_on_dp_ref_clk;
++/* DP Reference clock SS percentage
++ * (not to be mixed with DP IDCLK SS from PLL Settings)*/
++ uint32_t ss_percentage_divider;
++/* DP Reference clock SS percentage divider */
++};
++
++/**
++ * Pixel Clock Parameters structure
++ * These parameters are required as input
++ * when calculating Pixel Clock Dividers for requested Pixel Clock
++ */
++struct pixel_clk_flags {
++ uint32_t ENABLE_SS:1;
++ uint32_t DISPLAY_BLANKED:1;
++ uint32_t PROGRAM_PIXEL_CLOCK:1;
++ uint32_t PROGRAM_ID_CLOCK:1;
++};
++
++struct pixel_clk_params {
++ uint32_t requested_pix_clk; /* in KHz */
++/*> Requested Pixel Clock
++ * (based on Video Timing standard used for requested mode)*/
++ uint32_t requested_sym_clk; /* in KHz */
++/*> Requested Sym Clock (relevant only for display port)*/
++ uint32_t dp_ref_clk; /* in KHz */
++/*> DP reference clock - calculated only for DP signal for specific cases*/
++ struct graphics_object_id encoder_object_id;
++/*> Encoder object Id - needed by VBIOS Exec table*/
++ enum signal_type signal_type;
++/*> signalType -> Encoder Mode - needed by VBIOS Exec table*/
++ enum controller_id controller_id;
++/*> ControllerId - which controller using this PLL*/
++ enum dc_color_depth color_depth;
++ struct csdp_ref_clk_ds_params de_spread_params;
++/*> de-spread info, relevant only for on-the-fly tune-up pixel rate*/
++
++ uint32_t dvo_cfg;
++/*> If DVO, need passing link rate
++ * and output 12bit low or 24bit to VBIOS Exec table*/
++
++ enum disp_pll_config disp_pll_cfg;
++ struct pixel_clk_flags flags;
++};
++
++/**
++ * Pixel Clock Dividers structure with desired Pixel Clock
++ * (adjusted after VBIOS exec table),
++ * with actually calculated Clock and reference Crystal frequency
++ */
++struct pll_settings {
++ uint32_t actual_pix_clk;
++ uint32_t adjusted_pix_clk;
++ uint32_t calculated_pix_clk;
++ uint32_t vco_freq;
++ uint32_t reference_freq;
++ uint32_t reference_divider;
++ uint32_t feedback_divider;
++ uint32_t fract_feedback_divider;
++ uint32_t pix_clk_post_divider;
++ uint32_t ss_percentage;
++ bool use_external_clk;
++};
++
++#define MAX_PLL_CALC_ERROR 0xFFFFFFFF
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/connector_interface.h b/drivers/gpu/drm/amd/dal/include/connector_interface.h
+new file mode 100644
+index 0000000..e09af7e
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/connector_interface.h
+@@ -0,0 +1,82 @@
++/*
++ * 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_CONNECTOR_INTERFACE_H__
++#define __DAL_CONNECTOR_INTERFACE_H__
++
++#include "adapter_service_interface.h"
++#include "signal_types.h"
++
++/* forward declaration */
++struct connector;
++
++struct connector_signals {
++ const enum signal_type *signal;
++ uint32_t number_of_signals;
++};
++
++struct connector_feature_support {
++ bool HPD_FILTERING:1;
++ bool HW_DDC_POLLING:1;
++ enum hpd_source_id hpd_line;
++ enum channel_id ddc_line;
++};
++
++void dal_connector_get_features(
++ const struct connector *con,
++ struct connector_feature_support *cfs);
++
++struct connector *dal_connector_create(
++ struct dc_context *ctx,
++ struct adapter_service *as,
++ struct graphics_object_id go_id);
++
++void dal_connector_destroy(struct connector **connector);
++
++void dal_connector_destroy(struct connector **connector);
++
++const struct graphics_object_id dal_connector_get_graphics_object_id(
++ const struct connector *connector);
++
++uint32_t dal_connector_enumerate_output_signals(
++ const struct connector *connector);
++uint32_t dal_connector_enumerate_input_signals(
++ const struct connector *connector);
++
++struct connector_signals dal_connector_get_default_signals(
++ const struct connector *connector);
++
++bool dal_connector_program_hpd_filter(
++ const struct connector *connector,
++ const uint32_t delay_on_connect_in_ms,
++ const uint32_t delay_on_disconnect_in_ms);
++
++bool dal_connector_enable_ddc_polling(
++ const struct connector *connector,
++ const bool is_poll_for_connect);
++
++bool dal_connector_disable_ddc_polling(const struct connector *connector);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/dal_asic_id.h b/drivers/gpu/drm/amd/dal/include/dal_asic_id.h
+new file mode 100644
+index 0000000..fa04f80
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dal_asic_id.h
+@@ -0,0 +1,106 @@
++/*
++ * 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_ASIC_ID_H__
++#define __DAL_ASIC_ID_H__
++
++/*
++ * ASIC internal revision ID
++ */
++
++/* DCE80 (based on ci_id.h in Perforce) */
++
++#define CI_BONAIRE_M_A0 0x14
++#define CI_BONAIRE_M_A1 0x15
++#define CI_HAWAII_P_A0 0x28
++
++#define CI_UNKNOWN 0xFF
++
++#define ASIC_REV_IS_BONAIRE_M(rev) \
++ ((rev >= CI_BONAIRE_M_A0) && (rev < CI_HAWAII_P_A0))
++
++#define ASIC_REV_IS_HAWAII_P(rev) \
++ (rev >= CI_HAWAII_P_A0)
++
++/* KV1 with Spectre GFX core, 8-8-1-2 (CU-Pix-Primitive-RB) */
++#define KV_SPECTRE_A0 0x01
++
++/* KV2 with Spooky GFX core, including downgraded from Spectre core,
++ * 3-4-1-1 (CU-Pix-Primitive-RB) */
++#define KV_SPOOKY_A0 0x41
++
++/* KB with Kalindi GFX core, 2-4-1-1 (CU-Pix-Primitive-RB) */
++#define KB_KALINDI_A0 0x81
++
++/* KB with Kalindi GFX core, 2-4-1-1 (CU-Pix-Primitive-RB) */
++#define KB_KALINDI_A1 0x82
++
++/* BV with Kalindi GFX core, 2-4-1-1 (CU-Pix-Primitive-RB) */
++#define BV_KALINDI_A2 0x85
++
++/* ML with Godavari GFX core, 2-4-1-1 (CU-Pix-Primitive-RB) */
++#define ML_GODAVARI_A0 0xA1
++
++/* ML with Godavari GFX core, 2-4-1-1 (CU-Pix-Primitive-RB) */
++#define ML_GODAVARI_A1 0xA2
++
++#define KV_UNKNOWN 0xFF
++
++#define ASIC_REV_IS_KALINDI(rev) \
++ ((rev >= KB_KALINDI_A0) && (rev < KV_UNKNOWN))
++
++#define ASIC_REV_IS_BHAVANI(rev) \
++ ((rev >= BV_KALINDI_A2) && (rev < ML_GODAVARI_A0))
++
++#define ASIC_REV_IS_GODAVARI(rev) \
++ ((rev >= ML_GODAVARI_A0) && (rev < KV_UNKNOWN))
++
++/* DCE11 */
++#define CZ_CARRIZO_A0 0x01
++
++#define STONEY_A0 0x61
++#define CZ_UNKNOWN 0xFF
++
++#define ASIC_REV_IS_STONEY(rev) \
++ ((rev >= STONEY_A0) && (rev < CZ_UNKNOWN))
++
++/*
++ * ASIC chip ID
++ */
++/* DCE80 */
++#define DEVICE_ID_KALINDI_9834 0x9834
++#define DEVICE_ID_TEMASH_9839 0x9839
++#define DEVICE_ID_TEMASH_983D 0x983D
++
++
++/* Asic Family IDs for different asic family. */
++#define FAMILY_CI 120 /* Sea Islands: Hawaii (P), Bonaire (M) */
++#define FAMILY_KV 125 /* Fusion => Kaveri: Spectre, Spooky; Kabini: Kalindi */
++#define FAMILY_VI 130 /* Volcanic Islands: Iceland (V), Tonga (M) */
++#define FAMILY_CZ 135 /* Carrizo */
++
++#define FAMILY_UNKNOWN 0xFF
++
++#endif /* __DAL_ASIC_ID_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dal_register_logger.h b/drivers/gpu/drm/amd/dal/include/dal_register_logger.h
+new file mode 100644
+index 0000000..176d811
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dal_register_logger.h
+@@ -0,0 +1,43 @@
++/*
++ * 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_REGISTER_LOGGER__
++#define __DAL_REGISTER_LOGGER__
++
++/****************
++ * API functions
++ ***************/
++
++/* dal_reg_logger_push - begin Register Logging */
++void dal_reg_logger_push(const char *caller_func);
++/* dal_reg_logger_pop - stop Register Logging */
++void dal_reg_logger_pop(void);
++
++
++/* for internal use of the Logger only */
++void dal_reg_logger_rw_count_increment(void);
++bool dal_reg_logger_should_dump_register(void);
++
++#endif /* __DAL_REGISTER_LOGGER__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dal_types.h b/drivers/gpu/drm/amd/dal/include/dal_types.h
+new file mode 100644
+index 0000000..d3c91b9
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dal_types.h
+@@ -0,0 +1,292 @@
++/*
++ * 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_TYPES_H__
++#define __DAL_TYPES_H__
++
++#include "dcs_types.h"
++struct dal_logger;
++
++enum dce_version {
++ DCE_VERSION_UNKNOWN = (-1),
++#if defined(CONFIG_DRM_AMD_DAL_DCE11_0)
++ DCE_VERSION_11_0,
++#endif
++ DCE_VERSION_MAX
++};
++
++/*
++ * ASIC Runtime Flags
++ */
++struct dal_asic_runtime_flags {
++ union {
++ uint32_t raw;
++ struct {
++ uint32_t EMULATE_REPLUG_ON_CAP_CHANGE:1;
++ uint32_t SUPPORT_XRBIAS:1;
++ uint32_t SKIP_POWER_DOWN_ON_RESUME:1;
++ uint32_t FULL_DETECT_ON_RESUME:1;
++ uint32_t GSL_FRAMELOCK:1;
++ uint32_t NO_LOW_BPP_MODES:1;
++ uint32_t BLOCK_ON_INITIAL_DETECTION:1;
++ uint32_t OPTIMIZED_DISPLAY_PROGRAMMING_ON_BOOT:1;
++ uint32_t DRIVER_CONTROLLED_BRIGHTNESS:1;
++ uint32_t MODIFIABLE_FRAME_DURATION:1;
++ uint32_t MIRACAST_SUPPORTED:1;
++ uint32_t CONNECTED_STANDBY_SUPPORTED:1;
++ uint32_t GNB_WAKEUP_SUPPORTED:1;
++ } bits;
++ } flags;
++};
++
++struct hw_asic_id {
++ uint32_t chip_id;
++ uint32_t chip_family;
++ uint32_t pci_revision_id;
++ uint32_t hw_internal_rev;
++ uint32_t vram_type;
++ uint32_t vram_width;
++ uint32_t feature_flags;
++ struct dal_asic_runtime_flags runtime_flags;
++ uint32_t fake_paths_num;
++ void *atombios_base_address;
++};
++
++/* this is pci information. BDF stands for BUS,DEVICE,FUNCTION*/
++
++struct bdf_info {
++ uint16_t BUS_NUMBER:8;
++ uint16_t DEVICE_NUMBER:5;
++ uint16_t FUNCTION_NUMBER:3;
++};
++
++#define DAL_PARAM_INVALID_INT 0x80000000
++
++/* shift values for bool override parameter mask
++ * bmask is for this struct,if we touch this feature
++ * bval indicates every bit fields for this struct too,1 is enable this feature
++ * amdgpu.disp_bval=1594, amdgpu.disp_bmask=1594 ,
++ * finally will show log like this:
++ * Overridden FEATURE_LIGHT_SLEEP is enabled now
++ * Overridden FEATURE_USE_MAX_DISPLAY_CLK is enabled now
++ * Overridden FEATURE_ENABLE_DFS_BYPASS is enabled now
++ * Overridden FEATURE_POWER_GATING_PIPE_IN_TILE is enabled now
++ * Overridden FEATURE_USE_PPLIB is enabled now
++ * Overridden FEATURE_DISABLE_LPT_SUPPORT is enabled now
++ * Overridden FEATURE_DUMMY_FBC_BACKEND is enabled now */
++enum bool_param_shift {
++ DAL_PARAM_MAXIMIZE_STUTTER_MARKS = 0,
++ DAL_PARAM_LIGHT_SLEEP,
++ DAL_PARAM_MAXIMIZE_URGENCY_WATERMARKS,
++ DAL_PARAM_USE_MAX_DISPLAY_CLK,
++ DAL_PARAM_ENABLE_DFS_BYPASS,
++ DAL_PARAM_POWER_GATING_PIPE_IN_TILE,
++ DAL_PARAM_POWER_GATING_LB_PORTION,
++ DAL_PARAM_PSR_ENABLE,
++ DAL_PARAM_VARI_BRIGHT_ENABLE,
++ DAL_PARAM_USE_PPLIB,
++ DAL_PARAM_DISABLE_LPT_SUPPORT,
++ DAL_PARAM_DUMMY_FBC_BACKEND,
++ DAL_PARAM_ENABLE_GPU_SCALING,
++ DAL_BOOL_PARAM_MAX
++};
++
++/* array index for integer override parameters*/
++enum int_param_array_index {
++ DAL_PARAM_MAX_COFUNC_NON_DP_DISPLAYS = 0,
++ DAL_PARAM_DRR_SUPPORT,
++ DAL_INT_PARAM_MAX
++};
++
++struct dal_override_parameters {
++ uint32_t bool_param_enable_mask;
++ uint32_t bool_param_values;
++ uint32_t int_param_values[DAL_INT_PARAM_MAX];
++};
++
++
++struct dal_init_data {
++ struct hw_asic_id asic_id;
++ struct view_port_alignment vp_alignment;
++ struct bdf_info bdf_info;
++ struct dal_override_parameters display_param;
++ void *driver; /* ctx */
++ void *cgs_device;
++};
++
++struct dal_dc_init_data {
++ struct dc_context *ctx; /* TODO: remove 'dal' when DC is complete. */
++ struct adapter_service *adapter_srv;
++};
++
++struct dal_dev_c_lut {
++ uint8_t red;
++ uint8_t green;
++ uint8_t blue;
++ uint8_t reserved;
++};
++
++struct dal_dev_gamma_lut {
++ uint16_t red;
++ uint16_t green;
++ uint16_t blue;
++};
++
++struct dc_context {
++ struct dc *dc;
++
++ void *driver_context; /* e.g. amdgpu_device */
++
++ struct dal_logger *logger;
++ void *cgs_device;
++};
++
++/* Wireless display structs */
++
++union dal_remote_display_cea_mode_bitmap {
++ struct {
++ uint32_t CEA_640X480_60P:1;/*0*/
++ uint32_t CEA_720X480_60P:1;/*1*/
++ uint32_t CEA_720X480_60I:1;/*2*/
++ uint32_t CEA_720X576_50P:1;/*3*/
++ uint32_t CEA_720X576_50I:1;/*4*/
++ uint32_t CEA_1280X720_30P:1;/*5*/
++ uint32_t CEA_1280X720_60P:1;/*6*/
++ uint32_t CEA_1920X1080_30P:1;/*7*/
++ uint32_t CEA_1920X1080_60P:1;/*8*/
++ uint32_t CEA_1920X1080_60I:1;/*9*/
++ uint32_t CEA_1280X720_25P:1;/*10*/
++ uint32_t CEA_1280X728_50P:1;/*11*/
++ uint32_t CEA_1920X1080_25P:1;/*12*/
++ uint32_t CEA_1920X1080_50P:1;/*13*/
++ uint32_t CEA_1920X1080_50I:1;/*14*/
++ uint32_t CEA_1280X1024_24P:1;/*15*/
++ uint32_t CEA_1920X1080_24P:1;/*16*/
++ uint32_t RESERVED:15;/*[17-31]*/
++ } flags;
++ uint32_t raw;
++};
++
++union dal_remote_display_vesa_mode_bitmap {
++ struct {
++ uint32_t VESA_800X600_30P:1;/*0*/
++ uint32_t VESA_800X600_60P:1;/*1*/
++ uint32_t VESA_1024X768_30P:1;/*2*/
++ uint32_t VESA_1024X768_60P:1;/*3*/
++ uint32_t VESA_1152X864_30P:1;/*4*/
++ uint32_t VESA_1152X864_60P:1;/*5*/
++ uint32_t VESA_1280X768_30P:1;/*6*/
++ uint32_t VESA_1280X768_60P:1;/*7*/
++ uint32_t VESA_1280X800_30P:1;/*8*/
++ uint32_t VESA_1280X800_60P:1;/*9*/
++ uint32_t VESA_1360X768_30P:1;/*10*/
++ uint32_t VESA_1360X768_60P:1;/*11*/
++ uint32_t VESA_1366X768_30P:1;/*12*/
++ uint32_t VESA_1366X768_60P:1;/*13*/
++ uint32_t VESA_1280X1024_30P:1;/*14*/
++ uint32_t VESA_1280X1024_60P:1;/*15*/
++ uint32_t VESA_1400X1050_30P:1;/*16*/
++ uint32_t VESA_1400X1050_60P:1;/*17*/
++ uint32_t VESA_1440X900_30P:1;/*18*/
++ uint32_t VESA_1440X900_60P:1;/*19*/
++ uint32_t VESA_1600X900_30P:1;/*20*/
++ uint32_t VESA_1600X900_60P:1;/*21*/
++ uint32_t VESA_1600X1200_30P:1;/*22*/
++ uint32_t VESA_1600X1200_60P:1;/*23*/
++ uint32_t VESA_1680X1024_30P:1;/*24*/
++ uint32_t VESA_1680X1024_60P:1;/*25*/
++ uint32_t VESA_1680X1050_30P:1;/*26*/
++ uint32_t VESA_1680X1050_60P:1;/*27*/
++ uint32_t VESA_1920X1200_30P:1;/*28*/
++ uint32_t VESA_1920X1200_60P:1;/*29*/
++ uint32_t RESERVED:2;/*[30-31]*/
++ } flags;
++ uint32_t raw;
++};
++
++union dal_remote_display_hh_mode_bitmap {
++ struct {
++ uint32_t HH_800X480_30P:1;/*0*/
++ uint32_t HH_800X480_60P:1;/*1*/
++ uint32_t HH_854X480_30P:1;/*2*/
++ uint32_t HH_854X480_60P:1;/*3*/
++ uint32_t HH_864X480_30P:1;/*4*/
++ uint32_t HH_864X480_60P:1;/*5*/
++ uint32_t HH_640X360_30P:1;/*6*/
++ uint32_t HH_640X360_60P:1;/*7*/
++ uint32_t HH_960X540_30P:1;/*8*/
++ uint32_t HH_960X540_60P:1;/*9*/
++ uint32_t HH_848X480_30P:1;/*10*/
++ uint32_t HH_848X480_60P:1;/*11*/
++ uint32_t RESERVED:20;/*[12-31]*/
++ } flags;
++ uint32_t raw;
++};
++
++union dal_remote_display_stereo_3d_mode_bitmap {
++ struct {
++ uint32_t STEREO_1920X1080_24P_TOP_AND_BOTTOM:1;/*0*/
++ uint32_t STEREO_1280X720_60P_TOP_AND_BOTTOM:1;/*1*/
++ uint32_t STEREO_1280X720_50P_TOP_AND_BOTTOM:1;/*2*/
++ uint32_t STEREO_1920X1080_24X2P_FRAME_ALTERNATE:1;/*3*/
++ uint32_t STEREO_1280X720_60X2P_FRAME_ALTERNATE:1;/*4*/
++ uint32_t STEREO_1280X720_30X2P_FRAME_ALTERNATE:1;/*5*/
++ uint32_t STEREO_1280X720_50X2P_FRAME_ALTERNATE:1;/*6*/
++ uint32_t STEREO_1280X720_25X2P_FRAME_ALTERNATE:1;/*7*/
++ uint32_t STEREO_1920X1080_24P_FRAME_PACKING:1;/* 8*/
++ uint32_t STEREO_1280X720_60P_FRAME_PACKING:1;/* 9*/
++ uint32_t STEREO_1280X720_30P_FRAME_PACKING:1;/*10*/
++ uint32_t STEREO_1280X720_50P_FRAME_PACKING:1;/*11*/
++ uint32_t STEREO_1280X720_25P_FRAME_PACKING:1;/*12*/
++ uint32_t RESERVED:19; /*[13-31]*/
++ } flags;
++ uint32_t raw;
++};
++
++union dal_remote_display_audio_bitmap {
++ struct {
++ uint32_t LPCM_44100HZ_16BITS_2_CHANNELS:1;/*0*/
++ uint32_t LPCM_48000HZ_16BITS_2_CHANNELS:1;/*1*/
++ uint32_t AAC_48000HZ_16BITS_2_CHANNELS:1;/*2*/
++ uint32_t AAC_48000HZ_16BITS_4_CHANNELS:1;/*3*/
++ uint32_t AAC_48000HZ_16BITS_6_CHANNELS:1;/*4*/
++ uint32_t AAC_48000HZ_16BITS_8_CHANNELS:1;/*5*/
++ uint32_t AC3_48000HZ_16BITS_2_CHANNELS:1;/*6*/
++ uint32_t AC3_48000HZ_16BITS_4_CHANNELS:1;/*7*/
++ uint32_t AC3_48000HZ_16BITS_6_CHANNELS:1;/*8*/
++ uint32_t RESERVED:23;/*[9-31]*/
++ } flags;
++ uint32_t raw;
++};
++
++struct dal_remote_display_receiver_capability {
++ union dal_remote_display_cea_mode_bitmap cea_mode;
++ union dal_remote_display_vesa_mode_bitmap vesa_mode;
++ union dal_remote_display_hh_mode_bitmap hh_mode;
++ union dal_remote_display_stereo_3d_mode_bitmap stereo_3d_mode;
++ union dal_remote_display_audio_bitmap audio;
++};
++
++#endif /* __DAL_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dc_clock_generator_interface.h b/drivers/gpu/drm/amd/dal/include/dc_clock_generator_interface.h
+new file mode 100644
+index 0000000..b7fb9ff
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dc_clock_generator_interface.h
+@@ -0,0 +1,77 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_CLOCK_GENERATOR_INTERFACE_H__
++#define __DC_CLOCK_GENERATOR_INTERFACE_H__
++
++#include "grph_object_ctrl_defs.h"
++#include "set_mode_types.h"
++
++/* Parameter for programming the DCCP_DISP_SLOW_SELECT*/
++struct dccg_mapping_params {
++ uint32_t controllers_num;
++ enum controller_id *controllers;
++};
++
++/* Parameters related to HW DeSpread of DP Reference Clock*/
++struct dccg_dp_ref_clk_ds_params {
++ struct {
++ /* Flag for Enabled SS on DP Reference Clock*/
++ bool SS_ENABLED:1;
++ /* Flag for HW De Spread enabled
++ * (if enabled SS on DP Reference Clock)*/
++ bool DS_ENABLED:1;
++ /* Flag for HW De Spread Calculations enabled for DS_DTO_INCR
++ * and DS_DTO_MODULO (if 0 SW programs DS_DTO_INCR and
++ * DS_DTO_MODULO)*/
++ bool DS_CALCULATIONS:1;
++ } flags;
++ /*DP Reference clock SS percentage
++ * (if enabled downspread on DP Reference Clock)*/
++ uint32_t ss_percentage;
++ /*DP Reference clock SS percentage Divider (1000 or 100)*/
++ uint32_t ss_percentage_divider;
++};
++
++struct dc_clock_generator;
++
++void dal_dc_clock_generator_destroy(struct dc_clock_generator **dc);
++void dal_dc_clock_generator_set_display_pipe_mapping(
++ struct dc_clock_generator *dc_clk_gen,
++ struct dccg_mapping_params *params);
++bool dal_dc_clock_generator_get_dp_ref_clk_ds_params(
++ struct dc_clock_generator *dc_clk_gen,
++ struct dccg_dp_ref_clk_ds_params *params);
++bool dal_dc_clock_generator_enable_gtc_counter(
++ struct dc_clock_generator *dc_clk_gen,
++ uint32_t dprefclk);
++void dal_dc_clock_generator_disable_gtc_counter(
++ struct dc_clock_generator *dc_clk_gen);
++void dal_dc_clock_generator_set_gtc_group_offset(
++ struct dc_clock_generator *dc_clk_gen,
++ enum gtc_group group_num,
++ uint32_t offset);
++
++#endif /* __DC_CLOCK_GENERATOR_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dcs_interface.h b/drivers/gpu/drm/amd/dal/include/dcs_interface.h
+new file mode 100644
+index 0000000..b3474cf
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dcs_interface.h
+@@ -0,0 +1,351 @@
++/* 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_DCS_INTERFACE_H__
++#define __DAL_DCS_INTERFACE_H__
++
++#include "dcs_types.h"
++#include "grph_object_id.h"
++
++struct dal_context;
++struct dcs;
++struct ddc_service;
++enum ddc_transaction_type;
++enum ddc_result;
++struct display_sink_capability;
++enum dc_timing_3d_format;
++
++struct dcs_cea_audio_mode_list;
++struct dcs_customized_mode_list;
++
++struct dcs_init_data {
++ struct dal_context *dal;
++ struct adapter_service *as;
++ struct timing_service *ts;
++ enum dcs_interface_type interface_type;
++ struct graphics_object_id grph_obj_id;
++};
++
++struct dcs_cea_audio_mode_list *dal_dcs_cea_audio_mode_list_create(
++ uint32_t list_size);
++
++void dal_dcs_cea_audio_mode_list_destroy(
++ struct dcs_cea_audio_mode_list **list);
++
++bool dal_dcs_cea_audio_mode_list_append(
++ struct dcs_cea_audio_mode_list *list,
++ struct cea_audio_mode *cea_audio_mode);
++uint32_t dal_dcs_cea_audio_mode_list_get_count(
++ const struct dcs_cea_audio_mode_list *list);
++void dal_dcs_cea_audio_mode_list_clear(
++ struct dcs_cea_audio_mode_list *list);
++
++struct cea_audio_mode *dal_dcs_cea_audio_mode_list_at_index(
++ const struct dcs_cea_audio_mode_list *list,
++ uint32_t index);
++
++struct dcs *dal_dcs_create(const struct dcs_init_data *init_data);
++
++void dal_dcs_destroy(struct dcs **dcs);
++
++enum edid_retrieve_status dal_dcs_retrieve_raw_edid(struct dcs *dcs);
++
++uint32_t dal_dcs_get_edid_raw_data_size(struct dcs *dcs);
++
++enum edid_retrieve_status dal_dcs_override_raw_edid(
++ struct dcs *dcs,
++ uint32_t len,
++ uint8_t *data);
++
++const uint8_t *dal_dcs_get_edid_raw_data(
++ struct dcs *dcs,
++ uint32_t *buff_size);
++
++enum edid_retrieve_status dal_dcs_update_edid_from_last_retrieved(
++ struct dcs *dcs);
++
++/*Update DDC Service. returns the old DdcService being replaced*/
++struct ddc_service *dal_dcs_update_ddc(
++ struct dcs *dcs,
++ struct ddc_service *ddc);
++
++void dal_dcs_set_transaction_type(
++ struct dcs *dcs,
++ enum ddc_transaction_type type);
++
++/*updates the ModeTimingList of given path with
++ModeTiming reported by this DCS*/
++void dal_dcs_update_ts_timing_list_on_display(
++ struct dcs *dcs,
++ uint32_t display_index);
++
++/* DDC query on generic slave address*/
++bool dal_dcs_query_ddc_data(
++ struct dcs *dcs,
++ uint32_t address,
++ uint8_t *write_buf,
++ uint32_t write_buff_size,
++ uint8_t *read_buff,
++ uint32_t read_buff_size);
++
++bool dal_dcs_get_vendor_product_id_info(
++ struct dcs *dcs,
++ struct vendor_product_id_info *info);
++
++bool dal_dcs_get_display_name(struct dcs *dcs, uint8_t *name, uint32_t size);
++
++bool dal_dcs_get_display_characteristics(
++ struct dcs *dcs,
++ struct display_characteristics *characteristics);
++
++bool dal_dcs_get_screen_info(
++ struct dcs *dcs,
++ struct edid_screen_info *info);
++
++enum dcs_edid_connector_type dal_dcs_get_connector_type(struct dcs *dcs);
++
++bool dal_dcs_get_display_pixel_encoding(
++ struct dcs *dcs,
++ struct display_pixel_encoding_support *pe);
++
++enum display_dongle_type dal_dcs_get_dongle_type(struct dcs *dcs);
++
++void dal_dcs_query_sink_capability(
++ struct dcs *dcs,
++ struct display_sink_capability *sink_cap,
++ bool hpd_sense_bit);
++
++void dal_dcs_reset_sink_capability(struct dcs *dcs);
++
++bool dal_dcs_get_sink_capability(
++ struct dcs *dcs,
++ struct display_sink_capability *sink_cap);
++
++bool dal_dcs_emulate_sink_capability(
++ struct dcs *dcs,
++ struct display_sink_capability *sink_cap);
++
++bool dal_dcs_get_display_color_depth(
++ struct dcs *dcs,
++ struct display_color_depth_support *color_depth);
++
++bool dal_dcs_get_display_pixel_encoding(
++ struct dcs *dcs,
++ struct display_pixel_encoding_support *pixel_encoding);
++
++bool dal_dcs_get_cea861_support(
++ struct dcs *dcs,
++ struct cea861_support *cea861_support);
++
++bool dal_dcs_get_cea_vendor_specific_data_block(
++ struct dcs *dcs,
++ struct cea_vendor_specific_data_block *vendor_block);
++
++bool dal_dcs_get_cea_speaker_allocation_data_block(
++ struct dcs *dcs,
++ enum signal_type signal,
++ union cea_speaker_allocation_data_block *spkr_data);
++
++bool dal_dcs_get_cea_colorimetry_data_block(
++ struct dcs *dcs,
++ struct cea_colorimetry_data_block *colorimetry_data_block);
++
++bool dal_dcs_get_cea_video_capability_data_block(
++ struct dcs *dcs,
++ union cea_video_capability_data_block *video_capability_data_block);
++
++uint32_t dal_dcs_get_extensions_num(struct dcs *dcs);
++
++const struct dcs_cea_audio_mode_list *dal_dcs_get_cea_audio_modes(
++ struct dcs *dcs,
++ enum signal_type signal);
++
++bool dal_dcs_is_audio_supported(struct dcs *dcs);
++
++bool dal_dcs_validate_customized_mode(
++ struct dcs *dcs,
++ const struct dcs_customized_mode *customized_mode);
++
++bool dal_dcs_add_customized_mode(
++ struct dcs *dcs,
++ struct dcs_customized_mode *customized_mode);
++
++bool dal_dcs_delete_customized_mode(struct dcs *dcs, uint32_t index);
++
++const struct dcs_customized_mode_list *dal_dcs_get_customized_modes(
++ struct dcs *dcs);
++
++bool dal_dcs_delete_mode_timing_override(
++ struct dcs *dcs,
++ struct dcs_override_mode_timing *dcs_mode_timing);
++
++bool dal_dcs_set_mode_timing_override(
++ struct dcs *dcs,
++ uint32_t display_index,
++ struct dcs_override_mode_timing *dcs_mode_timing);
++
++bool dal_dcs_get_timing_override_for_mode(
++ struct dcs *dcs,
++ uint32_t display_index,
++ struct dc_mode_info *mode_info,
++ struct dcs_override_mode_timing_list *dcs_mode_timing_list);
++
++uint32_t dal_dcs_get_num_mode_timing_overrides(struct dcs *dcs);
++
++bool dal_dcs_get_timing_override_list(
++ struct dcs *dcs,
++ uint32_t display_index,
++ struct dcs_override_mode_timing_list *dcs_mode_timing_list,
++ uint32_t size);
++
++bool dal_dcs_get_supported_force_hdtv_mode(
++ struct dcs *dcs,
++ union hdtv_mode_support *hdtv_mode);
++
++bool dal_dcs_get_user_force_hdtv_mode(
++ struct dcs *dcs,
++ union hdtv_mode_support *hdtv_mode);
++
++bool dal_dcs_set_user_force_hdtv_mode(
++ struct dcs *dcs,
++ const union hdtv_mode_support *hdtv_mode);
++
++bool dal_dcs_get_fid9204_allow_ce_mode_only_option(
++ struct dcs *dcs,
++ bool is_hdmi,
++ bool *enable);
++
++bool dal_dcs_set_fid9204_allow_ce_mode_only_option(
++ struct dcs *dcs,
++ bool is_hdmi,
++ bool enable);
++
++bool dal_dcs_get_panel_misc_info(
++ struct dcs *dcs,
++ union panel_misc_info *panel_info);
++
++enum ddc_result dal_dcs_dpcd_read(
++ struct dcs *dcs,
++ uint32_t address,
++ uint8_t *buffer,
++ uint32_t length);
++
++enum ddc_result dal_dcs_dpcd_write(
++ struct dcs *dcs,
++ uint32_t address,
++ const uint8_t *buffer,
++ uint32_t length);
++
++bool dal_dcs_get_range_limit(
++ struct dcs *dcs,
++ struct display_range_limits *limit);
++
++bool dal_dcs_set_range_limit_override(
++ struct dcs *dcs,
++ struct display_range_limits *limit);
++
++bool dal_dcs_get_user_select_limit(
++ struct dcs *dcs,
++ struct monitor_user_select_limits *limit);
++
++bool dal_dcs_set_user_select_limit(
++ struct dcs *dcs,
++ struct monitor_user_select_limits *limit);
++
++bool dal_dcs_get_dongle_mode_support(
++ struct dcs *dcs,
++ union hdtv_mode_support *hdtv_mode);
++
++bool dal_dcs_get_timing_limits(
++ struct dcs *dcs,
++ struct timing_limits *timing_limits);
++
++bool dal_dcs_get_drr_config(
++ struct dcs *dcs,
++ struct drr_config *config);
++
++bool dal_dcs_force_dp_audio(struct dcs *dcs, bool force_audio_on);
++
++bool dal_dcs_is_dp_audio_forced(struct dcs *dcs);
++
++const struct monitor_patch_info *dal_dcs_get_monitor_patch_info(
++ struct dcs *dcs,
++ enum monitor_patch_type patch_type);
++
++bool dal_dcs_set_monitor_patch_info(
++ struct dcs *dcs,
++ struct monitor_patch_info *patch_info);
++
++union dcs_monitor_patch_flags dal_dcs_get_monitor_patch_flags(struct dcs *dcs);
++
++enum dcs_packed_pixel_format dal_dcs_get_enabled_packed_pixel_format(
++ struct dcs *dcs);
++
++enum dcs_packed_pixel_format dal_dcs_get_monitor_packed_pixel_format(
++ struct dcs *dcs);
++
++bool dal_dcs_report_single_selected_timing(struct dcs *dcs);
++
++bool dal_dcs_can_tile_scale(struct dcs *dcs);
++
++void dal_dcs_set_single_selected_timing_restriction(
++ struct dcs *dcs,
++ bool value);
++
++const struct dcs_edid_supported_max_bw *dal_dcs_get_edid_supported_max_bw(
++ struct dcs *dcs);
++
++bool dal_dcs_is_non_continous_frequency(struct dcs *dcs);
++
++struct dcs_stereo_3d_features dal_dcs_get_stereo_3d_features(
++ struct dcs *dcs,
++ enum dc_timing_3d_format format);
++
++union stereo_3d_support dal_dcs_get_stereo_3d_support(struct dcs *dcs);
++
++void dal_dcs_override_stereo_3d_support(
++ struct dcs *dcs,
++ union stereo_3d_support support);
++
++void dal_dcs_set_remote_display_receiver_capabilities(
++ struct dcs *dcs,
++ const struct dal_remote_display_receiver_capability *cap);
++
++void dal_dcs_clear_remote_display_receiver_capabilities(struct dcs *dcs);
++
++bool dal_dcs_get_display_tile_info(
++ struct dcs *dcs,
++ struct dcs_display_tile *display_tile,
++ bool first_display);
++
++bool dal_dcs_get_container_id(struct dcs *dcs,
++ struct dcs_container_id *container_id);
++
++bool dal_dcs_set_container_id(struct dcs *dcs,
++ struct dcs_container_id *container_id);
++
++void dal_dcs_invalidate_container_id(struct dcs *dcs);
++
++union dcs_monitor_patch_flags dal_dcs_get_monitor_patch_flags(struct dcs *dcs);
++
++#endif /* __DAL_DCS_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dcs_types.h b/drivers/gpu/drm/amd/dal/include/dcs_types.h
+new file mode 100644
+index 0000000..8c65057
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dcs_types.h
+@@ -0,0 +1,742 @@
++/*
++ * 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_DCS_TYPES_H__
++#define __DAL_DCS_TYPES_H__
++
++#include "signal_types.h"
++
++#include "dc_types.h"
++
++#define NUM_OF_BYTE_EDID_COLOR_CHARACTERISTICS 10
++#define MAX_NUMBER_OF_HDMI_VSDB_3D_EXTENDED_SUPPORT 21
++#define MAX_NUMBER_OF_HDMI_VSDB_VICS 7
++
++struct drr_config {
++ /* minimum frame per second for dynamic
++ * refresh rate feature; 0 if drr support not found*/
++ uint32_t min_fps_in_microhz;
++ bool force_lock_on_event;
++ bool lock_to_master_vsync;
++
++ struct {
++ uint8_t FORCED_BY_REGKEY_OR_ESCAPE:1;
++ uint8_t FORCED_BY_VBIOS:1;
++ uint8_t SUPPORTED_BY_EDID:1;
++ } support_method;
++};
++
++struct timing_limits {
++ uint32_t min_pixel_clock_in_khz;
++ uint32_t max_pixel_clock_in_khz;
++};
++
++struct vendor_product_id_info {
++ uint32_t manufacturer_id;
++ uint32_t product_id;
++ uint32_t serial_id;
++ uint32_t manufacture_week;
++ uint32_t manufacture_year;
++};
++
++struct display_range_limits {
++ uint32_t min_v_rate_hz;
++ uint32_t max_v_rate_hz;
++ uint32_t min_h_rate_khz;
++ uint32_t max_h_rateIn_khz;
++ uint32_t max_pix_clk_khz;
++ bool use_override;
++};
++
++struct monitor_user_select_limits {
++ bool use_ati_override;
++ uint32_t max_h_res;
++ uint32_t max_v_res;
++ uint32_t max_refresh_rate;
++};
++
++enum edid_screen_aspect_ratio {
++ EDID_SCREEN_AR_UNKNOWN = 0,
++ EDID_SCREEN_AR_PROJECTOR,
++ EDID_SCREEN_AR_16X9,
++ EDID_SCREEN_AR_16X10,
++ EDID_SCREEN_AR_4X3,
++ EDID_SCREEN_AR_5X4,
++ EDID_SCREEN_AR_9X16,
++ EDID_SCREEN_AR_10X16,
++ EDID_SCREEN_AR_3X4,
++ EDID_SCREEN_AR_4X5
++};
++
++struct edid_screen_info {
++ enum edid_screen_aspect_ratio aspect_ratio;
++ uint32_t width;
++ uint32_t height;
++};
++
++struct display_characteristics {
++ uint8_t gamma;
++ uint8_t color_characteristics[NUM_OF_BYTE_EDID_COLOR_CHARACTERISTICS];
++};
++
++union cv_smart_dongle_modes {
++ uint8_t all;
++ struct cv_smart_dongle_switches {
++ uint8_t MODE_1080I:1;
++ uint8_t MODE_720P:1;
++ uint8_t MODE_540P:1;
++ uint8_t MODE_480P:1;
++ uint8_t MODE_480I:1;
++ uint8_t MODE_16_9:1;
++ } switches;
++};
++
++struct cea_audio_mode {
++ uint8_t format_code; /* ucData[0] [6:3]*/
++ uint8_t channel_count; /* ucData[0] [2:0]*/
++ uint8_t sample_rate; /* ucData[1]*/
++ union {
++ uint8_t sample_size; /* for LPCM*/
++ /* for Audio Formats 2-8 (Max bit rate divided by 8 kHz)*/
++ uint8_t max_bit_rate;
++ uint8_t audio_codec_vendor_specific; /* for Audio Formats 9-15*/
++ };
++};
++
++union cea_speaker_allocation_data_block {
++ struct {
++ uint32_t FL_FR:1;
++ uint32_t LFE:1;
++ uint32_t FC:1;
++ uint32_t RL_RR:1;
++ uint32_t RC:1;
++ uint32_t FLC_FRC:1;
++ uint32_t RLC_RRC:1;
++ } bits;
++ uint32_t raw;
++};
++
++struct cea_colorimetry_data_block {
++ struct {
++ uint32_t XV_YCC601:1;
++ uint32_t XV_YCC709:1;
++ uint32_t S_YCC601:1;
++ uint32_t ADOBE_YCC601:1;
++ uint32_t ADOBE_RGB:1;
++
++ } flag;
++ struct {
++ uint32_t MD0:1;
++ uint32_t MD1:1;
++ uint32_t MD2:1;
++ uint32_t MD3:1;
++ } metadata_flag;
++};
++
++union cea_video_capability_data_block {
++ struct {
++ uint8_t S_CE0:1;
++ uint8_t S_CE1:1;
++ uint8_t S_IT0:1;
++ uint8_t S_IT1:1;
++ uint8_t S_PT0:1;
++ uint8_t S_PT1:1;
++ uint8_t QS:1;
++ uint8_t QY:1;
++ } bits;
++ uint8_t raw;
++};
++
++enum stereo_3d_multi_presence {
++ STEREO_3D_MULTI_NOT_PRESENT = 0,
++ STEREO_3D_MULTI_ALL_FORMATS,
++ STEREO_3D_MULTI_MASKED_FORMATS,
++ STEREO_3D_MULTI_RESERVED
++};
++
++enum cea_hdmi_vic {
++ CEA_HDMI_VIC_RESERVED = 0,
++ CEA_HDMI_VIC_4KX2K_30,
++ CEA_HDMI_VIC_4KX2K_25,
++ CEA_HDMI_VIC_4KX2K_24,
++ CEA_HDMI_VIC_4KX2K_24_SMPTE
++};
++
++struct cea_hdmi_vsdb_extended_caps {
++ uint32_t reserved;
++ uint32_t image_size;
++ enum stereo_3d_multi_presence stereo_3d_multi_present;
++ bool stereo_3d_present;
++ uint32_t hdmi_3d_len;
++ uint32_t hdmi_vic_len;
++};
++
++struct cea_vendor_specific_data_block {
++
++ uint32_t ieee_id;
++
++ struct commonent_phy {
++ uint32_t PHY_ADDR_A:4;
++ uint32_t PHY_ADDR_B:4;
++ uint32_t PHY_ADDR_C:4;
++ uint32_t PHY_ADDR_D:4;
++ } commonent_phy_addr;
++
++ struct byte6 {
++ uint32_t SUPPORTS_AI:1;
++ uint32_t DC_48BIT:1;
++ uint32_t DC_36BIT:1;
++ uint32_t DC_30BIT:1;
++ uint32_t DC_Y444:1;
++ uint32_t DVI_DUAL:1;
++ uint32_t RESERVED:2;
++ } byte6;/* link capabilities*/
++ bool byte6_valid;
++
++ uint32_t max_tmds_clk_mhz;
++
++ struct byte8 {
++ uint32_t LATENCY_FIELDS_PRESENT:1;
++ uint32_t ILATENCY_FIELDS_PRESENT:1;
++ uint32_t HDMI_VIDEO_PRESENT:1;
++ uint32_t RESERVED:1;
++ uint32_t CNC3_GAME:1;
++ uint32_t CNC2_CINEMA:1;
++ uint32_t CNC1_PHOTO:1;
++ uint32_t CNC0_GRAPHICS:1;
++ } byte8;
++ /*bit 6-7: latency flags to indicate valid latency fields*/
++ /*bit 5: support of additional video format capabilities*/
++ /* bit 0-3: flags indicating which content type is supported*/
++ uint32_t video_latency;
++ uint32_t audio_latency;
++ uint32_t i_video_latency;
++ uint32_t i_audio_latency;
++
++ struct cea_hdmi_vsdb_extended_caps hdmi_vsdb_extended_caps;
++
++ enum stereo_3d_multi_presence stereo_3d_multi_present;
++
++ struct {
++ bool FRAME_PACKING:1;
++ bool SIDE_BY_SIDE_HALF:1;
++ bool TOP_AND_BOTTOM:1;
++ } stereo_3d_all_support;
++ uint16_t stereo_3d_mask;
++
++ enum cea_hdmi_vic hdmi_vic[MAX_NUMBER_OF_HDMI_VSDB_VICS];
++ struct stereo_3d_extended_support {
++ struct {
++ bool FRAME_PACKING:1;
++ bool SIDE_BY_SIDE_HALF:1;
++ bool TOP_AND_BOTTOM:1;
++ } format;
++ uint32_t vic_index;
++ uint32_t value;
++ uint32_t size;
++ } stereo_3d_extended_support[MAX_NUMBER_OF_HDMI_VSDB_3D_EXTENDED_SUPPORT];
++};
++
++struct cea861_support {
++
++ uint32_t revision;
++ union {
++ struct {
++ uint32_t NATIVE_COUNT:4;
++ uint32_t BASE_AUDIO:1;
++ uint32_t YCRCB444:1;
++ uint32_t YCRCB422:1;
++ uint32_t UNDER_SCAN:1;
++ } features;
++ uint8_t raw_features;
++ };
++};
++
++struct dcs_customized_mode {
++ struct {
++ uint32_t READ_ONLY:1;
++ uint32_t ADD_BY_DRIVER:1;
++ uint32_t INTERLACED:1;
++ uint32_t BASE_MODE:1;
++ } flags;
++ struct dc_mode_info base_mode_info;
++ struct dc_mode_info customized_mode_info;
++};
++
++struct dcs_override_mode_timing {
++ /* possible timing standards, bit vector of TimingStandard*/
++ uint32_t possible_timing_standards;
++ /* indicate driver default timing is used , no override*/
++ bool use_driver_default_timing;
++ struct dc_mode_timing mode_timing;
++};
++
++struct dcs_override_mode_timing_list {
++ uint32_t max_num_overrides;
++ uint32_t num_overrides;
++ struct dcs_override_mode_timing mode_timings[1];
++};
++
++/* "interface type" is different from Signal Type because
++ * an "interface type" can be driven by more than one Signal Type.
++ * For example, INTERFACE_TYPE_DVI can be driven by
++ * Single or Dual link DVI signal. */
++enum dcs_interface_type {
++ INTERFACE_TYPE_VGA = 0,
++ INTERFACE_TYPE_DVI,
++ INTERFACE_TYPE_CV,
++ INTERFACE_TYPE_TV,
++ INTERFACE_TYPE_LVDS,
++ INTERFACE_TYPE_DP,
++ INTERFACE_TYPE_WIRELESS,
++ INTERFACE_TYPE_CF,
++ INTERFACE_TYPE_EDP
++};
++
++
++union panel_misc_info {
++ struct {
++ uint32_t H_CUT_OFF:1;
++ uint32_t H_SYNC_POLARITY:1;/*0=Active High, 1=Active Low*/
++ uint32_t V_SYNC_POLARITY:1; /*0=Active High, 1=Active Low*/
++ uint32_t V_CUT_OFF:1;
++ uint32_t H_REPLICATION_BY_2:1;
++ uint32_t V_REPLICATION_BY_2:1;
++ uint32_t COMPOSITE_SYNC:1;
++ uint32_t INTERLACE:1;
++ uint32_t DOUBLE_CLOCK:1;
++ uint32_t RGB888:1;
++ uint32_t GREY_LEVEL:2;
++ uint32_t SPATIAL:1;
++ uint32_t TEMPORAL:1;
++ uint32_t API_ENABLED:1;
++ } bits;
++ uint32_t raw;
++};
++
++union hdtv_mode_support {
++ struct {
++ uint32_t HDTV_SUPPORT_480I:1;
++ uint32_t HDTV_SUPPORT_480P:1;
++ uint32_t HDTV_SUPPORT_576I25:1;
++ uint32_t HDTV_SUPPORT_576P50:1;
++ uint32_t HDTV_SUPPORT_720P:1;
++ uint32_t HDTV_SUPPORT_720P50:1;
++ uint32_t HDTV_SUPPORT_1080I:1;
++ uint32_t HDTV_SUPPORT_1080I25:1;
++ uint32_t HDTV_SUPPORT_1080P:1;
++ uint32_t HDTV_SUPPORT_1080P50:1;
++ uint32_t HDTV_SUPPORT_1080P24:1;
++ uint32_t HDTV_SUPPORT_1080P25:1;
++ uint32_t HDTV_SUPPORT_1080P30:1;
++ uint32_t HDTV_SUPPORT_16X9:1;
++ } bits;
++ uint32_t raw;
++};
++
++enum edid_retrieve_status {
++ EDID_RETRIEVE_SUCCESS = 0,
++ EDID_RETRIEVE_FAIL,
++ EDID_RETRIEVE_SAME_EDID,
++ EDID_RETRIEVE_FAIL_WITH_PREVIOUS_SUCCESS
++};
++
++#define DCS_DECODE_EDID_RETRIEVE_STATUS(status) \
++ (status == EDID_RETRIEVE_SUCCESS) ? "EDID_RETRIEVE_SUCCESS" : \
++ (status == EDID_RETRIEVE_FAIL) ? "EDID_RETRIEVE_FAIL" : \
++ (status == EDID_RETRIEVE_SAME_EDID) ? "EDID_RETRIEVE_SAME_EDID" : \
++ (status == EDID_RETRIEVE_FAIL_WITH_PREVIOUS_SUCCESS) ? \
++ "EDID_RETRIEVE_FAIL_WITH_PREVIOUS_SUCCESS" : "Unknown"
++
++
++#ifndef TV_SIGNALFORMAT_DEFINED
++#define TV_SIGNALFORMAT_DEFINED
++enum tv_signal_format {
++ TV_SIGNAL_FORMAT_UNKNOWN,
++ TV_SIGNAL_FORMAT_NTSC,
++ TV_SIGNAL_FORMAT_NTSC_J,
++ TV_SIGNAL_FORMAT_PAL,
++ TV_SIGNAL_FORMAT_PAL_M,
++ TV_SIGNAL_FORMAT_PAL_CN,
++ TV_SIGNAL_FORMAT_SECAM
++};
++#endif
++
++enum tv_signal_format_result {
++ TV_SIGNAL_FORMAT_RESULT_OK,
++ TV_SIGNAL_FORMAT_SET_MODE_REQ,
++ TV_SIGNAL_FORMAT_REBOOT_REQ,
++ TV_SIGNAL_FORMAT_ERROR
++};
++
++enum pixel_encoding_mask {
++ PIXEL_ENCODING_MASK_YCBCR444 = 0x01,
++ PIXEL_ENCODING_MASK_YCBCR422 = 0x02,
++ PIXEL_ENCODING_MASK_RGB = 0x04,
++};
++
++struct display_pixel_encoding_support {
++ uint32_t mask;
++};
++
++enum color_depth_index {
++ COLOR_DEPTH_INDEX_UNKNOWN,
++ COLOR_DEPTH_INDEX_666 = 0x01,
++ COLOR_DEPTH_INDEX_888 = 0x02,
++ COLOR_DEPTH_INDEX_101010 = 0x04,
++ COLOR_DEPTH_INDEX_121212 = 0x08,
++ COLOR_DEPTH_INDEX_141414 = 0x10,
++ COLOR_DEPTH_INDEX_161616 = 0x20,
++ COLOR_DEPTH_INDEX_LAST = 0x40,
++};
++
++struct display_color_depth_support {
++ uint32_t mask;
++ bool deep_color_native_res_only;
++};
++
++struct display_color_and_pixel_support {
++ struct display_color_depth_support color_depth_support;
++ struct display_pixel_encoding_support pixel_encoding_support;
++ bool deep_color_y444_support;
++};
++
++enum dcs_packed_pixel_format {
++ DCS_PACKED_PIXEL_FORMAT_NOT_PACKED = 0,
++ DCS_PACKED_PIXEL_FORMAT_SPLIT_G70_B54_R70_B10 = 1,
++ DCS_PACKED_PIXEL_FORMAT_R70_G76 = 2,
++ DCS_PACKED_PIXEL_FORMAT_SPLIT_B70_G10_R70_G76 = 3,
++ DCS_PACKED_PIXEL_FORMAT_G70_B54_R70_B10 = 4,
++ DCS_PACKED_PIXEL_FORMAT_G70_B54 = 5,
++ DCS_PACKED_PIXEL_FORMAT_B70_R30_G70_R74 = 6,
++ DCS_PACKED_PIXEL_FORMAT_B70_G70_R70 = 7,
++ DCS_PACKED_PIXEL_FORMAT_B70_R32_G70_R76 = 8,
++};
++
++enum monitor_manufacturer_id {
++ MONITOR_MANUFACTURER_ID_0 = 0x0000,
++ MONITOR_MANUFACTURER_ID_1 = 0x3834,
++ MONITOR_MANUFACTURER_ID_2 = 0x4d24,
++ MONITOR_MANUFACTURER_ID_3 = 0x293E,
++ MONITOR_MANUFACTURER_ID_4 = 0x635a,
++ MONITOR_MANUFACTURER_ID_5 = 0x1006,
++ MONITOR_MANUFACTURER_ID_6 = 0xc32a,
++ MONITOR_MANUFACTURER_ID_7 = 0x4d24,
++ MONITOR_MANUFACTURER_ID_8 = 0x110e,
++ MONITOR_MANUFACTURER_ID_9 = 0xaf0d,
++ MONITOR_MANUFACTURER_ID_10 = 0x6D1E,
++ MONITOR_MANUFACTURER_ID_11 = 0xA338,
++ MONITOR_MANUFACTURER_ID_12 = 0xC315,
++ MONITOR_MANUFACTURER_ID_13 = 0xD94D,
++ MONITOR_MANUFACTURER_ID_14 = 0x104D,
++ MONITOR_MANUFACTURER_ID_15 = 0x855C,
++ MONITOR_MANUFACTURER_ID_16 = 0x4251,
++ MONITOR_MANUFACTURER_ID_17 = 0xA934,
++ MONITOR_MANUFACTURER_ID_18 = 0x0C41,
++ /* TODO: Update when EDID is available */
++ MONITOR_MANUFACTURER_ID_19 = 0xDEAD,
++ MONITOR_MANUFACTURER_ID_20 = 0x6904,
++ MONITOR_MANUFACTURER_ID_21 = 0xAC10,
++ MONITOR_MANUFACTURER_ID_22 = 0x2D4C,
++ MONITOR_MANUFACTURER_ID_23 = 0x144E,
++ MONITOR_MANUFACTURER_ID_24 = 0x6c50,
++ MONITOR_MANUFACTURER_ID_26 = 0x0c41,
++ MONITOR_MANUFACTURER_ID_27 = 0x143E,
++ MONITOR_MANUFACTURER_ID_25 = 0xffff,
++ MONITOR_MANUFACTURER_ID_28 = 0x3421,
++ MONITOR_MANUFACTURER_ID_29 = 0x2D19,
++ MONITOR_MANUFACTURER_ID_30 = 0x8B52,
++ MONITOR_MANUFACTURER_ID_31 = 0x7204,
++ MONITOR_MANUFACTURER_ID_32 = 0xF022,
++ MONITOR_MANUFACTURER_ID_33 = 0x0E11,
++ MONITOR_MANUFACTURER_ID_34 = 0xD241,
++ MONITOR_MANUFACTURER_ID_35 = 0xAE30,
++ MONITOR_MANUFACTURER_ID_36 = 0xF91E,
++ MONITOR_MANUFACTURER_ID_37 = 0xAB4C,
++};
++
++enum monitor_product_id {
++ MONITOR_PRODUCT_ID_0 = 0x0000,
++ MONITOR_PRODUCT_ID_1 = 0x0BCC,
++ MONITOR_PRODUCT_ID_2 = 0x251F,
++ MONITOR_PRODUCT_ID_3 = 0x5241,
++ MONITOR_PRODUCT_ID_4 = 0x6919,
++ MONITOR_PRODUCT_ID_5 = 0xee18,
++ MONITOR_PRODUCT_ID_6 = 0xf008,
++ MONITOR_PRODUCT_ID_7 = 0x2f0c,
++ MONITOR_PRODUCT_ID_7_2 = 0x3411,
++ MONITOR_PRODUCT_ID_9 = 0x4208,
++ MONITOR_PRODUCT_ID_10 = 0xE51D,
++ MONITOR_PRODUCT_ID_11 = 0x7E22,
++ MONITOR_PRODUCT_ID_12 = 0x0E23,
++ MONITOR_PRODUCT_ID_13 = 0x9d08,
++ MONITOR_PRODUCT_ID_14 = 0x9236,
++ MONITOR_PRODUCT_ID_15 = 0x9227,
++ MONITOR_PRODUCT_ID_16 = 0x0220,
++ MONITOR_PRODUCT_ID_17 = 0x4920,
++ MONITOR_PRODUCT_ID_18 = 0x251f,
++ MONITOR_PRODUCT_ID_19 = 0x1395,
++ MONITOR_PRODUCT_ID_20 = 0xc04e,
++ MONITOR_PRODUCT_ID_21 = 0x5787,
++ MONITOR_PRODUCT_ID_22 = 0x5A71,
++ MONITOR_PRODUCT_ID_23 = 0x6622,
++ MONITOR_PRODUCT_ID_24 = 0x20C1,
++ MONITOR_PRODUCT_ID_25 = 0x2110,
++ MONITOR_PRODUCT_ID_26 = 0x2006,
++ MONITOR_PRODUCT_ID_27 = 0x1827,
++ MONITOR_PRODUCT_ID_28 = 0x0EA0,
++ MONITOR_PRODUCT_ID_29 = 0x03D0,
++ MONITOR_PRODUCT_ID_30 = 0x01D2,
++ MONITOR_PRODUCT_ID_31 = 0x2801,
++ MONITOR_PRODUCT_ID_32 = 0x0FB3,
++ MONITOR_PRODUCT_ID_33 = 0x0FB1,
++ MONITOR_PRODUCT_ID_34 = 0xA045,
++ MONITOR_PRODUCT_ID_35 = 0x0001,
++ MONITOR_PRODUCT_ID_36 = 0xA296,
++ MONITOR_PRODUCT_ID_38 = 0x21DC,
++ MONITOR_PRODUCT_ID_37 = 0x21EA,
++ MONITOR_PRODUCT_ID_39 = 0x4093,
++ MONITOR_PRODUCT_ID_40 = 0x4094,
++ MONITOR_PRODUCT_ID_41 = 0x4094,
++ MONITOR_PRODUCT_ID_42 = 0x32A2,
++ MONITOR_PRODUCT_ID_43 = 0xE009,
++ MONITOR_PRODUCT_ID_44 = 0xA010,
++ MONITOR_PRODUCT_ID_45 = 0x405C,
++ MONITOR_PRODUCT_ID_46 = 0xF017,
++ MONITOR_PRODUCT_ID_47 = 0xD026,
++ MONITOR_PRODUCT_ID_48 = 0x4036,
++ MONITOR_PRODUCT_ID_49 = 0x4065,
++ MONITOR_PRODUCT_ID_50 = 0xA02A,
++ MONITOR_PRODUCT_ID_51 = 0xA02C,
++ MONITOR_PRODUCT_ID_46_HDMI = 0xF016,
++ MONITOR_PRODUCT_ID_53 = 0xF048,
++ MONITOR_PRODUCT_ID_54 = 0xA0A2,
++ MONITOR_PRODUCT_ID_55 = 0x4083,
++ MONITOR_PRODUCT_ID_56 = 0x0E74,
++ MONITOR_PRODUCT_ID_57 = 0x2771,
++ MONITOR_PRODUCT_ID_58 = 0x0814,
++ MONITOR_PRODUCT_ID_59 = 0xffff,
++ MONITOR_PRODUCT_ID_60 = 0x3339,
++ MONITOR_PRODUCT_ID_61 = 0x01F5,
++ MONITOR_PRODUCT_ID_62 = 0x02A5,
++ MONITOR_PRODUCT_ID_63 = 0x06AC,
++ MONITOR_PRODUCT_ID_64 = 0x04D5,
++ MONITOR_PRODUCT_ID_65 = 0x079D,
++ MONITOR_PRODUCT_ID_66 = 0x079F,
++ MONITOR_PRODUCT_ID_67 = 0x0797,
++ MONITOR_PRODUCT_ID_68 = 0x0B80,
++ MONITOR_PRODUCT_ID_69 = 0x7D06,
++ MONITOR_PRODUCT_ID_70 = 0x0131,
++ MONITOR_PRODUCT_ID_71 = 0x8545,
++ MONITOR_PRODUCT_ID_72 = 0x0002,
++ MONITOR_PRODUCT_ID_73 = 0x0125,
++ MONITOR_PRODUCT_ID_74 = 0x00D0,
++ MONITOR_PRODUCT_ID_75 = 0x26F7,
++ MONITOR_PRODUCT_ID_76 = 0x26F9,
++ MONITOR_PRODUCT_ID_77 = 0x2807,
++ MONITOR_PRODUCT_ID_78 = 0x26F3,
++ MONITOR_PRODUCT_ID_79 = 0x2676,
++ MONITOR_PRODUCT_ID_80 = 0x0A72,
++ MONITOR_PRODUCT_ID_81 = 0x2693,
++ MONITOR_PRODUCT_ID_82 = 0x2615,
++ MONITOR_PRODUCT_ID_83 = 0x2613,
++ MONITOR_PRODUCT_ID_84 = 0x262D,
++ MONITOR_PRODUCT_ID_85 = 0x264B,
++ MONITOR_PRODUCT_ID_86 = 0x2869,
++ MONITOR_PRODUCT_ID_87 = 0x286C,
++ MONITOR_PRODUCT_ID_88 = 0x288F,
++ MONITOR_PRODUCT_ID_89 = 0x2954,
++ MONITOR_PRODUCT_ID_90 = 0x6522,
++ MONITOR_PRODUCT_ID_91 = 0x0FAE,
++ MONITOR_PRODUCT_ID_92 = 0x0A0C,
++ MONITOR_PRODUCT_ID_93 = 0x00BF,
++ MONITOR_PRODUCT_ID_94 = 0x0,
++};
++
++enum monitor_patch_type {
++ MONITOR_PATCH_TYPE_NONE,
++ MONITOR_PATCH_TYPE_ERROR_CHECKSUM,
++ MONITOR_PATCH_TYPE_HDTV_WITH_PURE_DFP_EDID,
++ MONITOR_PATCH_TYPE_DO_NOT_USE_DETAILED_TIMING,
++ MONITOR_PATCH_TYPE_DO_NOT_USE_RANGE_LIMITATION,
++ MONITOR_PATCH_TYPE_EDID_EXTENTION_ERROR_CHECK_SUM,
++ MONITOR_PATCH_TYPE_TURN_OFF_DISPLAY_BEFORE_MODE_CHANGE,
++ MONITOR_PATCH_TYPE_RESTRICT_VESA_MODE_TIMING,
++ MONITOR_PATCH_TYPE_DO_NOT_USE_EDID_MAX_PIX_CLK,
++ MONITOR_PATCH_TYPE_VENDOR_0,
++ MONITOR_PATCH_TYPE_RANDOM_CRT,
++ MONITOR_PATCH_TYPE_VENDOR_1,
++ MONITOR_PATCH_TYPE_LIMIT_PANEL_SUPPORT_RGB_ONLY,
++ MONITOR_PATCH_TYPE_PACKED_PIXEL_FORMAT,
++ MONITOR_PATCH_TYPE_LARGE_PANEL,
++ MONITOR_PATCH_TYPE_STEREO_SUPPORT,
++ /* 0 (default) - mean patch will not be applied, however it can be
++ * explicitly set to 1
++ */
++ MONITOR_PATCH_TYPE_DUAL_EDID_PANEL,
++ MONITOR_PATCH_TYPE_IGNORE_19X12_STD_TIMING,
++ MONITOR_PATCH_TYPE_MULTIPLE_PACKED_TYPE,
++ MONITOR_PATCH_TYPE_RESET_TX_ON_DISPLAY_POWER_ON,
++ MONITOR_PATCH_TYPE_VENDOR_2,
++ MONITOR_PATCH_TYPE_RESTRICT_PROT_DUAL_LINK_DVI,
++ MONITOR_PATCH_TYPE_FORCE_LINK_RATE,
++ MONITOR_PATCH_TYPE_DELAY_AFTER_DP_RECEIVER_POWER_UP,
++ MONITOR_PATCH_TYPE_KEEP_DP_RECEIVER_POWERED,
++ MONITOR_PATCH_TYPE_DELAY_BEFORE_READ_EDID,
++ MONITOR_PATCH_TYPE_DELAY_AFTER_PIXEL_FORMAT_CHANGE,
++ MONITOR_PATCH_TYPE_INCREASE_DEFER_WRITE_RETRY_I2C_OVER_AUX,
++ MONITOR_PATCH_TYPE_NO_DEFAULT_TIMINGS,
++ MONITOR_PATCH_TYPE_ADD_CEA861_DETAILED_TIMING_VIC16,
++ MONITOR_PATCH_TYPE_ADD_CEA861_DETAILED_TIMING_VIC31,
++ MONITOR_PATCH_TYPE_DELAY_BEFORE_UNMUTE,
++ MONITOR_PATCH_TYPE_RETRY_LINK_TRAINING_ON_FAILURE,
++ MONITOR_PATCH_TYPE_ALLOW_AUX_WHEN_HPD_LOW,
++ MONITOR_PATCH_TYPE_TILED_DISPLAY,
++ MONITOR_PATCH_TYPE_DISABLE_PSR_ENTRY_ABORT,
++ MONITOR_PATCH_TYPE_EDID_EXTENTION_ERROR_CHECKSUM,
++ MONITOR_PATCH_TYPE_ALLOW_ONLY_CE_MODE,
++ MONITOR_PATCH_TYPE_VID_STREAM_DIFFER_TO_SYNC,
++ MONITOR_PATCH_TYPE_EXTRA_DELAY_ON_DISCONNECT,
++ MONITOR_PATCH_TYPE_DELAY_AFTER_DISABLE_BACKLIGHT_DFS_BYPASS,
++ MONITOR_PATCH_TYPE_SINGLE_MODE_PACKED_PIXEL
++};
++
++/* Single entry in the monitor table */
++struct monitor_patch_info {
++ enum monitor_manufacturer_id manufacturer_id;
++ enum monitor_product_id product_id;
++ enum monitor_patch_type type;
++ uint32_t param;
++};
++
++union dcs_monitor_patch_flags {
++ struct {
++ bool ERROR_CHECKSUM:1;
++ bool HDTV_WITH_PURE_DFP_EDID:1;
++ bool DO_NOT_USE_DETAILED_TIMING:1;
++ bool DO_NOT_USE_RANGE_LIMITATION:1;
++ bool EDID_EXTENTION_ERROR_CHECKSUM:1;
++ bool TURN_OFF_DISPLAY_BEFORE_MODE_CHANGE:1;
++ bool RESTRICT_VESA_MODE_TIMING:1;
++ bool DO_NOT_USE_EDID_MAX_PIX_CLK:1;
++ bool VENDOR_0:1;
++ bool RANDOM_CRT:1;/* 10 bits used including this one-*/
++ bool VENDOR_1:1;
++ bool LIMIT_PANEL_SUPPORT_RGB_ONLY:1;
++ bool PACKED_PIXEL_FORMAT:1;
++ bool LARGE_PANEL:1;
++ bool STEREO_SUPPORT:1;
++ bool DUAL_EDID_PANEL:1;
++ bool IGNORE_19X12_STD_TIMING:1;
++ bool MULTIPLE_PACKED_TYPE:1;
++ bool RESET_TX_ON_DISPLAY_POWER_ON:1;
++ bool ALLOW_ONLY_CE_MODE:1;/* 20 bits used including this one*/
++ bool RESTRICT_PROT_DUAL_LINK_DVI:1;
++ bool FORCE_LINK_RATE:1;
++ bool DELAY_AFTER_DP_RECEIVER_POWER_UP:1;
++ bool KEEP_DP_RECEIVER_POWERED:1;
++ bool DELAY_BEFORE_READ_EDID:1;
++ bool DELAY_AFTER_PIXEL_FORMAT_CHANGE:1;
++ bool INCREASE_DEFER_WRITE_RETRY_I2C_OVER_AUX:1;
++ bool NO_DEFAULT_TIMINGS:1;
++ bool ADD_CEA861_DETAILED_TIMING_VIC16:1;
++ bool ADD_CEA861_DETAILED_TIMING_VIC31:1; /* 30 bits*/
++ bool DELAY_BEFORE_UNMUTE:1;
++ bool RETRY_LINK_TRAINING_ON_FAILURE:1;
++ bool ALLOW_AUX_WHEN_HPD_LOW:1;
++ bool TILED_DISPLAY:1;
++ bool DISABLE_PSR_ENTRY_ABORT:1;
++ bool INTERMITTENT_EDID_ERROR:1;/* 36 bits total*/
++ bool VID_STREAM_DIFFER_TO_SYNC:1;/* 37 bits total*/
++ bool EXTRA_DELAY_ON_DISCONNECT:1;/* 38 bits total*/
++ bool DELAY_AFTER_DISABLE_BACKLIGHT_DFS_BYPASS:1;/* 39 bits total*/
++ } flags;
++ uint64_t raw;
++};
++
++struct dcs_edid_supported_max_bw {
++ uint32_t pix_clock_khz;
++ uint32_t bits_per_pixel;
++};
++
++struct dcs_stereo_3d_features {
++ struct {
++/* 3D Format supported by monitor (implies supported by driver)*/
++ uint32_t SUPPORTED:1;
++/* 3D Format supported on all timings
++(no need to check every timing for 3D support)*/
++ uint32_t ALL_TIMINGS:1;
++/* 3D Format supported in clone mode*/
++ uint32_t CLONE_MODE:1;
++/* Scaling allowed when driving 3D Format*/
++ uint32_t SCALING:1;
++/* Left and right images packed by SW within single frame*/
++ uint32_t SINGLE_FRAME_SW_PACKED:1;
++ } flags;
++};
++
++struct dcs_container_id {
++ /*128bit GUID in binary form*/
++ uint8_t guid[16];
++ /* 8 byte port ID -> ELD.PortID*/
++ uint32_t port_id[2];
++ /* 2 byte manufacturer name -> ELD.ManufacturerName*/
++ uint16_t manufacturer_name;
++ /* 2 byte product code -> ELD.ProductCode*/
++ uint16_t product_code;
++};
++
++struct dcs_display_tile {
++/*unique Id of Tiled Display. 0 - means display is not part in Tiled Display*/
++ uint64_t id;
++ uint32_t rows;/* size of Tiled Display in tiles*/
++ uint32_t cols;/* size of Tiled Display in tiles*/
++ uint32_t width;/* size of current Tile in pixels*/
++ uint32_t height;/* size of current Tile in pixels*/
++ uint32_t row;/* location of current Tile*/
++ uint32_t col;/* location of current Tile*/
++ struct {
++ /*in pixels*/
++ uint32_t left;
++ uint32_t right;
++ uint32_t top;
++ uint32_t bottom;
++ } bezel;/* bezel information of current tile*/
++
++ struct {
++ uint32_t SEPARATE_ENCLOSURE:1;
++ uint32_t BEZEL_INFO_PRESENT:1;
++ uint32_t CAN_SCALE:1;
++ } flags;
++
++ struct {
++ uint32_t manufacturer_id;
++ uint32_t product_id;
++ uint32_t serial_id;
++ } topology_id;
++};
++
++#endif /* __DAL_DCS_TYPES_H__ */
++
+diff --git a/drivers/gpu/drm/amd/dal/include/ddc_interface.h b/drivers/gpu/drm/amd/dal/include/ddc_interface.h
+new file mode 100644
+index 0000000..22fd31f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/ddc_interface.h
+@@ -0,0 +1,74 @@
++/*
++ * 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_DDC_INTERFACE_H__
++#define __DAL_DDC_INTERFACE_H__
++
++#include "gpio_types.h"
++
++struct ddc;
++
++enum gpio_result dal_ddc_open(
++ struct ddc *ddc,
++ enum gpio_mode mode,
++ enum gpio_ddc_config_type config_type);
++
++enum gpio_result dal_ddc_get_clock(
++ const struct ddc *ddc,
++ uint32_t *value);
++
++enum gpio_result dal_ddc_set_clock(
++ const struct ddc *ddc,
++ uint32_t value);
++
++enum gpio_result dal_ddc_get_data(
++ const struct ddc *ddc,
++ uint32_t *value);
++
++enum gpio_result dal_ddc_set_data(
++ const struct ddc *ddc,
++ uint32_t value);
++
++enum gpio_result dal_ddc_change_mode(
++ struct ddc *ddc,
++ enum gpio_mode mode);
++
++bool dal_ddc_is_hw_supported(
++ const struct ddc *ddc);
++
++enum gpio_ddc_line dal_ddc_get_line(
++ const struct ddc *ddc);
++
++bool dal_ddc_check_line_aborted(
++ const struct ddc *ddc);
++
++enum gpio_result dal_ddc_set_config(
++ struct ddc *ddc,
++ enum gpio_ddc_config_type config_type);
++
++void dal_ddc_close(
++ struct ddc *ddc);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/ddc_service_interface.h b/drivers/gpu/drm/amd/dal/include/ddc_service_interface.h
+new file mode 100644
+index 0000000..ca3e6ce
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/ddc_service_interface.h
+@@ -0,0 +1,100 @@
++/*
++ * 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_DDC_SERVICE_INTERFACE_H__
++#define __DAL_DDC_SERVICE_INTERFACE_H__
++
++#include "ddc_service_types.h"
++
++struct ddc_service;
++struct adapter_service;
++struct graphics_object_id;
++enum ddc_result;
++struct av_sync_data;
++struct dp_receiver_id_info;
++
++struct ddc_service_init_data {
++ struct adapter_service *as;
++ struct graphics_object_id id;
++ struct dc_context *ctx;
++};
++struct ddc_service *dal_ddc_service_create(
++ struct ddc_service_init_data *ddc_init_data);
++
++void dal_ddc_service_destroy(struct ddc_service **ddc);
++
++enum ddc_service_type dal_ddc_service_get_type(struct ddc_service *ddc);
++
++void dal_ddc_service_set_transaction_type(
++ struct ddc_service *ddc,
++ enum ddc_transaction_type type);
++
++bool dal_ddc_service_is_in_aux_transaction_mode(struct ddc_service *ddc);
++
++uint32_t dal_ddc_service_edid_query(struct ddc_service *ddc);
++
++uint32_t dal_ddc_service_get_edid_buf_len(struct ddc_service *ddc);
++
++void dal_ddc_service_get_edid_buf(struct ddc_service *ddc, uint8_t *edid_buf);
++
++void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
++ struct ddc_service *ddc,
++ struct display_sink_capability *sink_cap);
++
++bool dal_ddc_service_query_ddc_data(
++ struct ddc_service *ddc,
++ uint32_t address,
++ uint8_t *write_buf,
++ uint32_t write_size,
++ uint8_t *read_buf,
++ uint32_t read_size);
++
++bool dal_ddc_service_get_dp_receiver_id_info(
++ struct ddc_service *ddc,
++ struct dp_receiver_id_info *info);
++
++enum ddc_result dal_ddc_service_read_dpcd_data(
++ struct ddc_service *ddc,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t len);
++
++enum ddc_result dal_ddc_service_write_dpcd_data(
++ struct ddc_service *ddc,
++ uint32_t address,
++ const uint8_t *data,
++ uint32_t len);
++
++void dal_ddc_service_write_scdc_data(
++ struct ddc_service *ddc_service,
++ uint32_t pix_clk,
++ bool lte_340_scramble);
++
++void dal_ddc_service_read_scdc_data(
++ struct ddc_service *ddc_service);
++
++void ddc_service_set_dongle_type(struct ddc_service *ddc,
++ enum display_dongle_type dongle_type);
++
++#endif /* __DAL_DDC_SERVICE_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/ddc_service_types.h b/drivers/gpu/drm/amd/dal/include/ddc_service_types.h
+new file mode 100644
+index 0000000..47ad2ed
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/ddc_service_types.h
+@@ -0,0 +1,220 @@
++/*
++ * 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_DDC_SERVICE_TYPES_H__
++#define __DAL_DDC_SERVICE_TYPES_H__
++
++#include "include/hw_sequencer_types.h"
++
++#define DP_BRANCH_DEVICE_ID_1 0x0010FA
++#define DP_BRANCH_DEVICE_ID_2 0x0022B9
++#define DP_SINK_DEVICE_ID_1 0x4CE000
++#define DP_BRANCH_DEVICE_ID_3 0x00001A
++#define DP_BRANCH_DEVICE_ID_4 0x0080e1
++#define DP_BRANCH_DEVICE_ID_5 0x006037
++#define DP_SINK_DEVICE_ID_2 0x001CF8
++
++
++enum ddc_result {
++ DDC_RESULT_UNKNOWN = 0,
++ DDC_RESULT_SUCESSFULL,
++ DDC_RESULT_FAILED_CHANNEL_BUSY,
++ DDC_RESULT_FAILED_TIMEOUT,
++ DDC_RESULT_FAILED_PROTOCOL_ERROR,
++ DDC_RESULT_FAILED_NACK,
++ DDC_RESULT_FAILED_INCOMPLETE,
++ DDC_RESULT_FAILED_OPERATION,
++ DDC_RESULT_FAILED_INVALID_OPERATION,
++ DDC_RESULT_FAILED_BUFFER_OVERFLOW
++};
++
++enum ddc_service_type {
++ DDC_SERVICE_TYPE_CONNECTOR,
++ DDC_SERVICE_TYPE_DISPLAY_PORT_MST,
++};
++
++enum ddc_transaction_type {
++ DDC_TRANSACTION_TYPE_NONE = 0,
++ DDC_TRANSACTION_TYPE_I2C,
++ DDC_TRANSACTION_TYPE_I2C_OVER_AUX,
++ DDC_TRANSACTION_TYPE_I2C_OVER_AUX_WITH_DEFER,
++ DDC_TRANSACTION_TYPE_I2C_OVER_AUX_RETRY_DEFER
++};
++
++enum display_dongle_type {
++ DISPLAY_DONGLE_NONE = 0,
++ /* Active converter types*/
++ DISPLAY_DONGLE_DP_VGA_CONVERTER,
++ DISPLAY_DONGLE_DP_DVI_CONVERTER,
++ DISPLAY_DONGLE_DP_HDMI_CONVERTER,
++ /* DP-HDMI/DVI passive dongles (Type 1 and Type 2)*/
++ DISPLAY_DONGLE_DP_DVI_DONGLE,
++ DISPLAY_DONGLE_DP_HDMI_DONGLE,
++ /* Other types of dongle*/
++ DISPLAY_DONGLE_DP_HDMI_MISMATCHED_DONGLE,
++};
++
++enum dcs_dpcd_revision {
++ DCS_DPCD_REV_10 = 0x10,
++ DCS_DPCD_REV_11 = 0x11,
++ DCS_DPCD_REV_12 = 0x12
++};
++
++/**
++ * display sink capability
++ */
++struct display_sink_capability {
++ /* dongle type (DP converter, CV smart dongle) */
++ enum display_dongle_type dongle_type;
++
++ /**********************************************************
++ capabilities going INTO SINK DEVICE (stream capabilities)
++ **********************************************************/
++ /* Dongle's downstream count. */
++ uint32_t downstrm_sink_count;
++ /* Is dongle's downstream count info field (downstrm_sink_count)
++ * valid. */
++ bool downstrm_sink_count_valid;
++
++ /* Maximum additional audio delay in microsecond (us) */
++ uint32_t additional_audio_delay;
++ /* Audio latency value in microsecond (us) */
++ uint32_t audio_latency;
++ /* Interlace video latency value in microsecond (us) */
++ uint32_t video_latency_interlace;
++ /* Progressive video latency value in microsecond (us) */
++ uint32_t video_latency_progressive;
++ /* Dongle caps: Maximum pixel clock supported over dongle for HDMI */
++ uint32_t max_hdmi_pixel_clock;
++ /* Dongle caps: Maximum deep color supported over dongle for HDMI */
++ enum dc_color_depth max_hdmi_deep_color;
++
++ /************************************************************
++ capabilities going OUT OF SOURCE DEVICE (link capabilities)
++ ************************************************************/
++ /* support for Spread Spectrum(SS) */
++ bool ss_supported;
++ /* DP link settings (laneCount, linkRate, Spread) */
++ uint32_t dp_link_lane_count;
++ uint32_t dp_link_rate;
++ uint32_t dp_link_spead;
++
++ enum dcs_dpcd_revision dpcd_revision;
++ /* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
++ indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
++ bool is_dp_hdmi_s3d_converter;
++ /* to check if we have queried the display capability
++ * for eDP panel already. */
++ bool is_edp_sink_cap_valid;
++};
++
++struct dp_receiver_id_info {
++ uint32_t dpcd_rev;
++ uint32_t sink_id;
++ int8_t sink_id_str[6];
++ int8_t sink_hw_revision;
++ int8_t sink_fw_revision[2];
++ uint32_t branch_id;
++ int8_t branch_name[6];
++ enum display_dongle_type dongle_type;
++};
++
++struct av_sync_data {
++ uint8_t av_granularity;/* DPCD 00023h */
++ uint8_t aud_dec_lat1;/* DPCD 00024h */
++ uint8_t aud_dec_lat2;/* DPCD 00025h */
++ uint8_t aud_pp_lat1;/* DPCD 00026h */
++ uint8_t aud_pp_lat2;/* DPCD 00027h */
++ uint8_t vid_inter_lat;/* DPCD 00028h */
++ uint8_t vid_prog_lat;/* DPCD 00029h */
++ uint8_t aud_del_ins1;/* DPCD 0002Bh */
++ uint8_t aud_del_ins2;/* DPCD 0002Ch */
++ uint8_t aud_del_ins3;/* DPCD 0002Dh */
++};
++
++/** EDID retrieval related constants, also used by MstMgr **/
++
++#define DDC_EDID_SEGMENT_SIZE 256
++#define DDC_EDID_BLOCK_SIZE 128
++#define DDC_EDID_BLOCKS_PER_SEGMENT \
++ (DDC_EDID_SEGMENT_SIZE / DDC_EDID_BLOCK_SIZE)
++
++#define DDC_EDID_EXT_COUNT_OFFSET 0x7E
++
++#define DDC_EDID_ADDRESS_START 0x50
++#define DDC_EDID_ADDRESS_END 0x52
++#define DDC_EDID_SEGMENT_ADDRESS 0x30
++
++/* signatures for Edid 1x */
++#define DDC_EDID1X_VENDORID_SIGNATURE_OFFSET 8
++#define DDC_EDID1X_VENDORID_SIGNATURE_LEN 4
++#define DDC_EDID1X_EXT_CNT_AND_CHECKSUM_OFFSET 126
++#define DDC_EDID1X_EXT_CNT_AND_CHECKSUM_LEN 2
++#define DDC_EDID1X_CHECKSUM_OFFSET 127
++/* signatures for Edid 20*/
++#define DDC_EDID_20_SIGNATURE_OFFSET 0
++#define DDC_EDID_20_SIGNATURE 0x20
++
++#define DDC_EDID20_VENDORID_SIGNATURE_OFFSET 1
++#define DDC_EDID20_VENDORID_SIGNATURE_LEN 4
++#define DDC_EDID20_CHECKSUM_OFFSET 255
++#define DDC_EDID20_CHECKSUM_LEN 1
++
++/*DP to VGA converter*/
++static const uint8_t DP_VGA_CONVERTER_ID_1[] = "mVGAa";
++/*DP to Dual link DVI converter*/
++static const uint8_t DP_DVI_CONVERTER_ID_1[] = "m2DVIa";
++/*Travis*/
++static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT";
++/*Nutmeg*/
++static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
++/*DP to VGA converter*/
++static const uint8_t DP_VGA_CONVERTER_ID_4[] = "DpVga";
++/*DP to Dual link DVI converter*/
++static const uint8_t DP_DVI_CONVERTER_ID_4[] = "m2DVIa";
++/*DP to Dual link DVI converter 2*/
++static const uint8_t DP_DVI_CONVERTER_ID_42[] = "v2DVIa";
++
++static const uint8_t DP_SINK_DEV_STRING_ID2_REV0[] = "\0\0\0\0\0\0";
++
++/* Identifies second generation PSR TCON from Parade: Device ID string:
++ * yy-xx-**-**-**-**
++ */
++/* xx - Hw ID high byte */
++static const uint32_t DP_SINK_DEV_STRING_ID2_REV1_HW_ID_HIGH_BYTE =
++ 0x06;
++
++/* yy - HW ID low byte, the same silicon has several package/feature flavors */
++static const uint32_t DP_SINK_DEV_STRING_ID2_REV1_HW_ID_LOW_BYTE1 =
++ 0x61;
++static const uint32_t DP_SINK_DEV_STRING_ID2_REV1_HW_ID_LOW_BYTE2 =
++ 0x62;
++static const uint32_t DP_SINK_DEV_STRING_ID2_REV1_HW_ID_LOW_BYTE3 =
++ 0x63;
++static const uint32_t DP_SINK_DEV_STRING_ID2_REV1_HW_ID_LOW_BYTE4 =
++ 0x72;
++static const uint32_t DP_SINK_DEV_STRING_ID2_REV1_HW_ID_LOW_BYTE5 =
++ 0x73;
++
++#endif /* __DAL_DDC_SERVICE_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/default_mode_list_interface.h b/drivers/gpu/drm/amd/dal/include/default_mode_list_interface.h
+new file mode 100644
+index 0000000..35a5695
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/default_mode_list_interface.h
+@@ -0,0 +1,37 @@
++/*
++ * 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_DEFAULT_MODE_LIST_INTERFACE_H__
++#define __DAL_DEFAULT_MODE_LIST_INTERFACE_H__
++
++struct default_mode_list;
++
++uint32_t dal_default_mode_list_get_count(const struct default_mode_list *dml);
++
++struct dc_mode_info *dal_default_mode_list_get_mode_info_at_index(
++ const struct default_mode_list *dml,
++ uint32_t index);
++
++#endif /*__DAL_DEFAULT_MODE_LIST_INTERFACE_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/include/display_clock_interface.h b/drivers/gpu/drm/amd/dal/include/display_clock_interface.h
+new file mode 100644
+index 0000000..2f48b8a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/display_clock_interface.h
+@@ -0,0 +1,189 @@
++/*
++ * 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 __DISPLAY_CLOCK_INTERFACE_H__
++#define __DISPLAY_CLOCK_INTERFACE_H__
++
++#include "hw_sequencer_types.h"
++#include "grph_object_defs.h"
++#include "signal_types.h"
++#include "scaler_types.h"
++
++/* Timing related information*/
++struct dc_timing_params {
++ uint32_t INTERLACED:1;
++ uint32_t HCOUNT_BY_TWO:1;
++ uint32_t PIXEL_REPETITION:4; /*< values 1 to 10 supported*/
++ uint32_t PREFETCH:1;
++
++ uint32_t h_total;
++ uint32_t h_addressable;
++ uint32_t h_sync_width;
++};
++
++/* Scaling related information*/
++struct dc_scaling_params {
++ uint32_t h_overscan_right;
++ uint32_t h_overscan_left;
++ uint32_t h_taps;
++ uint32_t v_taps;
++};
++
++/*Display Request Mode (1 and 2 valid when scaler is OFF)*/
++enum display_request_mode {
++ REQUEST_ONLY_AT_EVERY_READ_POINTER_INCREMENT = 0,
++ REQUEST_WAITING_FOR_THE_FIRST_READ_POINTER_ONLY,
++ REQUEST_WITHOUT_WAITING_FOR_READ_POINTER
++};
++
++/* FBC minimum CompressionRatio*/
++enum fbc_compression_ratio {
++ FBC_COMPRESSION_NOT_USED = 0,
++ FBC_MINIMUM_COMPRESSION_RATIO_1 = 1,
++ FBC_MINIMUM_COMPRESSION_RATIO_2 = 2,
++ FBC_MINIMUM_COMPRESSION_RATIO_4 = 4,
++ FBC_MINIMUM_COMPRESSION_RATIO_8 = 8
++};
++
++/* VScalerEfficiency */
++enum v_scaler_efficiency {
++ V_SCALER_EFFICIENCY_LB36BPP = 0,
++ V_SCALER_EFFICIENCY_LB30BPP = 1,
++ V_SCALER_EFFICIENCY_LB24BPP = 2,
++ V_SCALER_EFFICIENCY_LB18BPP = 3
++};
++
++/* Parameters required for minimum Engine
++ * and minimum Display clock calculations*/
++struct min_clock_params {
++ uint32_t id;
++ uint32_t requested_pixel_clock; /* in KHz */
++ uint32_t actual_pixel_clock; /* in KHz */
++ struct view source_view;
++ struct view dest_view;
++ struct dc_timing_params timing_info;
++ struct dc_scaling_params scaling_info;
++ struct color_quality color_info;
++ enum signal_type signal_type;
++ enum dc_color_depth deep_color_depth;
++ enum v_scaler_efficiency scaler_efficiency;
++ bool line_buffer_prefetch_enabled;
++};
++
++/* Enumerations for Source selection of the Display clock */
++enum display_clock_source_select {
++ USE_PIXEL_CLOCK_PLL = 0,
++ USE_EXTERNAL_CLOCK,
++ USE_ENGINE_CLOCK
++};
++
++/* Result of Minimum System and Display clock calculations.
++ * Minimum System clock and Display clock, source and path to be used
++ * for Display clock*/
++struct minimum_clocks_calculation_result {
++ uint32_t min_sclk_khz;
++ uint32_t min_dclk_khz;
++ uint32_t min_mclk_khz;
++ uint32_t min_deep_sleep_sclk;
++};
++
++/* Enumeration of all clocks states */
++enum clocks_state {
++ CLOCKS_STATE_INVALID,
++ CLOCKS_STATE_ULTRA_LOW,
++ CLOCKS_STATE_LOW,
++ CLOCKS_STATE_NOMINAL,
++ CLOCKS_STATE_PERFORMANCE
++};
++
++/* Structure containing all state-dependent clocks
++ * (dependent on "enum clocks_state") */
++struct state_dependent_clocks {
++ uint32_t display_clk_khz;
++ uint32_t pixel_clk_khz;
++ uint32_t dvo_clk_khz;
++};
++
++struct display_clock_state {
++ uint32_t DFS_BYPASS_ACTIVE:1;
++};
++
++struct display_clock;
++
++struct display_clock *dal_display_clock_dce110_create(
++ struct dc_context *ctx,
++ struct adapter_service *as);
++
++struct display_clock *dal_display_clock_dce80_create(
++ struct dc_context *ctx,
++ struct adapter_service *as);
++
++void dal_display_clock_destroy(struct display_clock **to_destroy);
++bool dal_display_clock_validate(
++ struct display_clock *disp_clk,
++ struct min_clock_params *params);
++uint32_t dal_display_clock_calculate_min_clock(
++ struct display_clock *disp_clk,
++ uint32_t path_num,
++ struct min_clock_params *params);
++uint32_t dal_display_clock_get_validation_clock(struct display_clock *disp_clk);
++void dal_display_clock_set_clock(
++ struct display_clock *disp_clk,
++ uint32_t requested_clock_khz);
++uint32_t dal_display_clock_get_clock(struct display_clock *disp_clk);
++enum clocks_state dal_display_clock_get_min_clocks_state(
++ struct display_clock *disp_clk);
++enum clocks_state dal_display_clock_get_required_clocks_state(
++ struct display_clock *disp_clk,
++ struct state_dependent_clocks *req_clocks);
++bool dal_display_clock_set_min_clocks_state(
++ struct display_clock *disp_clk,
++ enum clocks_state clocks_state);
++uint32_t dal_display_clock_get_dp_ref_clk_frequency(
++ struct display_clock *disp_clk);
++/*the second parameter of "switchreferenceclock" is
++ * a dummy argument for all pre dce 6.0 versions*/
++void dal_display_clock_switch_reference_clock(
++ struct display_clock *disp_clk,
++ bool use_external_ref_clk,
++ uint32_t requested_clock_khz);
++void dal_display_clock_set_dp_ref_clock_source(
++ struct display_clock *disp_clk,
++ enum clock_source_id clk_src);
++void dal_display_clock_store_max_clocks_state(
++ struct display_clock *disp_clk,
++ enum clocks_state max_clocks_state);
++void dal_display_clock_set_clock_state(
++ struct display_clock *disp_clk,
++ struct display_clock_state clk_state);
++struct display_clock_state dal_display_clock_get_clock_state(
++ struct display_clock *disp_clk);
++uint32_t dal_display_clock_get_dfs_bypass_threshold(
++ struct display_clock *disp_clk);
++void dal_display_clock_invalid_clock_state(
++ struct display_clock *disp_clk);
++
++
++#endif /* __DISPLAY_CLOCK_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/display_path_interface.h b/drivers/gpu/drm/amd/dal/include/display_path_interface.h
+new file mode 100644
+index 0000000..7bf2ef2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/display_path_interface.h
+@@ -0,0 +1,436 @@
++/*
++ * 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 __DISPLAY_PATH_INTERFACE_H__
++#define __DISPLAY_PATH_INTERFACE_H__
++
++#include "display_path_types.h"
++#include "dcs_types.h"
++#include "grph_object_ctrl_defs.h"
++#include "signal_types.h"
++#include "controller_types.h"
++
++struct encoder;
++struct controller;
++struct connector;
++struct audio;
++struct clock_source;
++struct link_service;
++struct goc_link_service_data;
++struct drr_config;
++
++struct display_path;
++
++struct display_path *dal_display_path_create(void);
++
++struct display_path *dal_display_path_clone(
++ const struct display_path *self,
++ bool copy_active_state);
++
++void dal_display_path_destroy(
++ struct display_path **to_destroy);
++
++bool dal_display_path_validate(
++ struct display_path *path,
++ enum signal_type sink_signal);
++
++bool dal_display_path_add_link(
++ struct display_path *path,
++ struct encoder *encoder);
++
++bool dal_display_path_add_connector(
++ struct display_path *path,
++ struct connector *connector);
++
++struct connector *dal_display_path_get_connector(
++ struct display_path *path);
++
++int32_t dal_display_path_acquire(
++ struct display_path *path);
++
++bool dal_display_path_is_acquired(
++ const struct display_path *path);
++
++int32_t dal_display_path_get_ref_counter(
++ const struct display_path *path);
++
++int32_t dal_display_path_release(
++ struct display_path *path);
++
++void dal_display_path_release_resources(
++ struct display_path *path);
++
++void dal_display_path_acquire_links(
++ struct display_path *path);
++
++bool dal_display_path_is_source_blanked(
++ const struct display_path *path);
++
++bool dal_display_path_is_source_unblanked(
++ const struct display_path *path);
++
++void dal_display_path_set_source_blanked(
++ struct display_path *path,
++ enum display_tri_state state);
++
++bool dal_display_path_is_target_blanked(
++ const struct display_path *path);
++
++bool dal_display_path_is_target_unblanked(
++ const struct display_path *path);
++
++void dal_display_path_set_target_blanked(
++ struct display_path *path,
++ enum display_tri_state state);
++
++bool dal_display_path_is_target_powered_on(
++ const struct display_path *path);
++
++bool dal_display_path_is_target_powered_off(
++ const struct display_path *path);
++
++void dal_display_path_set_target_powered_on(
++ struct display_path *path,
++ enum display_tri_state state);
++
++bool dal_display_path_is_target_connected(
++ const struct display_path *path);
++
++void dal_display_path_set_target_connected(
++ struct display_path *path,
++ bool c);
++
++uint32_t dal_display_path_get_display_index(
++ const struct display_path *path);
++
++void dal_display_path_set_display_index(
++ struct display_path *path,
++ uint32_t index);
++
++struct connector_device_tag_info *dal_display_path_get_device_tag(
++ struct display_path *path);
++
++void dal_display_path_set_device_tag(
++ struct display_path *path,
++ struct connector_device_tag_info tag);
++
++enum clock_sharing_group dal_display_path_get_clock_sharing_group(
++ const struct display_path *path);
++
++void dal_display_path_set_clock_sharing_group(
++ struct display_path *path,
++ enum clock_sharing_group clock);
++
++union display_path_properties dal_display_path_get_properties(
++ const struct display_path *path);
++
++void dal_display_path_set_properties(
++ struct display_path *path,
++ union display_path_properties p);
++
++struct dcs *dal_display_path_get_dcs(
++ const struct display_path *path);
++
++void dal_display_path_set_dcs(
++ struct display_path *path,
++ struct dcs *dcs);
++
++uint32_t dal_display_path_get_number_of_links(
++ const struct display_path *path);
++
++void dal_display_path_set_controller(
++ struct display_path *path,
++ struct controller *controller);
++
++struct controller *dal_display_path_get_controller(
++ const struct display_path *path);
++
++void dal_display_path_set_clock_source(
++ struct display_path *path,
++ struct clock_source *clock);
++
++struct clock_source *dal_display_path_get_clock_source(
++ const struct display_path *path);
++
++void dal_display_path_set_alt_clock_source(
++ struct display_path *path,
++ struct clock_source *clock);
++
++struct clock_source *dal_display_path_get_alt_clock_source(
++ const struct display_path *path);
++
++void dal_display_path_set_fbc_info(
++ struct display_path *path,
++ struct fbc_info *clock);
++
++struct fbc_info *dal_display_path_get_fbc_info(
++ struct display_path *path);
++
++void dal_display_path_set_drr_config(
++ struct display_path *path,
++ struct drr_config *clock);
++
++void dal_display_path_get_drr_config(
++ const struct display_path *path,
++ struct drr_config *clock);
++
++void dal_display_path_set_static_screen_triggers(
++ struct display_path *path,
++ const struct static_screen_events *events);
++
++void dal_display_path_get_static_screen_triggers(
++ const struct display_path *path,
++ struct static_screen_events *events);
++
++bool dal_display_path_is_psr_supported(
++ const struct display_path *path);
++
++bool dal_display_path_is_drr_supported(
++ const struct display_path *path);
++
++void dal_display_path_set_link_service_data(
++ struct display_path *path,
++ uint32_t idx,
++ const struct goc_link_service_data *data);
++
++bool dal_display_path_get_link_service_data(
++ const struct display_path *path,
++ uint32_t idx,
++ struct goc_link_service_data *data);
++
++struct link_service *dal_display_path_get_link_query_interface(
++ const struct display_path *path,
++ uint32_t idx);
++
++void dal_display_path_set_link_query_interface(
++ struct display_path *path,
++ uint32_t idx,
++ struct link_service *link);
++
++struct link_service *dal_display_path_get_link_config_interface(
++ const struct display_path *path,
++ uint32_t idx);
++
++struct link_service *dal_display_path_get_link_service_interface(
++ const struct display_path *path,
++ uint32_t idx);
++
++struct encoder *dal_display_path_get_upstream_encoder(
++ const struct display_path *path,
++ uint32_t idx);
++
++struct encoder *dal_display_path_get_upstream_object(
++ const struct display_path *path,
++ uint32_t idx);
++
++struct encoder *dal_display_path_get_downstream_encoder(
++ const struct display_path *path,
++ uint32_t idx);
++
++struct encoder *dal_display_path_get_downstream_object(
++ const struct display_path *path,
++ uint32_t idx);
++
++struct audio *dal_display_path_get_audio(
++ const struct display_path *path,
++ uint32_t idx);
++
++void dal_display_path_set_audio(
++ struct display_path *path,
++ uint32_t idx,
++ struct audio *a);
++
++struct audio *dal_display_path_get_audio_object(
++ const struct display_path *path,
++ uint32_t idx);
++
++void dal_display_path_set_audio_active_state(
++ struct display_path *path,
++ uint32_t idx,
++ bool state);
++
++enum engine_id dal_display_path_get_stream_engine(
++ const struct display_path *path,
++ uint32_t idx);
++
++void dal_display_path_set_stream_engine(
++ struct display_path *path,
++ uint32_t idx,
++ enum engine_id id);
++
++bool dal_display_path_is_link_active(
++ const struct display_path *path,
++ uint32_t idx);
++
++void dal_display_path_set_link_active_state(
++ struct display_path *path,
++ uint32_t idx,
++ bool state);
++
++enum signal_type dal_display_path_get_config_signal(
++ const struct display_path *path,
++ uint32_t idx);
++
++enum signal_type dal_display_path_get_query_signal(
++ const struct display_path *path,
++ uint32_t idx);
++
++struct link_service *dal_display_path_get_mst_link_service(
++ const struct display_path *path);
++
++void dal_display_path_set_sync_output_object(
++ struct display_path *path,
++ enum sync_source o_source,
++ struct encoder *o_object);
++
++struct encoder *dal_display_path_get_sync_output_object(
++ const struct display_path *path);
++
++void dal_display_path_set_stereo_sync_object(
++ struct display_path *path,
++ struct encoder *stereo_sync);
++
++struct encoder *dal_display_path_get_stereo_sync_object(
++ const struct display_path *path);
++
++void dal_display_path_set_sync_input_source(
++ struct display_path *path,
++ enum sync_source s);
++
++enum sync_source dal_display_path_get_sync_input_source(
++ const struct display_path *path);
++
++void dal_display_path_set_sync_output_source(
++ struct display_path *path,
++ enum sync_source s);
++
++enum sync_source dal_display_path_get_sync_output_source(
++ const struct display_path *path);
++
++bool dal_display_path_set_pixel_clock_safe_range(
++ struct display_path *path,
++ struct pixel_clock_safe_range *range);
++
++bool dal_display_path_get_pixel_clock_safe_range(
++ const struct display_path *path,
++ struct pixel_clock_safe_range *range);
++
++void dal_display_path_set_ddi_channel_mapping(
++ struct display_path *path,
++ union ddi_channel_mapping mapping);
++
++bool dal_display_path_set_sink_signal(
++ struct display_path *path,
++ enum signal_type sink_signal);
++
++enum signal_type dal_display_path_sink_signal_to_asic_signal(
++ struct display_path *path,
++ enum signal_type sink_signal);
++
++enum signal_type dal_display_path_sink_signal_to_link_signal(
++ struct display_path *path,
++ enum signal_type sink_signal,
++ uint32_t idx);
++
++enum signal_type dal_display_path_downstream_to_upstream_signal(
++ struct display_path *path,
++ enum signal_type signal,
++ uint32_t idx);
++
++bool dal_display_path_is_audio_present(
++ const struct display_path *path,
++ uint32_t *audio_pin);
++
++bool dal_display_path_is_dp_auth_supported(
++ struct display_path *path);
++
++bool dal_display_path_is_vce_supported(
++ const struct display_path *path);
++
++bool dal_display_path_is_sls_capable(
++ const struct display_path *path);
++
++bool dal_display_path_is_gen_lock_capable(
++ const struct display_path *path);
++
++struct transmitter_configuration dal_display_path_get_transmitter_configuration(
++ const struct display_path *path,
++ bool physical);
++
++bool dal_display_path_is_ss_supported(
++ const struct display_path *path);
++
++bool dal_display_path_is_ss_configurable(
++ const struct display_path *path);
++
++void dal_display_path_set_ss_support(
++ struct display_path *path,
++ bool s);
++
++enum signal_type dal_display_path_get_active_signal(
++ struct display_path *path,
++ uint32_t idx);
++
++bool dal_display_path_contains_object(
++ struct display_path *path,
++ struct graphics_object_id id);
++
++/* Multi-plane declarations.
++ * This structure should also be used for Stereo. */
++struct display_path_plane {
++ struct controller *controller;
++ /* During dal_tm_acquire_plane_resources() set blnd_mode, because
++ * "layer index" is known at that point, and we must decide how
++ * "controller" should do the blending */
++ enum blender_mode blnd_mode;
++ /* Some use-cases allow to power-gate FE.
++ * For example, with Full Screen Video on Underlay we can
++ * disable the 'root' plane.
++ * This flag indicates that FE should be power-gated */
++ bool disabled;
++};
++
++bool dal_display_path_add_plane(
++ struct display_path *path,
++ struct display_path_plane *plane);
++
++uint8_t dal_display_path_get_number_of_planes(
++ const struct display_path *path);
++
++struct display_path_plane *dal_display_path_get_plane_at_index(
++ const struct display_path *path,
++ uint8_t index);
++
++struct controller *dal_display_path_get_controller_for_layer_index(
++ const struct display_path *path,
++ uint8_t layer_index);
++
++void dal_display_path_release_planes(
++ struct display_path *path);
++
++void dal_display_path_release_non_root_planes(
++ struct display_path *path);
++
++#endif /* __DISPLAY_PATH_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/display_path_types.h b/drivers/gpu/drm/amd/dal/include/display_path_types.h
+new file mode 100644
+index 0000000..8aac46d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/display_path_types.h
+@@ -0,0 +1,132 @@
++/*
++ * 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_DISPLAY_PATH_TYPES_H__
++#define __DAL_DISPLAY_PATH_TYPES_H__
++
++#include "grph_object_defs.h"
++
++enum {
++ CONTROLLER_HANDLE_INVALID = (uint32_t) (-1)
++};
++
++/*Limit maximum number of cofunctional paths*/
++enum {
++ MAX_COFUNCTIONAL_PATHS = 6
++};
++
++struct pixel_clock_safe_range {
++ uint32_t min_frequency;
++ uint32_t max_frequency;
++};
++
++/**
++ * ClockSharingGroup
++ * Enumeration of Clock Source Sharing categories
++ * Instead using enum we define valid range for clock sharing group values
++ * This is because potential num of group can be pretty big
++ */
++
++enum clock_sharing_group {
++ /* Default group for display paths that cannot share clock source.
++ * Display path in such group will aqcuire clock source exclusively*/
++ CLOCK_SHARING_GROUP_EXCLUSIVE = 0,
++ /* DisplayPort paths will have this group if clock sharing
++ * level is DisplayPortShareable*/
++ CLOCK_SHARING_GROUP_DISPLAY_PORT = 1,
++ /* Mst paths will have this group if clock sharing
++ * level is DpMstShareable*/
++ CLOCK_SHARING_GROUP_DP_MST = 2,
++ /* Display paths will have this group when
++ * desired to use alternative DPRef clock source.*/
++ CLOCK_SHARING_GROUP_ALTERNATIVE_DP_REF = 3,
++ /* Start of generic SW sharing groups.*/
++ CLOCK_SHARING_GROUP_GROUP1 = 4,
++ /* Total number of clock sharing groups.*/
++ CLOCK_SHARING_GROUP_MAX = 32,
++};
++/* Should be around maximal number of ever connected displays (since boot :)*/
++/*TEMP*/
++enum goc_link_settings_type {
++ GOC_LINK_SETTINGS_TYPE_PREFERRED = 0,
++ GOC_LINK_SETTINGS_TYPE_REPORTED,
++ GOC_LINK_SETTINGS_TYPE_TRAINED,
++ GOC_LINK_SETTINGS_TYPE_OVERRIDEN_TRAINED,
++ GOC_LINK_SETTINGS_TYPE_MAX
++};
++
++struct dp_audio_test_data {
++
++ struct dp_audio_test_data_flags {
++ uint32_t test_requested:1;
++ uint32_t disable_video:1;
++ } flags;
++
++ /*struct dp_audio_test_data_flags flags;*/
++ uint32_t sampling_rate;
++ uint32_t channel_count;
++ uint32_t pattern_type;
++ uint8_t pattern_period[8];
++};
++
++struct goc_link_service_data {
++ struct dp_audio_test_data dp_audio_test_data;
++};
++/* END-OF-TEMP*/
++
++
++union display_path_properties {
++ struct bit_map {
++ uint32_t ALWAYS_CONNECTED:1;
++ uint32_t HPD_SUPPORTED:1;
++ uint32_t NON_DESTRUCTIVE_POLLING:1;
++ uint32_t FORCE_CONNECT_SUPPORTED:1;
++ uint32_t FAKED_PATH:1;
++ uint32_t IS_BRANCH_DP_MST_PATH:1;
++ uint32_t IS_ROOT_DP_MST_PATH:1;
++ uint32_t IS_DP_AUDIO_SUPPORTED:1;
++ uint32_t IS_HDMI_AUDIO_SUPPORTED:1;
++ } bits;
++
++ uint32_t raw;
++};
++
++enum display_tri_state {
++ DISPLAY_TRI_STATE_UNKNOWN = 0,
++ DISPLAY_TRI_STATE_TRUE,
++ DISPLAY_TRI_STATE_FALSE
++};
++
++enum {
++ MAX_NUM_OF_LINKS_PER_PATH = 2
++};
++enum {
++ SINK_LINK_INDEX = (uint32_t) (-1)
++};
++enum {
++ ASIC_LINK_INDEX = 0
++};
++
++#endif /* __DAL_DISPLAY_PATH_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/display_service_interface.h b/drivers/gpu/drm/amd/dal/include/display_service_interface.h
+new file mode 100644
+index 0000000..b602bca
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/display_service_interface.h
+@@ -0,0 +1,165 @@
++/*
++ * 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 __DISPLAY_SERVICE_INTERFACE_H__
++#define __DISPLAY_SERVICE_INTERFACE_H__
++
++#include "include/display_service_types.h"
++#include "include/display_path_types.h"
++#include "include/grph_object_ctrl_defs.h"
++
++struct display_service;
++struct ds_overlay;
++struct ds_dispatch;
++struct ds_synchronization;
++struct path_mode_set;
++
++struct display_service *dal_display_service_create(
++ struct ds_init_data *data);
++
++void dal_display_service_destroy(
++ struct display_service **ds);
++
++struct ds_dispatch *dal_display_service_get_adjustment_interface(
++ struct display_service *ds);
++
++struct ds_overlay *dal_display_service_get_overlay_interface(
++ struct display_service *ds);
++
++struct ds_dispatch *dal_display_service_get_set_mode_interface(
++ struct display_service *ds);
++
++struct ds_dispatch *dal_display_service_get_reset_mode_interface(
++ struct display_service *ds);
++
++struct ds_synchronization *dal_display_service_get_synchronization_interface(
++ struct display_service *ds);
++
++enum ds_return dal_display_service_notify_v_sync_int_state(
++ struct display_service *ds,
++ uint32_t display_index,
++ bool maintain_v_sync_phase);
++
++enum ds_return dal_display_service_target_power_control(
++ struct display_service *ds,
++ uint32_t display_index,
++ bool power_on);
++
++enum ds_return dal_display_service_power_down_active_hw(
++ struct display_service *ds,
++ enum dc_video_power_state state);
++
++enum ds_return dal_display_service_mem_request_control(
++ struct display_service *ds,
++ uint32_t display_index,
++ bool enable);
++
++enum ds_return dal_display_service_set_multimedia_pass_through_mode(
++ struct display_service *ds,
++ uint32_t display_index,
++ bool passThrough);
++
++enum ds_return dal_display_service_set_palette(
++ struct display_service *ds,
++ uint32_t display_index,
++ const struct ds_devclut *palette,
++ const uint32_t start,
++ const uint32_t length);
++
++enum ds_return dal_display_service_apply_pix_clk_range(
++ struct display_service *ds,
++ uint32_t display_index,
++ struct pixel_clock_safe_range *range);
++
++enum ds_return dal_display_service_get_safe_pix_clk(
++ struct display_service *ds,
++ uint32_t display_index,
++ uint32_t *pix_clk_khz);
++
++enum ds_return dal_display_service_apply_refreshrate_adjustment(
++ struct display_service *ds,
++ uint32_t display_index,
++ enum ds_refreshrate_adjust_action action,
++ struct ds_refreshrate *refreshrate);
++
++enum ds_return dal_display_service_pre_ddc(
++ struct display_service *ds,
++ uint32_t display_index);
++
++enum ds_return dal_display_service_post_ddc(
++ struct display_service *ds,
++ uint32_t display_index);
++
++enum ds_return dal_display_service_backlight_control(
++ struct display_service *ds,
++ uint32_t display_index,
++ bool enable);
++
++enum ds_return dal_display_service_get_backlight_user_level(
++ struct display_service *ds,
++ uint32_t display_index,
++ uint32_t *level);
++
++enum ds_return dal_display_service_get_backlight_effective_level(
++ struct display_service *ds,
++ uint32_t display_index,
++ uint32_t *level);
++
++enum ds_return dal_display_service_enable_hpd(
++ struct display_service *ds,
++ uint32_t display_index);
++
++enum ds_return dal_display_service_disable_hpd(
++ struct display_service *ds,
++ uint32_t display_index);
++
++enum ds_return dal_display_service_get_min_mem_channels(
++ struct display_service *ds,
++ const struct path_mode_set *path_mode_set,
++ uint32_t mem_channels_num,
++ uint32_t *min_mem_channels_num);
++
++enum ds_return dal_display_service_enable_advanced_request(
++ struct display_service *ds,
++ bool enable);
++
++/*Audio related*/
++enum ds_return dal_display_service_enable_audio_endpoint(
++ struct display_service *ds,
++ uint32_t display_index,
++ bool enable);
++
++enum ds_return dal_display_service_mute_audio_endpoint(
++ struct display_service *ds,
++ uint32_t display_index,
++ bool mute);
++
++bool dal_display_service_calc_view_port_for_wide_display(
++ struct display_service *ds,
++ uint32_t display_index,
++ const struct ds_view_port *set_view_port,
++ struct ds_get_view_port *get_view_port);
++
++#endif /* __DISPLAY_SERVICE_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/display_service_types.h b/drivers/gpu/drm/amd/dal/include/display_service_types.h
+new file mode 100644
+index 0000000..4f27f59
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/display_service_types.h
+@@ -0,0 +1,167 @@
++/*
++ * 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_DISPLAY_SERVICE_TYPES_H__
++#define __DAL_DISPLAY_SERVICE_TYPES_H__
++struct ds_dispatch {
++
++};
++
++struct ds_view_port_alignment {
++ uint8_t x_width_size_alignment;
++ uint8_t y_height_size_alignment;
++ uint8_t x_start_alignment;
++ uint8_t y_start_alignment;
++};
++
++struct hw_sequencer;
++struct topology_mgr;
++struct adapter_service;
++struct timing_service;
++
++struct ds_init_data {
++ struct dal_context *dal_context;
++ struct hw_sequencer *hwss;
++ struct topology_mgr *tm;
++ struct adapter_service *as;
++ struct timing_service *ts;
++ struct ds_view_port_alignment view_port_alignment;
++};
++
++enum ds_return {
++ DS_SUCCESS,
++ DS_SUCCESS_FALLBACK,
++ DS_ERROR,
++ DS_SET_MODE_REQUIRED,
++ DS_REBOOT_REQUIRED,
++ DS_OUT_OF_RANGE,
++ DS_RESOURCE_UNAVAILABLE,
++ DS_NOT_SUPPORTED
++};
++
++struct ds_devclut {
++ uint8_t red;
++ uint8_t green;
++ uint8_t blue;
++ uint8_t reserved;
++};
++
++enum ds_refreshrate_adjust_action {
++ DS_REFRESHRATE_ADJUST_ACTION_SET,
++ DS_REFRESHRATE_ADJUST_ACTION_RESET,
++ DS_REFRESHRATE_ADJUST_ACTION_UPDATE,
++};
++
++struct ds_refreshrate {
++ uint32_t numerator;
++ uint32_t denominator;
++};
++
++/*Contains delta in pixels between two active CRTC timings and relevant timing
++details. Delta will be positive if CRTC1 timing running before CRTC2 and
++negative otherwise (CRTC2 timing running before CRTC1)*/
++/*CRTC1 running before CRTC2 = CRTC1 pixel position in
++frame smaller then CRTC2 position*/
++struct ds_timings_delta_info {
++ int32_t delta_in_pixels;
++ uint32_t pix_clk_khz;
++ uint32_t h_total;
++ uint32_t v_total;
++};
++
++enum ds_audio_os_channel_name {
++ DS_AUDIO_OS_CHANNEL_L = 0,
++ DS_AUDIO_OS_CHANNEL_R = 1,
++ DS_AUDIO_OS_CHANNEL_C = 2,
++ DS_AUDIO_OS_CHANNEL_SUB = 3,
++ DS_AUDIO_OS_CHANNEL_RL = 4,
++ DS_AUDIO_OS_CHANNEL_RR = 5,
++ DS_AUDIO_OS_CHANNEL_SL = 6,
++ DS_AUDIO_OS_CHANNEL_SR = 7,
++ DS_AUDIO_OS_CHANNEL_SILENT = 8,
++ DS_AUDIO_OS_CHANNEL_NO_ASSOCIATION = 15
++};
++
++enum ds_audio_azalia_channel_name {
++ DS_AUDIO_AZALIA_CHANNEL_FL = 0,
++ DS_AUDIO_AZALIA_CHANNEL_FR = 1,
++ DS_AUDIO_AZALIA_CHANNEL_FC = 2,
++ DS_AUDIO_AZALIA_CHANNEL_SUB = 3,
++ DS_AUDIO_AZALIA_CHANNEL_SL = 4,
++ DS_AUDIO_AZALIA_CHANNEL_SR = 5,
++ DS_AUDIO_AZALIA_CHANNEL_BL = 6,
++ DS_AUDIO_AZALIA_CHANNEL_BR = 7,
++ DS_AUDIO_AZALIA_CHANNEL_SILENT = 8,
++ DS_AUDIO_AZALIA_CHANNEL_NO_ASSOCIATION = 15
++};
++
++enum ds_audio_channel_format {
++ DS_AUDIO_CHANNEL_FORMAT_2P0 = 0,
++ DS_AUDIO_CHANNEL_FORMAT_2P1,
++ DS_AUDIO_CHANNEL_FORMAT_5P1,
++ DS_AUDIO_CHANNEL_FORMAT_7P1
++};
++
++/*Used for get/set Mirabilis*/
++enum ds_mirabilis_control_option {
++ DS_MIRABILIS_UNINITIALIZE = 0,
++ DS_MIRABILIS_DISABLE,
++ DS_MIRABILIS_ENABLE,
++ DS_MIRABILIS_SAVE_PROFILE
++};
++
++struct ds_disp_identifier {
++ uint32_t display_index;
++ uint32_t manufacture_id;
++ uint32_t product_id;
++ uint32_t serial_no;
++};
++
++struct ds_view_port {
++ uint32_t x_start;
++ uint32_t y_start;
++ uint32_t width;
++ uint32_t height;
++ uint32_t controller;
++};
++
++#define DS_MAX_NUM_VIEW_PORTS 2
++struct ds_get_view_port {
++ uint32_t num_of_view_ports;
++ struct ds_view_port view_ports[DS_MAX_NUM_VIEW_PORTS];
++};
++
++struct ranged_timing_preference_flags {
++ union {
++ struct {
++ uint32_t prefer_enable_drr:1;
++ uint32_t force_disable_drr:1;
++
++ } bits;
++ uint32_t u32all;
++ };
++};
++
++#endif /* __DAL_DISPLAY_SERVICE_TYPE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dmcu_interface.h b/drivers/gpu/drm/amd/dal/include/dmcu_interface.h
+new file mode 100644
+index 0000000..c712cc2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dmcu_interface.h
+@@ -0,0 +1,87 @@
++/*
++ * 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_DMCU_INTERFACE_H__
++#define __DAL_DMCU_INTERFACE_H__
++
++#include "grph_object_defs.h"
++#include "dmcu_types.h"
++
++/* Interface functions */
++
++/* DMCU setup related interface functions */
++struct dmcu *dal_dmcu_create(
++ struct dmcu_init_data *init_data);
++void dal_dmcu_destroy(struct dmcu **dmcu);
++void dal_dmcu_release_hw(struct dmcu *dmcu);
++
++void dal_dmcu_power_up(struct dmcu *dmcu);
++void dal_dmcu_power_down(struct dmcu *dmcu);
++
++void dal_dmcu_configure_wait_loop(
++ struct dmcu *dmcu,
++ uint32_t display_clock);
++
++/* PSR feature related interface functions */
++void dal_dmcu_psr_setup(
++ struct dmcu *dmcu,
++ struct dmcu_context *dmcu_context);
++void dal_dmcu_psr_enable(struct dmcu *dmcu);
++void dal_dmcu_psr_disable(struct dmcu *dmcu);
++void dal_dmcu_psr_block(struct dmcu *dmcu, bool block_psr);
++bool dal_dmcu_psr_is_blocked(struct dmcu *dmcu);
++void dal_dmcu_psr_set_level(
++ struct dmcu *dmcu,
++ union dmcu_psr_level psr_level);
++void dal_dmcu_psr_allow_power_down_crtc(
++ struct dmcu *dmcu,
++ bool should_allow_crtc_power_down);
++bool dal_dmcu_psr_submit_command(
++ struct dmcu *dmcu,
++ struct dmcu_context *dmcu_context,
++ struct dmcu_config_data *config_data);
++void dal_dmcu_psr_get_config_data(
++ struct dmcu *dmcu,
++ uint32_t v_total,
++ struct dmcu_config_data *config_data);
++
++/* ABM feature related interface functions */
++void dal_dmcu_abm_enable(
++ struct dmcu *dmcu,
++ enum controller_id controller_id,
++ uint32_t vsync_rate_hz);
++void dal_dmcu_abm_disable(struct dmcu *dmcu);
++bool dal_dmcu_abm_enable_smooth_brightness(struct dmcu *dmcu);
++bool dal_dmcu_abm_disable_smooth_brightness(struct dmcu *dmcu);
++void dal_dmcu_abm_varibright_control(
++ struct dmcu *dmcu,
++ const struct varibright_control *varibright_control);
++bool dal_dmcu_abm_set_backlight_level(
++ struct dmcu *dmcu,
++ uint8_t backlight_8_bit);
++uint8_t dal_dmcu_abm_get_user_backlight_level(struct dmcu *dmcu);
++uint8_t dal_dmcu_abm_get_current_backlight_level(struct dmcu *dmcu);
++
++#endif /* __DAL_DMCU_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dmcu_types.h b/drivers/gpu/drm/amd/dal/include/dmcu_types.h
+new file mode 100644
+index 0000000..1f3107d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dmcu_types.h
+@@ -0,0 +1,199 @@
++/*
++ * 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_DMCU_TYPES_H__
++#define __DAL_DMCU_TYPES_H__
++
++/* Forward declaration */
++struct dmcu;
++
++/* Required information for creation and initialization of a controller */
++struct dmcu_init_data {
++ struct dal_context *dal_context;
++ struct adapter_service *as;
++ uint32_t max_engine_clock_in_khz;
++};
++
++/* Interface structure defines */
++
++enum dmcu_action {
++ DMCU_ACTION_PSR_ENABLE,
++ DMCU_ACTION_PSR_EXIT,
++ DMCU_ACTION_PSR_RFB_UPDATE,
++ DMCU_ACTION_PSR_SET,
++ DMCU_ACTION_PSR_CLEAR_COUNT,
++ DMCU_ACTION_PSR_COUNT_REQUEST,
++ DMCU_ACTION_PSR_STATE_REQUEST,
++ DMCU_ACTION_PSR_SET_LEVEL,
++ DMCU_ACTION_PSR_ADVANCE_STATE,
++ DMCU_ACTION_PSR_SET_WAITLOOP
++};
++
++enum dmcu_output {
++ DMCU_OUTPUT_PSR_ACK,
++ DMCU_OUTPUT_PSR_NACK,
++ DMCU_OUTPUT_PSR_AUX_ERR,
++ DMCU_OUTPUT_PSR_COUNT_STATUS,
++ DMCU_OUTPUT_PSR_STATE_STATUS,
++ DMCU_OUTPUT_PSR_RFB_UPDATE_ERR,
++ DMCU_OUTPUT_PSR_ERR,
++ DMCU_OUTPUT_PSR_GET_REPLY,
++ DMCU_OUTPUT_PSR_ENTRY_ERROR,
++ DMCU_OUTPUT_PSR_LT_ERROR,
++ DMCU_OUTPUT_PSR_FORCE_SR_ERROR,
++ DMCU_OUTPUT_PSR_SDP_SEND_TIMEOUT
++};
++
++/* PSR states, based similarly on states defined in eDP specification. */
++enum psr_state {
++ STATE0, /* PSR is disabled */
++ STATE1, /* PSR is enabled, but inactive */
++ STATE1A,
++ STATE2, /* PSR is transitioning to active state */
++ STATE2A,
++ STATE3, /* PSR is active; Display is in self refresh */
++ STATE3INIT,
++ STATE4, /* RFB single frame update */
++ STATE4A,
++ STATE4B,
++ STATE4C,
++ STATE4D,
++ STATE5, /* Exiting from PSR active state */
++ STATE5A,
++ STATE5B,
++ STATE5C
++};
++
++enum phy_type {
++ PHY_TYPE_UNKNOWN = 1,
++ PHY_TYPE_PCIE_PHY = 2,
++ PHY_TYPE_UNIPHY = 3,
++};
++
++struct dmcu_context {
++ enum channel_id channel;
++ enum transmitter transmitter_id;
++ enum engine_id engine_id;
++ enum controller_id controller_id;
++ enum phy_type phy_type;
++ enum physical_phy_id smu_physical_phy_id;
++
++ /* Vertical total pixels from crtc timing.
++ * This is used for static screen detection.
++ * ie. If we want to detect half a frame,
++ * we use this to determine the hyst lines.*/
++ uint32_t crtc_timing_vertical_total;
++
++ /* PSR supported from panel capabilities
++ * and current display configuration */
++ bool psr_supported_display_config;
++
++ /* Whether fast link training is supported by the panel */
++ bool psr_exit_link_training_required;
++
++ /* If RFB setup time is greater than the total VBLANK time, it is not
++ * possible for the sink to capture the video frame in the same frame
++ * the SDP is sent. In this case, the frame capture indication bit
++ * should be set and an extra static frame should be transmitted to
++ * the sink */
++ bool psr_frame_capture_indication_required;
++
++ /* Set the last possible line SDP may be transmitted without violating
++ * the RFB setup time */
++ bool sdp_transmit_line_num_deadline;
++
++ /* The VSync rate in Hz used to calculate the step size
++ * for smooth brightness feature */
++ uint32_t vsync_rate_hz;
++};
++
++union dmcu_psr_level {
++ struct {
++ bool SKIP_CRC:1;
++ bool SKIP_DP_VID_STREAM_DISABLE:1;
++ bool SKIP_PHY_POWER_DOWN:1;
++ bool SKIP_AUX_ACK_CHECK:1;
++ bool SKIP_CRTC_DISABLE:1;
++ bool SKIP_AUX_RFB_CAPTURE_CHECK:1;
++ bool SKIP_SMU_NOTIFICATION:1;
++ bool SKIP_AUTO_STATE_ADVANCE:1;
++ bool DISABLE_PSR_ENTRY_ABORT:1;
++ } bits;
++ uint32_t u32all;
++};
++
++struct dmcu_config_data {
++ /* Command sent to DMCU. */
++ enum dmcu_action action;
++ /* PSR Level controls which HW blocks to power down during PSR active,
++ * and also other sequence modifications. */
++ union dmcu_psr_level psr_level;
++ /* To indicate that first changed frame from active state should not
++ * result in exit to inactive state, but instead perform an automatic
++ * single frame RFB update. */
++ bool rfb_update_auto_en;
++ /* Number of consecutive static frames to detect before entering PSR
++ * active state. */
++ uint32_t hyst_frames;
++ /* Partial frames before entering PSR active. Note this parameter is in
++ * units of 100 lines. i.e. Wait a value of 5 means wait 500 additional
++ * lines. */
++ uint32_t hyst_lines;
++ /* Number of repeated AUX retries before indicating failure to driver.
++ * In a working case, first attempt to write/read AUX should pass. */
++ uint32_t aux_repeat;
++ /* Additional delay after remote frame capture before continuing to
++ * power down. This is mainly for debug purposes to identify timing
++ * issues. */
++ uint32_t frame_delay;
++ /* Controls how long the delay of a wait loop is. It should be tuned
++ * to 1 us, and needs to be reconfigured every time DISPCLK changes. */
++ uint32_t wait_loop_num;
++};
++
++struct dmcu_output_data {
++ /* DMCU reply */
++ enum dmcu_output output;
++ /* The current PSR state. */
++ uint32_t psr_state;
++ /* The number of frames during PSR active state. */
++ uint32_t psr_count;
++};
++
++enum varibright_command {
++ VARIBRIGHT_CMD_SET_VB_LEVEL = 0,
++ VARIBRIGHT_CMD_USER_ENABLE,
++ VARIBRIGHT_CMD_POST_DISPLAY_CONFIG,
++ VARIBRIGHT_CMD_UNKNOWN
++};
++
++struct varibright_control {
++ enum varibright_command command;
++ uint8_t level;
++ bool enable;
++ bool activate;
++};
++
++#endif /* __DAL_DMCU_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dpcd_access_service_interface.h b/drivers/gpu/drm/amd/dal/include/dpcd_access_service_interface.h
+new file mode 100644
+index 0000000..a942c77
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dpcd_access_service_interface.h
+@@ -0,0 +1,65 @@
++/*
++ * 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
++ *
++ */
++
++#ifdef __DPCD_ACCESS_SERVICE_INTERFACE_HPP__
++#define __DPCD_ACCESS_SERVICE_INTERFACE_HPP__
++
++/* DDC service transaction error codes
++ * depends on transaction status
++ */
++enum ddc_result {
++ DDCRESULT_UNKNOWN = 0,
++ DDCRESULT_SUCESSFULL,
++ DDCRESULT_FAILEDCHANNELBUSY,
++ DDCRESULT_FAILEDTIMEOUT,
++ DDCRESULT_FAILEDPROTOCOLERROR,
++ DDCRESULT_FAILEDNACK,
++ DDCRESULT_FAILEDINCOMPLETE,
++ DDCRESULT_FAILEDOPERATION,
++ DDCRESULT_FAILEDINVALIDOPERATION,
++ DDCRESULT_FAILEDBUFFEROVERFLOW
++};
++
++enum {
++ MaxNativeAuxTransactionSize = 16
++};
++
++struct display_sink_capability;
++
++/* TO DO: below functions can be moved to ddc_service (think about it)*/
++enum ddc_result dal_ddc_read_dpcd_data(
++ uint32_t address,
++ unsigned char *data,
++ uint32_t size);
++
++enum ddc_result dal_ddc_write_dpcd_data(
++ uint32_t address,
++ const unsigned char *data uint32_t size);
++
++bool dal_aux_query_dp_sink_capability(display_sink_capability *sink_cap);
++bool start_gtc_sync(void);
++bool stop_gtc_sync(void);
++
++#endif /*__DPCD_ACCESS_SERVICE_INTERFACE_HPP__*/
+diff --git a/drivers/gpu/drm/amd/dal/include/dpcd_defs.h b/drivers/gpu/drm/amd/dal/include/dpcd_defs.h
+new file mode 100644
+index 0000000..cefa1fc
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dpcd_defs.h
+@@ -0,0 +1,869 @@
++/*
++ * 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_DPCD_DEFS_H__
++#define __DAL_DPCD_DEFS_H__
++
++enum dpcd_address {
++/* addresses marked with 1.2 are only defined since DP 1.2 spec */
++
++ /* Reciever Capability Field */
++ DPCD_ADDRESS_DPCD_REV = 0x00000,
++ DPCD_ADDRESS_MAX_LINK_RATE = 0x00001,
++ DPCD_ADDRESS_MAX_LANE_COUNT = 0x00002,
++ DPCD_ADDRESS_MAX_DOWNSPREAD = 0x00003,
++ DPCD_ADDRESS_NORP = 0x00004,
++ DPCD_ADDRESS_DOWNSTREAM_PORT_PRESENT = 0x00005,
++ DPCD_ADDRESS_MAIN_LINK_CHANNEL_CODING = 0x00006,
++ DPCD_ADDRESS_DOWNSTREAM_PORT_COUNT = 0x00007,
++ DPCD_ADDRESS_RECEIVE_PORT0_CAP0 = 0x00008,
++ DPCD_ADDRESS_RECEIVE_PORT0_CAP1 = 0x00009,
++ DPCD_ADDRESS_RECEIVE_PORT1_CAP0 = 0x0000A,
++ DPCD_ADDRESS_RECEIVE_PORT1_CAP1 = 0x0000B,
++
++ DPCD_ADDRESS_I2C_SPEED_CNTL_CAP = 0x0000C,/*1.2*/
++ DPCD_ADDRESS_EDP_CONFIG_CAP = 0x0000D,/*1.2*/
++ DPCD_ADDRESS_TRAINING_AUX_RD_INTERVAL = 0x000E,/*1.2*/
++
++ DPCD_ADDRESS_MSTM_CAP = 0x00021,/*1.2*/
++
++ /* Audio Video Sync Data Feild */
++ DPCD_ADDRESS_AV_GRANULARITY = 0x0023,
++ DPCD_ADDRESS_AUDIO_DECODE_LATENCY1 = 0x0024,
++ DPCD_ADDRESS_AUDIO_DECODE_LATENCY2 = 0x0025,
++ DPCD_ADDRESS_AUDIO_POSTPROCESSING_LATENCY1 = 0x0026,
++ DPCD_ADDRESS_AUDIO_POSTPROCESSING_LATENCY2 = 0x0027,
++ DPCD_ADDRESS_VIDEO_INTERLACED_LATENCY = 0x0028,
++ DPCD_ADDRESS_VIDEO_PROGRESSIVE_LATENCY = 0x0029,
++ DPCD_ADDRESS_AUDIO_DELAY_INSERT1 = 0x0002B,
++ DPCD_ADDRESS_AUDIO_DELAY_INSERT2 = 0x0002C,
++ DPCD_ADDRESS_AUDIO_DELAY_INSERT3 = 0x0002D,
++
++ /* Audio capability */
++ DPCD_ADDRESS_NUM_OF_AUDIO_ENDPOINTS = 0x00022,
++
++ DPCD_ADDRESS_GUID_START = 0x00030,/*1.2*/
++ DPCD_ADDRESS_GUID_END = 0x0003f,/*1.2*/
++
++ DPCD_ADDRESS_PSR_SUPPORT_VER = 0x00070,
++ DPCD_ADDRESS_PSR_CAPABILITY = 0x00071,
++
++ DPCD_ADDRESS_DWN_STRM_PORT0_CAPS = 0x00080,/*1.2a*/
++
++ /* Link Configuration Field */
++ DPCD_ADDRESS_LINK_BW_SET = 0x00100,
++ DPCD_ADDRESS_LANE_COUNT_SET = 0x00101,
++ DPCD_ADDRESS_TRAINING_PATTERN_SET = 0x00102,
++ DPCD_ADDRESS_LANE0_SET = 0x00103,
++ DPCD_ADDRESS_LANE1_SET = 0x00104,
++ DPCD_ADDRESS_LANE2_SET = 0x00105,
++ DPCD_ADDRESS_LANE3_SET = 0x00106,
++ DPCD_ADDRESS_DOWNSPREAD_CNTL = 0x00107,
++ DPCD_ADDRESS_I2C_SPEED_CNTL = 0x00109,/*1.2*/
++
++ DPCD_ADDRESS_EDP_CONFIG_SET = 0x0010A,
++ DPCD_ADDRESS_LINK_QUAL_LANE0_SET = 0x0010B,
++ DPCD_ADDRESS_LINK_QUAL_LANE1_SET = 0x0010C,
++ DPCD_ADDRESS_LINK_QUAL_LANE2_SET = 0x0010D,
++ DPCD_ADDRESS_LINK_QUAL_LANE3_SET = 0x0010E,
++
++ DPCD_ADDRESS_LANE0_SET2 = 0x0010F,/*1.2*/
++ DPCD_ADDRESS_LANE2_SET2 = 0x00110,/*1.2*/
++
++ DPCD_ADDRESS_MSTM_CNTL = 0x00111,/*1.2*/
++
++ DPCD_ADDRESS_PSR_ENABLE_CFG = 0x0170,
++
++ /* Payload Table Configuration Field 1.2 */
++ DPCD_ADDRESS_PAYLOAD_ALLOCATE_SET = 0x001C0,
++ DPCD_ADDRESS_PAYLOAD_ALLOCATE_START_TIMESLOT = 0x001C1,
++ DPCD_ADDRESS_PAYLOAD_ALLOCATE_TIMESLOT_COUNT = 0x001C2,
++
++ DPCD_ADDRESS_SINK_COUNT = 0x0200,
++ DPCD_ADDRESS_DEVICE_SERVICE_IRQ_VECTOR = 0x0201,
++
++ /* Link / Sink Status Field */
++ DPCD_ADDRESS_LANE_01_STATUS = 0x00202,
++ DPCD_ADDRESS_LANE_23_STATUS = 0x00203,
++ DPCD_ADDRESS_LANE_ALIGN_STATUS_UPDATED = 0x0204,
++ DPCD_ADDRESS_SINK_STATUS = 0x0205,
++
++ /* Adjust Request Field */
++ DPCD_ADDRESS_ADJUST_REQUEST_LANE0_1 = 0x0206,
++ DPCD_ADDRESS_ADJUST_REQUEST_LANE2_3 = 0x0207,
++ DPCD_ADDRESS_ADJUST_REQUEST_POST_CURSOR2 = 0x020C,
++
++ /* Test Request Field */
++ DPCD_ADDRESS_TEST_REQUEST = 0x0218,
++ DPCD_ADDRESS_TEST_LINK_RATE = 0x0219,
++ DPCD_ADDRESS_TEST_LANE_COUNT = 0x0220,
++ DPCD_ADDRESS_TEST_PATTERN = 0x0221,
++ DPCD_ADDRESS_TEST_MISC1 = 0x0232,
++
++ /* Phy Test Pattern Field */
++ DPCD_ADDRESS_TEST_PHY_PATTERN = 0x0248,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_7_0 = 0x0250,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_15_8 = 0x0251,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_23_16 = 0x0252,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_31_24 = 0x0253,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_39_32 = 0x0254,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_47_40 = 0x0255,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_55_48 = 0x0256,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_63_56 = 0x0257,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_71_64 = 0x0258,
++ DPCD_ADDRESS_TEST_80BIT_CUSTOM_PATTERN_79_72 = 0x0259,
++
++ /* Test Response Field*/
++ DPCD_ADDRESS_TEST_RESPONSE = 0x0260,
++
++ /* Audio Test Pattern Field 1.2*/
++ DPCD_ADDRESS_TEST_AUDIO_MODE = 0x0271,
++ DPCD_ADDRESS_TEST_AUDIO_PATTERN_TYPE = 0x0272,
++ DPCD_ADDRESS_TEST_AUDIO_PERIOD_CH_1 = 0x0273,
++ DPCD_ADDRESS_TEST_AUDIO_PERIOD_CH_2 = 0x0274,
++ DPCD_ADDRESS_TEST_AUDIO_PERIOD_CH_3 = 0x0275,
++ DPCD_ADDRESS_TEST_AUDIO_PERIOD_CH_4 = 0x0276,
++ DPCD_ADDRESS_TEST_AUDIO_PERIOD_CH_5 = 0x0277,
++ DPCD_ADDRESS_TEST_AUDIO_PERIOD_CH_6 = 0x0278,
++ DPCD_ADDRESS_TEST_AUDIO_PERIOD_CH_7 = 0x0279,
++ DPCD_ADDRESS_TEST_AUDIO_PERIOD_CH_8 = 0x027A,
++
++ /* Payload Table Status Field */
++ DPCD_ADDRESS_PAYLOAD_TABLE_UPDATE_STATUS = 0x002C0,/*1.2*/
++ DPCD_ADDRESS_VC_PAYLOAD_ID_SLOT1 = 0x002C1,/*1.2*/
++ DPCD_ADDRESS_VC_PAYLOAD_ID_SLOT63 = 0x002FF,/*1.2*/
++
++ /* Source Device Specific Field */
++ DPCD_ADDRESS_SOURCE_DEVICE_ID_START = 0x0300,
++ DPCD_ADDRESS_SOURCE_DEVICE_ID_END = 0x0301,
++ DPCD_ADDRESS_SOURCE_RESERVED_START = 0x030C,
++ DPCD_ADDRESS_SOURCE_RESERVED_END = 0x03FF,
++
++ /* Sink Device Specific Field */
++ DPCD_ADDRESS_SINK_DEVICE_ID_START = 0x0400,
++ DPCD_ADDRESS_SINK_DEVICE_ID_END = 0x0402,
++ DPCD_ADDRESS_SINK_DEVICE_STR_START = 0x0403,
++ DPCD_ADDRESS_SINK_DEVICE_STR_END = 0x0408,
++ DPCD_ADDRESS_SINK_REVISION_START = 0x409,
++ DPCD_ADDRESS_SINK_REVISION_END = 0x40B,
++
++ /* Branch Device Specific Field */
++ DPCD_ADDRESS_BRANCH_DEVICE_ID_START = 0x0500,
++ DPCD_ADDRESS_BRANCH_DEVICE_ID_END = 0x0502,
++ DPCD_ADDRESS_BRANCH_DEVICE_STR_START = 0x0503,
++ DPCD_ADDRESS_BRANCH_DEVICE_STR_END = 0x0508,
++
++ DPCD_ADDRESS_POWER_STATE = 0x0600,
++
++ /* EDP related */
++ DPCD_ADDRESS_EDP_REV = 0x0700,
++ DPCD_ADDRESS_EDP_CAPABILITY = 0x0701,
++ DPCD_ADDRESS_EDP_BACKLIGHT_ADJUST_CAP = 0x0702,
++ DPCD_ADDRESS_EDP_GENERAL_CAP2 = 0x0703,
++
++ DPCD_ADDRESS_EDP_DISPLAY_CONTROL = 0x0720,
++ DPCD_ADDRESS_EDP_BACKLIGHT_SET = 0x0721,
++ DPCD_ADDRESS_EDP_BACKLIGHT_BRIGHTNESS_MSB = 0x0722,
++ DPCD_ADDRESS_EDP_BACKLIGHT_BRIGHTNESS_LSB = 0x0723,
++ DPCD_ADDRESS_EDP_PWMGEN_BIT_COUNT = 0x0724,
++ DPCD_ADDRESS_EDP_PWMGEN_BIT_COUNT_CAP_MIN = 0x0725,
++ DPCD_ADDRESS_EDP_PWMGEN_BIT_COUNT_CAP_MAX = 0x0726,
++ DPCD_ADDRESS_EDP_BACKLIGHT_CONTROL_STATUS = 0x0727,
++ DPCD_ADDRESS_EDP_BACKLIGHT_FREQ_SET = 0x0728,
++ DPCD_ADDRESS_EDP_REVERVED = 0x0729,
++ DPCD_ADDRESS_EDP_BACKLIGNT_FREQ_CAP_MIN_MSB = 0x072A,
++ DPCD_ADDRESS_EDP_BACKLIGNT_FREQ_CAP_MIN_MID = 0x072B,
++ DPCD_ADDRESS_EDP_BACKLIGNT_FREQ_CAP_MIN_LSB = 0x072C,
++ DPCD_ADDRESS_EDP_BACKLIGNT_FREQ_CAP_MAX_MSB = 0x072D,
++ DPCD_ADDRESS_EDP_BACKLIGNT_FREQ_CAP_MAX_MID = 0x072E,
++ DPCD_ADDRESS_EDP_BACKLIGNT_FREQ_CAP_MAX_LSB = 0x072F,
++
++ DPCD_ADDRESS_EDP_DBC_MINIMUM_BRIGHTNESS_SET = 0x0732,
++ DPCD_ADDRESS_EDP_DBC_MAXIMUM_BRIGHTNESS_SET = 0x0733,
++
++ /* Sideband MSG Buffers 1.2 */
++ DPCD_ADDRESS_DOWN_REQ_START = 0x01000,
++ DPCD_ADDRESS_DOWN_REQ_END = 0x011ff,
++
++ DPCD_ADDRESS_UP_REP_START = 0x01200,
++ DPCD_ADDRESS_UP_REP_END = 0x013ff,
++
++ DPCD_ADDRESS_DOWN_REP_START = 0x01400,
++ DPCD_ADDRESS_DOWN_REP_END = 0x015ff,
++
++ DPCD_ADDRESS_UP_REQ_START = 0x01600,
++ DPCD_ADDRESS_UP_REQ_END = 0x017ff,
++
++ /* ESI (Event Status Indicator) Field 1.2 */
++ DPCD_ADDRESS_SINK_COUNT_ESI = 0x02002,
++ DPCD_ADDRESS_DEVICE_IRQ_ESI0 = 0x02003,
++ DPCD_ADDRESS_DEVICE_IRQ_ESI1 = 0x02004,
++ /*@todo move dpcd_address_Lane01Status back here*/
++
++ DPCD_ADDRESS_PSR_ERROR_STATUS = 0x2006,
++ DPCD_ADDRESS_PSR_EVENT_STATUS = 0x2007,
++ DPCD_ADDRESS_PSR_SINK_STATUS = 0x2008,
++ DPCD_ADDRESS_PSR_DBG_REGISTER0 = 0x2009,
++ DPCD_ADDRESS_PSR_DBG_REGISTER1 = 0x200A,
++
++ /* Travis specific addresses */
++ DPCD_ADDRESS_TRAVIS_SINK_DEV_SEL = 0x5f0,
++ DPCD_ADDRESS_TRAVIS_SINK_ACCESS_OFFSET = 0x5f1,
++ DPCD_ADDRESS_TRAVIS_SINK_ACCESS_REG = 0x5f2,
++};
++
++enum dpcd_revision {
++ DPCD_REV_10 = 0x10,
++ DPCD_REV_11 = 0x11,
++ DPCD_REV_12 = 0x12
++};
++
++enum dp_pwr_state {
++ DP_PWR_STATE_D0 = 1,/* direct HW translation! */
++ DP_PWR_STATE_D3
++};
++
++/* these are the types stored at DOWNSTREAMPORT_PRESENT */
++enum dpcd_downstream_port_type {
++ DOWNSTREAM_DP = 0,
++ DOWNSTREAM_VGA,
++ DOWNSTREAM_DVI_HDMI,
++ DOWNSTREAM_NONDDC /* has no EDID (TV,CV) */
++};
++
++enum dpcd_link_test_patterns {
++ LINK_TEST_PATTERN_NONE = 0,
++ LINK_TEST_PATTERN_COLOR_RAMP,
++ LINK_TEST_PATTERN_VERTICAL_BARS,
++ LINK_TEST_PATTERN_COLOR_SQUARES
++};
++
++enum dpcd_test_color_format {
++ TEST_COLOR_FORMAT_RGB = 0,
++ TEST_COLOR_FORMAT_YCBCR422,
++ TEST_COLOR_FORMAT_YCBCR444
++};
++
++enum dpcd_test_bit_depth {
++ TEST_BIT_DEPTH_6 = 0,
++ TEST_BIT_DEPTH_8,
++ TEST_BIT_DEPTH_10,
++ TEST_BIT_DEPTH_12,
++ TEST_BIT_DEPTH_16
++};
++
++/* PHY (encoder) test patterns
++The order of test patterns follows DPCD register PHY_TEST_PATTERN (0x248) */
++enum dpcd_phy_test_patterns {
++ PHY_TEST_PATTERN_NONE = 0,
++ PHY_TEST_PATTERN_D10_2,
++ PHY_TEST_PATTERN_SYMBOL_ERROR,
++ PHY_TEST_PATTERN_PRBS7,
++ PHY_TEST_PATTERN_80BIT_CUSTOM,/* For DP1.2 only */
++ PHY_TEST_PATTERN_HBR2_COMPLIANCE_EYE/* For DP1.2 only */
++};
++
++enum dpcd_test_dyn_range {
++ TEST_DYN_RANGE_VESA = 0,
++ TEST_DYN_RANGE_CEA
++};
++
++enum dpcd_audio_test_pattern {
++ AUDIO_TEST_PATTERN_OPERATOR_DEFINED = 0,/* direct HW translation */
++ AUDIO_TEST_PATTERN_SAWTOOTH
++};
++
++enum dpcd_audio_sampling_rate {
++ AUDIO_SAMPLING_RATE_32KHZ = 0,/* direct HW translation */
++ AUDIO_SAMPLING_RATE_44_1KHZ,
++ AUDIO_SAMPLING_RATE_48KHZ,
++ AUDIO_SAMPLING_RATE_88_2KHZ,
++ AUDIO_SAMPLING_RATE_96KHZ,
++ AUDIO_SAMPLING_RATE_176_4KHZ,
++ AUDIO_SAMPLING_RATE_192KHZ
++};
++
++enum dpcd_audio_channels {
++ AUDIO_CHANNELS_1 = 0,/* direct HW translation */
++ AUDIO_CHANNELS_2,
++ AUDIO_CHANNELS_3,
++ AUDIO_CHANNELS_4,
++ AUDIO_CHANNELS_5,
++ AUDIO_CHANNELS_6,
++ AUDIO_CHANNELS_7,
++ AUDIO_CHANNELS_8,
++
++ AUDIO_CHANNELS_COUNT
++};
++
++enum dpcd_audio_test_pattern_periods {
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_NOTUSED = 0,/* direct HW translation */
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_3,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_6,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_12,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_24,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_48,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_96,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_192,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_384,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_768,
++ DPCD_AUDIO_TEST_PATTERN_PERIOD_1536
++};
++
++/* This enum is for programming DPCD TRAINING_PATTERN_SET */
++enum dpcd_training_patterns {
++ DPCD_TRAINING_PATTERN_VIDEOIDLE = 0,/* direct HW translation! */
++ DPCD_TRAINING_PATTERN_1,
++ DPCD_TRAINING_PATTERN_2,
++ DPCD_TRAINING_PATTERN_3
++};
++
++/* This enum is for use with PsrSinkPsrStatus.bits.sinkSelfRefreshStatus
++It defines the possible PSR states. */
++enum dpcd_psr_sink_states {
++ PSR_SINK_STATE_INACTIVE = 0,
++ PSR_SINK_STATE_ACTIVE_CAPTURE_DISPLAY_ON_SOURCE_TIMING = 1,
++ PSR_SINK_STATE_ACTIVE_DISPLAY_FROM_SINK_RFB = 2,
++ PSR_SINK_STATE_ACTIVE_CAPTURE_DISPLAY_ON_SINK_TIMING = 3,
++ PSR_SINK_STATE_ACTIVE_CAPTURE_TIMING_RESYNC = 4,
++ PSR_SINK_STATE_SINK_INTERNAL_ERROR = 7,
++};
++
++/* This enum defines the Panel's eDP revision at DPCD 700h
++ * 00h = eDP v1.1 or lower
++ * 01h = eDP v1.2
++ * 02h = eDP v1.3 (PSR support starts here)
++ * 03h = eDP v1.4
++ * If unknown revision, treat as eDP v1.1, meaning least functionality set.
++ * This enum has values matched to eDP spec, thus values should not change.
++ */
++enum dpcd_edp_revision {
++ DPCD_EDP_REVISION_EDP_V1_1 = 0,
++ DPCD_EDP_REVISION_EDP_V1_2 = 1,
++ DPCD_EDP_REVISION_EDP_V1_3 = 2,
++ DPCD_EDP_REVISION_EDP_V1_4 = 3,
++ DPCD_EDP_REVISION_EDP_UNKNOWN = DPCD_EDP_REVISION_EDP_V1_1,
++};
++
++union dpcd_rev {
++ struct {
++ uint8_t MINOR:4;
++ uint8_t MAJOR:4;
++ } bits;
++ uint8_t raw;
++};
++
++union max_lane_count {
++ struct {
++ uint8_t MAX_LANE_COUNT:5;
++ uint8_t POST_LT_ADJ_REQ_SUPPORTED:1;
++ uint8_t TPS3_SUPPORTED:1;
++ uint8_t ENHANCED_FRAME_CAP:1;
++ } bits;
++ uint8_t raw;
++};
++
++union max_down_spread {
++ struct {
++ uint8_t MAX_DOWN_SPREAD:1;
++ uint8_t RESERVED:5;
++ uint8_t NO_AUX_HANDSHAKE_LINK_TRAINING:1;
++ uint8_t RESERVED1:1;
++ } bits;
++ uint8_t raw;
++};
++
++union mstm_cap {
++ struct {
++ uint8_t MST_CAP:1;
++ uint8_t RESERVED:7;
++ } bits;
++ uint8_t raw;
++};
++
++union mstm_cntl {
++ struct {
++ uint8_t MST_EN:1;
++ uint8_t UP_REQ_EN:1;
++ uint8_t UPSTREAM_IS_SRC:1;
++ uint8_t RESERVED:5;
++ } bits;
++ uint8_t raw;
++};
++
++union lane_count_set {
++ struct {
++ uint8_t LANE_COUNT_SET:5;
++ uint8_t POST_LT_ADJ_REQ_GRANTED:1;
++ uint8_t RESERVED:1;
++ uint8_t ENHANCED_FRAMING:1;
++ } bits;
++ uint8_t raw;
++};
++
++/* for DPCD_ADDRESS_I2C_SPEED_CNTL_CAP
++ * and DPCD_ADDRESS_I2C_SPEED_CNTL
++ */
++union i2c_speed {
++ struct {
++ uint8_t _1KBPS:1;
++ uint8_t _5KBPS:1;
++ uint8_t _10KBPS:1;
++ uint8_t _100KBPS:1;
++ uint8_t _400KBPS:1;
++ uint8_t _1MBPS:1;
++ uint8_t reserved:2;
++ } bits;
++ uint8_t raw;
++};
++
++union payload_table_update_status {
++ struct {
++ uint8_t VC_PAYLOAD_TABLE_UPDATED:1;
++ uint8_t ACT_HANDLED:1;
++ } bits;
++ uint8_t raw;
++};
++
++union device_irq_esi_0 {
++ struct {
++ uint8_t REMOTE_CONTROL_CMD_PENDING:1;
++ uint8_t AUTOMATED_TEST_REQUEST:1;
++ uint8_t CP_IRQ:1;
++ uint8_t MCCS_IRQ:1;
++ uint8_t DOWN_REP_MSG_RDY:1;
++ uint8_t UP_REQ_MSG_RDY:1;
++ uint8_t SINK_SPECIFIC_IRQ:1;
++ uint8_t RESERVED:1;
++ } bits;
++ uint8_t raw;
++};
++
++union lane_status {
++ struct {
++ uint8_t CR_DONE_0:1;
++ uint8_t CHANNEL_EQ_DONE_0:1;
++ uint8_t SYMBOL_LOCKED_0:1;
++ uint8_t RESERVED0:1;
++ uint8_t CR_DONE_1:1;
++ uint8_t CHANNEL_EQ_DONE_1:1;
++ uint8_t SYMBOL_LOCKED_1:1;
++ uint8_t RESERVED_1:1;
++ } bits;
++ uint8_t raw;
++};
++
++union device_service_irq {
++ struct {
++ uint8_t REMOTE_CONTROL_CMD_PENDING:1;
++ uint8_t AUTOMATED_TEST:1;
++ uint8_t CP_IRQ:1;
++ uint8_t MCCS_IRQ:1;
++ uint8_t DOWN_REP_MSG_RDY:1;
++ uint8_t UP_REQ_MSG_RDY:1;
++ uint8_t SINK_SPECIFIC:1;
++ uint8_t reserved:1;
++ } bits;
++ uint8_t raw;
++};
++
++union downstream_port {
++ struct {
++ uint8_t PRESENT:1;
++ uint8_t TYPE:2;
++ uint8_t FORMAT_CONV:1;
++ uint8_t DETAILED_CAPS:1;
++ uint8_t RESERVED:3;
++ } bits;
++ uint8_t raw;
++};
++
++union sink_count {
++ struct {
++ uint8_t SINK_COUNT:6;
++ uint8_t CPREADY:1;
++ uint8_t RESERVED:1;
++ } bits;
++ uint8_t raw;
++};
++
++union lane_align_status_updated {
++ struct {
++ uint8_t INTERLANE_ALIGN_DONE:1;
++ uint8_t POST_LT_ADJ_REQ_IN_PROGRESS:1;
++ uint8_t RESERVED:4;
++ uint8_t DOWNSTREAM_PORT_STATUS_CHANGED:1;
++ uint8_t LINK_STATUS_UPDATED:1;
++ } bits;
++ uint8_t raw;
++};
++
++union lane_adjust {
++ struct {
++ uint8_t VOLTAGE_SWING_LANE:2;
++ uint8_t PRE_EMPHASIS_LANE:2;
++ uint8_t RESERVED:4;
++ } bits;
++ uint8_t raw;
++};
++
++/* Automated test structures */
++union test_request {
++ struct {
++ uint8_t LINK_TRAINING:1;
++ uint8_t LINK_TEST_PATTERN:1;
++ uint8_t EDID_READ:1;
++ uint8_t PHY_TEST_PATTERN:1;
++ uint8_t AUDIO_TEST_PATTERN:1;
++ uint8_t AUDIO_TEST_NO_VIDEO:1;
++ uint8_t RESERVED:1;
++ uint8_t TEST_STEREO_3D:1;
++ } bits;
++ uint8_t raw;
++};
++
++union test_response {
++ struct {
++ uint8_t ACK:1;
++ uint8_t NO_ACK:1;
++ uint8_t RESERVED:6;
++ } bits;
++ uint8_t raw;
++};
++
++union link_test_pattern {
++ struct {
++ uint8_t PATTERN:2;/*DpcdLinkTestPatterns*/
++ uint8_t RESERVED:6;
++ } bits;
++ uint8_t raw;
++};
++
++union test_misc {
++ struct dpcd_test_misc_bits {
++ uint8_t SYNC_CLOCK:1;
++ uint8_t CLR_FORMAT:2;/*DpcdTestColorFormat*/
++ uint8_t DYN_RANGE:1;/*DpcdTestDynRange*/
++ uint8_t YCBCR:1;/*DpcdTestYCbCrStandard*/
++ uint8_t BPC:3;/*DpcdTestBitDepth*/
++ } bits;
++ uint8_t raw;
++};
++
++union phy_test_pattern {
++ struct {
++ /* This field is 2 bits for DP1.1 and 3 bits for DP1.2.*/
++ uint8_t PATTERN:3;
++ uint8_t RESERVED:5;/* BY spec, bit7:2 is 0 for DP1.1.*/
++ } bits;
++ uint8_t raw;
++};
++
++union audio_test_mode {
++ struct {
++ uint8_t SAMPLING_RATE:4;
++ uint8_t CHANNEL_COUNT:4;
++ } bits;
++ uint8_t raw;
++};
++
++union audio_tes_tpattern_period {
++ struct {
++ uint8_t PATTERN_PERIOD:4;
++ uint8_t RESERVED:4;
++ } bits;
++ uint8_t raw;
++};
++
++struct audio_test_pattern_type {
++ uint8_t value;
++};
++
++union dpcd_training_pattern {
++ struct {
++ uint8_t TRAINING_PATTERN_SET:2;
++ uint8_t LINK_QUAL_PATTERN_SET:2;
++ uint8_t RECOVERED_CLOCK_OUT_EN:1;
++ uint8_t SCRAMBLING_DISABLE:1;
++ uint8_t RESERVED:2;
++ } bits;
++ uint8_t raw;
++};
++
++/* Training Lane is used to configure downstream DP device's voltage swing
++and pre-emphasis levels*/
++/* The DPCD addresses are from 0x103 to 0x106*/
++union dpcd_training_lane {
++ struct {
++ uint8_t VOLTAGE_SWING_SET:2;
++ uint8_t MAX_SWING_REACHED:1;
++ uint8_t PRE_EMPHASIS_SET:2;
++ uint8_t MAX_PRE_EMPHASIS_REACHED:1;
++ uint8_t RESERVED:2;
++ } bits;
++ uint8_t raw;
++};
++
++/*Training Lane Set 2 is used to configure downstream DP device's
++post cursor 2 level of Training Pattern 2 or 3*/
++/* The DPCD addresses are 0x10F (TRAINING_LANE0_1_SET2)
++and 0x110 (TRAINING_LANE2_3_SET2)*/
++union dpcd_training_lane_set2 {
++ struct {
++ uint8_t POST_CURSOR2_SET:2;
++ uint8_t MAX_POST_CURSOR2_REACHED:1;
++ uint8_t RESERVED:1;
++ } bits;
++ uint8_t raw;
++};
++
++union dpcd_psr_configuration {
++ struct {
++ uint8_t ENABLE:1;
++ uint8_t TRANSMITTER_ACTIVE_IN_PSR:1;
++ uint8_t CRC_VERIFICATION:1;
++ uint8_t FRAME_CAPTURE_INDICATION:1;
++ uint8_t LINE_CAPTURE_INDICATION:1;
++ uint8_t IRQ_HPD_WITH_CRC_ERROR:1;
++ uint8_t RESERVED:2;
++ } bits;
++ uint8_t raw;
++};
++
++union psr_error_status {
++ struct {
++ uint8_t LINK_CRC_ERROR:1;
++ uint8_t RFB_STORAGE_ERROR:1;
++ uint8_t RESERVED:6;
++ } bits;
++ uint8_t raw;
++};
++
++union psr_event_status_ind {
++ struct {
++ uint8_t SINK_PSR_CAP_CHANGE:1;
++ uint8_t RESERVED:7;
++ } bits;
++ uint8_t raw;
++};
++
++union psr_sink_psr_status {
++ struct {
++ uint8_t SINK_SELF_REFRESH_STATUS:3;
++ uint8_t RESERVED:5;
++ } bits;
++ uint8_t raw;
++};
++
++/* EDP related 0x701 */
++union edp_generial_cap1 {
++ struct {
++ uint8_t TCON_BACKLIGHT_ADJUSTMENT_CAPABLE:1;
++ uint8_t BACKLIGHT_PIN_ENABLE_CAPABLE:1;
++ uint8_t BACKLIGHT_AUX_ENABLE_CAPABLE:1;
++ uint8_t PANEL_SELFTEST_PIN_ENABLE_CAPABLE:1;
++ uint8_t BACKLIGHT_SELFTEST_AUX_ENABLE_CAPABLE:1;
++ uint8_t FRC_ENABLE_CAPABLE:1;
++ uint8_t COLOR_ENGINE_CAPABLE:1;
++ /*bit 7, pane can be controlled by 0x600*/
++ uint8_t SET_POWER_CAPABLE:1;
++ } bits;
++ uint8_t raw;
++};
++
++/* TMDS-converter related */
++union dwnstream_port_caps_byte0 {
++ struct {
++ uint8_t DWN_STRM_PORTX_TYPE:3;
++ uint8_t DWN_STRM_PORTX_HPD:1;
++ uint8_t RESERVERD:4;
++ } bits;
++ uint8_t raw;
++};
++
++/* these are the detailed types stored at DWN_STRM_PORTX_CAP (00080h)*/
++enum dpcd_downstream_port_detailed_type {
++ DOWN_STREAM_DETAILED_DP = 0,
++ DOWN_STREAM_DETAILED_VGA,
++ DOWN_STREAM_DETAILED_DVI,
++ DOWN_STREAM_DETAILED_HDMI,
++ DOWN_STREAM_DETAILED_NONDDC,/* has no EDID (TV,CV)*/
++ DOWN_STREAM_DETAILED_DP_PLUS_PLUS
++};
++
++union dwnstream_port_caps_byte2 {
++ struct {
++ uint8_t MAX_BITS_PER_COLOR_COMPONENT:2;
++ uint8_t RESERVED:6;
++ } bits;
++ uint8_t raw;
++};
++
++union dp_downstream_port_present {
++ uint8_t byte;
++ struct {
++ uint8_t PORT_PRESENT:1;
++ uint8_t PORT_TYPE:2;
++ uint8_t FMT_CONVERSION:1;
++ uint8_t DETAILED_CAPS:1;
++ uint8_t RESERVED:3;
++ } fields;
++};
++
++
++union dwnstream_port_caps_byte3_dvi {
++ struct {
++ uint8_t RESERVED1:1;
++ uint8_t DUAL_LINK:1;
++ uint8_t HIGH_COLOR_DEPTH:1;
++ uint8_t RESERVED2:5;
++ } bits;
++ uint8_t raw;
++};
++
++union dwnstream_port_caps_byte3_hdmi {
++ struct {
++ uint8_t FRAME_SEQ_TO_FRAME_PACK:1;
++ uint8_t RESERVED:7;
++ } bits;
++ uint8_t raw;
++};
++
++/*4-byte structure for detailed capabilities of a down-stream port
++(DP-to-TMDS converter).*/
++union dwnstream_portx_caps {
++ struct {
++ union dwnstream_port_caps_byte0 byte0;
++ uint8_t max_tmds_clk;/* byte1 */
++ union dwnstream_port_caps_byte2 byte2;
++
++ union {
++ union dwnstream_port_caps_byte3_dvi byte_dvi;
++ union dwnstream_port_caps_byte3_hdmi byte_hdmi;
++ } byte3;
++ } bytes;
++ uint8_t raw[4];
++};
++
++union sink_status {
++ struct {
++ uint8_t RX_PORT0_STATUS:1;
++ uint8_t RX_PORT1_STATUS:1;
++ uint8_t RESERVED:6;
++ } bits;
++ uint8_t raw;
++};
++
++/*6-byte structure corresponding to 6 registers (200h-205h)
++read during handling of HPD-IRQ*/
++union hpd_irq_data {
++ struct {
++ union sink_count sink_cnt;/* 200h */
++ union device_service_irq device_service_irq;/* 201h */
++ union lane_status lane01_status;/* 202h */
++ union lane_status lane23_status;/* 203h */
++ union lane_align_status_updated lane_status_updated;/* 204h */
++ union sink_status sink_status;
++ } bytes;
++ uint8_t raw[6];
++};
++
++union down_stream_port_count {
++ struct {
++ uint8_t DOWN_STR_PORT_COUNT:4;
++ uint8_t RESERVED:2; /*Bits 5:4 = RESERVED. Read all 0s.*/
++ /*Bit 6 = MSA_TIMING_PAR_IGNORED
++ 0 = Sink device requires the MSA timing parameters
++ 1 = Sink device is capable of rendering incoming video
++ stream without MSA timing parameters*/
++ uint8_t IGNORE_MSA_TIMING_PARAM:1;
++ /*Bit 7 = OUI Support
++ 0 = OUI not supported
++ 1 = OUI supported
++ (OUI and Device Identification mandatory for DP 1.2)*/
++ uint8_t OUI_SUPPORT:1;
++ } bits;
++ uint8_t raw;
++};
++
++union down_spread_ctrl {
++ struct {
++ uint8_t RESERVED1:4;/* Bit 3:0 = RESERVED. Read all 0s*/
++ /* Bits 4 = SPREAD_AMP. Spreading amplitude
++ 0 = Main link signal is not downspread
++ 1 = Main link signal is downspread <= 0.5%
++ with frequency in the range of 30kHz ~ 33kHz*/
++ uint8_t SPREAD_AMP:1;
++ uint8_t RESERVED2:2;/*Bit 6:5 = RESERVED. Read all 0s*/
++ /*Bit 7 = MSA_TIMING_PAR_IGNORE_EN
++ 0 = Source device will send valid data for the MSA Timing Params
++ 1 = Source device may send invalid data for these MSA Timing Params*/
++ uint8_t IGNORE_MSA_TIMING_PARAM:1;
++ } bits;
++ uint8_t raw;
++};
++
++union dpcd_edp_config {
++ struct {
++ uint8_t PANEL_MODE_EDP:1;
++ uint8_t FRAMING_CHANGE_ENABLE:1;
++ uint8_t RESERVED:5;
++ uint8_t PANEL_SELF_TEST_ENABLE:1;
++ } bits;
++ uint8_t raw;
++};
++
++struct dp_device_vendor_id {
++ uint8_t ieee_oui[3];/*24-bit IEEE OUI*/
++ uint8_t ieee_device_id[6];/*usually 6-byte ASCII name*/
++};
++
++struct dp_sink_hw_fw_revision {
++ uint8_t ieee_hw_rev;
++ uint8_t ieee_fw_rev[2];
++};
++
++/*DPCD register of DP receiver capability field bits-*/
++union edp_configuration_cap {
++ struct {
++ uint8_t ALT_SCRAMBLER_RESET:1;
++ uint8_t FRAMING_CHANGE:1;
++ uint8_t RESERVED:1;
++ uint8_t DPCD_DISPLAY_CONTROL_CAPABLE:1;
++ uint8_t RESERVED2:4;
++ } bits;
++ uint8_t raw;
++};
++
++union psr_capabilities {
++ struct {
++ uint8_t EXIT_LT_NOT_REQ:1;
++ uint8_t RFB_SETUP_TIME:3;
++ uint8_t RESERVED:4;
++ } bits;
++ uint8_t raw;
++};
++
++#endif /* __DAL_DPCD_DEFS_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/dvo_interface.h b/drivers/gpu/drm/amd/dal/include/dvo_interface.h
+new file mode 100644
+index 0000000..58d2c6f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/dvo_interface.h
+@@ -0,0 +1,48 @@
++/*
++ * 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_DVO_INTERFACE_H__
++#define __DAL_DVO_INTERFACE_H__
++
++#include "gpio_types.h"
++
++struct dvo;
++
++enum gpio_result dal_dvo_open(
++ struct dvo *dvo,
++ enum gpio_mode mode);
++
++enum gpio_result dal_dvo_get_value(
++ const struct dvo *dvo,
++ uint32_t *value);
++
++enum gpio_result dal_dvo_set_value(
++ const struct dvo *dvo,
++ uint32_t value);
++
++void dal_dvo_close(
++ struct dvo *dvo);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/encoder_interface.h b/drivers/gpu/drm/amd/dal/include/encoder_interface.h
+new file mode 100644
+index 0000000..5fbf816
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/encoder_interface.h
+@@ -0,0 +1,278 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of enc 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 enc 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_ENCODER_INTERFACE_H__
++#define __DAL_ENCODER_INTERFACE_H__
++
++#include "encoder_types.h"
++#include "adapter_service_interface.h"
++#include "fixed31_32.h"
++
++enum encoder_result {
++ ENCODER_RESULT_OK,
++ ENCODER_RESULT_ERROR,
++ ENCODER_RESULT_NOBANDWIDTH,
++ ENCODER_RESULT_SINKCONNECTIVITYCHANGED,
++};
++
++struct encoder_init_data {
++ struct adapter_service *adapter_service;
++ enum channel_id channel;
++ struct graphics_object_id connector;
++ enum hpd_source_id hpd_source;
++ /* TODO: in DAL2, here was pointer to EventManagerInterface */
++ struct graphics_object_id encoder;
++ struct dc_context *ctx;
++};
++
++/* forward declaration */
++struct encoder;
++
++struct encoder *dal_encoder_create(
++ const struct encoder_init_data *init_data);
++
++/* access graphics object base */
++const struct graphics_object_id dal_encoder_get_graphics_object_id(
++ const struct encoder *enc);
++
++/*
++ * Signal types support
++ */
++uint32_t dal_encoder_enumerate_input_signals(
++ const struct encoder *enc);
++uint32_t dal_encoder_enumerate_output_signals(
++ const struct encoder *enc);
++bool dal_encoder_is_input_signal_supported(
++ const struct encoder *enc,
++ enum signal_type signal);
++bool dal_encoder_is_output_signal_supported(
++ const struct encoder *enc,
++ enum signal_type signal);
++void dal_encoder_set_input_signals(
++ struct encoder *enc,
++ uint32_t signals);
++void dal_encoder_set_output_signals(
++ struct encoder *enc,
++ uint32_t signals);
++
++/*
++ * Programming interface
++ */
++/* perform power-up sequence (boot up, resume, recovery) */
++enum encoder_result dal_encoder_power_up(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++/* perform power-down (shut down, stand-by */
++enum encoder_result dal_encoder_power_down(
++ struct encoder *enc,
++ const struct encoder_output *output);
++/* setup encoder block (DIG, DVO, DAC), does not enables encoder */
++enum encoder_result dal_encoder_setup(
++ struct encoder *enc,
++ const struct encoder_output *output);
++/* activate transmitter,
++ * do preparation before enables the actual stream output */
++enum encoder_result dal_encoder_pre_enable_output(
++ struct encoder *enc,
++ const struct encoder_pre_enable_output_param *param);
++/* activate transmitter, enables actual stream output */
++enum encoder_result dal_encoder_enable_output(
++ struct encoder *enc,
++ const struct encoder_output *output);
++/* deactivate transmitter, disables stream output */
++enum encoder_result dal_encoder_disable_output(
++ struct encoder *enc,
++ const struct encoder_output *output);
++/* output blank data,
++ *prevents output of the actual surface data on active transmitter */
++enum encoder_result dal_encoder_blank(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++/* stop sending blank data,
++ * output the actual surface data on active transmitter */
++enum encoder_result dal_encoder_unblank(
++ struct encoder *enc,
++ const struct encoder_unblank_param *param);
++/* setup stereo signal from given controller */
++enum encoder_result dal_encoder_setup_stereo(
++ struct encoder *enc,
++ const struct encoder_3d_setup *setup);
++/* enable HSync/VSync output from given controller */
++enum encoder_result dal_encoder_enable_sync_output(
++ struct encoder *enc,
++ enum sync_source src);
++/* disable HSync/VSync output */
++enum encoder_result dal_encoder_disable_sync_output(
++ struct encoder *enc);
++/* action of encoder before DDC transaction */
++enum encoder_result dal_encoder_pre_ddc(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++/* action of encoder after DDC transaction */
++enum encoder_result dal_encoder_post_ddc(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++/* CRT DDC EDID polling interrupt interface */
++enum encoder_result dal_encoder_update_implementation(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++/* set test pattern signal */
++enum encoder_result dal_encoder_set_dp_phy_pattern(
++ struct encoder *enc,
++ const struct encoder_set_dp_phy_pattern_param *param);
++
++void dal_encoder_release_hw(struct encoder *enc);
++/*
++ * Information interface
++ */
++/* check whether sink is present based on SENSE detection,
++ * analog encoders will return true */
++bool dal_encoder_is_sink_present(
++ struct encoder *enc,
++ struct graphics_object_id downstream);
++/* detect load on the sink,
++ * for analog signal,
++ * load detection will be called for the specified signal */
++enum signal_type dal_encoder_detect_load(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++/* detect output sink type,
++ * for digital perform sense detection,
++ * for analog return encoder's signal type */
++enum signal_type dal_encoder_detect_sink(
++ struct encoder *enc,
++ struct graphics_object_id downstream);
++/* get transmitter id */
++enum transmitter dal_encoder_get_transmitter(
++ const struct encoder *enc);
++/* */
++enum transmitter dal_encoder_get_paired_transmitter(
++ const struct encoder *enc);
++/* */
++enum physical_phy_id dal_encoder_get_phy(
++ const struct encoder *enc);
++/* */
++enum physical_phy_id dal_encoder_get_paired_phy(
++ const struct encoder *enc);
++/* reports if the encoder supports given link settings */
++bool dal_encoder_is_link_settings_supported(
++ struct encoder *enc,
++ const struct link_settings *link_settings);
++/* options and features supported by encoder */
++struct encoder_feature_support dal_encoder_get_supported_features(
++ const struct encoder *enc);
++/* reports list of supported stream engines */
++union supported_stream_engines dal_encoder_get_supported_stream_engines(
++ const struct encoder *enc);
++/* reports preferred stream engine */
++enum engine_id dal_encoder_get_preferred_stream_engine(
++ const struct encoder *enc);
++/* reports whether clock source can be used with enc encoder */
++bool dal_encoder_is_clock_source_supported(
++ const struct encoder *enc,
++ enum clock_source_id clock_source);
++/* check encoder capabilities to confirm
++ * specified timing is in the encoder limits
++ * when outputting certain signal */
++enum encoder_result dal_encoder_validate_output(
++ struct encoder *enc,
++ const struct encoder_output *output);
++/* retrieves sync source which outputs VSync signal from encoder */
++enum sync_source dal_encoder_get_vsync_output_source(
++ const struct encoder *enc);
++/*
++ * Adjustments
++ */
++/* update AVI info frame */
++void dal_encoder_update_info_frame(
++ struct encoder *enc,
++ const struct encoder_info_frame_param *param);
++/* */
++void dal_encoder_stop_info_frame(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++/* */
++enum encoder_result dal_encoder_set_lcd_backlight_level(
++ struct encoder *enc,
++ uint32_t level);
++/* backlight control interface */
++enum encoder_result dal_encoder_backlight_control(
++ struct encoder *enc,
++ bool enable);
++/*
++ * DP MST programming
++ */
++/* update payload slot allocation for each DP MST stream */
++enum encoder_result dal_encoder_update_mst_alloc_table(
++ struct encoder *enc,
++ const struct dp_mst_stream_allocation_table *table,
++ bool is_removal);
++/* enable virtual channel stream with throttled value X.Y */
++enum encoder_result dal_encoder_enable_stream(
++ struct encoder *enc,
++ enum engine_id engine,
++ struct fixed31_32 throttled_vcp_size);
++/* disable virtual channel stream */
++enum encoder_result dal_encoder_disable_stream(
++ struct encoder *enc,
++ enum engine_id engine);
++void dal_encoder_set_multi_path(struct encoder *enc, bool is_multi_path);
++/*
++ * Test harness
++ */
++/* check whether Test Pattern enabled */
++bool dal_encoder_is_test_pattern_enabled(
++ struct encoder *enc,
++ enum engine_id engine);
++/* set lane parameters */
++enum encoder_result dal_encoder_set_lane_settings(
++ struct encoder *enc,
++ const struct encoder_context *ctx,
++ const struct link_training_settings *link_settings);
++/* get lane parameters */
++enum encoder_result dal_encoder_get_lane_settings(
++ struct encoder *enc,
++ const struct encoder_context *ctx,
++ struct link_training_settings *link_settings);
++/* enable master clock of HPD interrupt */
++void dal_encoder_enable_hpd(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++/* disable all HPD interrupts */
++void dal_encoder_disable_hpd(
++ struct encoder *enc,
++ const struct encoder_context *ctx);
++
++/* get current HW state - used for optimization code path only */
++enum clock_source_id dal_encoder_get_active_clock_source(
++ const struct encoder *enc);
++enum engine_id dal_encoder_get_active_engine(
++ const struct encoder *enc);
++
++/* destroy encoder instance */
++void dal_encoder_destroy(
++ struct encoder **ptr);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/encoder_types.h b/drivers/gpu/drm/amd/dal/include/encoder_types.h
+new file mode 100644
+index 0000000..2897a1d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/encoder_types.h
+@@ -0,0 +1,216 @@
++/*
++ * 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_ENCODER_TYPES_H__
++#define __DAL_ENCODER_TYPES_H__
++
++#include "grph_object_defs.h"
++#include "signal_types.h"
++#include "hw_sequencer_types.h"
++#include "link_service_types.h"
++
++struct encoder_context {
++ /*
++ * HW programming context
++ */
++ /* DIG id. Also used as AC context */
++ enum engine_id engine;
++ /* DDC line */
++ enum channel_id channel;
++ /* HPD line */
++ enum hpd_source_id hpd_source;
++ /*
++ * ASIC Control (VBIOS) context
++ */
++ /* encoder output signal */
++ enum signal_type signal;
++ /* native connector id */
++ struct graphics_object_id connector;
++ /* downstream object (can be connector or downstream encoder) */
++ struct graphics_object_id downstream;
++};
++
++union encoder_flags {
++ struct {
++ /* enable audio (DP/eDP only) */
++ uint32_t ENABLE_AUDIO:1;
++ /* coherency */
++ uint32_t COHERENT:1;
++ /* delay after Pixel Format change before enable transmitter */
++ uint32_t DELAY_AFTER_PIXEL_FORMAT_CHANGE:1;
++ /* by default, do not turn off VCC when disabling output */
++ uint32_t TURN_OFF_VCC:1;
++ /* by default, do wait for HPD low after turn of panel VCC */
++ uint32_t NO_WAIT_FOR_HPD_LOW:1;
++ /* slow DP panels don't reset internal fifo */
++ uint32_t VID_STREAM_DIFFER_TO_SYNC:1;
++ } bits;
++ uint32_t raw;
++};
++
++struct encoder_info_packet {
++ bool valid;
++ uint8_t hb0;
++ uint8_t hb1;
++ uint8_t hb2;
++ uint8_t hb3;
++ uint8_t sb[28];
++};
++
++struct encoder_info_frame {
++ /* auxiliary video information */
++ struct encoder_info_packet avi;
++ struct encoder_info_packet gamut;
++ struct encoder_info_packet vendor;
++ /* source product description */
++ struct encoder_info_packet spd;
++ /* video stream configuration */
++ struct encoder_info_packet vsc;
++};
++
++struct encoder_info_frame_param {
++ struct encoder_info_frame packets;
++ struct encoder_context enc_ctx;
++};
++
++/*TODO: cleanup pending encoder cleanup*/
++struct encoder_output {
++ /* encoder AC & HW programming context */
++ struct encoder_context enc_ctx;
++ /* requested timing */
++ struct hw_crtc_timing crtc_timing;
++ /* clock source id (PLL or external) */
++ enum clock_source_id clock_source;
++ /* link settings (DP/eDP only) */
++ struct link_settings link_settings;
++ /* info frame packets */
++ struct encoder_info_frame info_frame;
++ /* timing validation (HDMI only) */
++ uint32_t max_tmds_clk_from_edid_in_mhz;
++ /* edp panel mode */
++ enum dp_panel_mode dp_panel_mode;
++ /* delay in milliseconds after powering up DP receiver (DP/eDP only) */
++ uint32_t delay_after_dp_receiver_power_up;
++ /* various flags for features and workarounds */
++ union encoder_flags flags;
++ /* delay after pixel format change */
++ uint32_t delay_after_pixel_format_change;
++ /* controller id */
++ enum controller_id controller;
++ /* maximum supported deep color depth for HDMI */
++ enum dc_color_depth max_hdmi_deep_color;
++ /* maximum supported pixel clock for HDMI */
++ uint32_t max_hdmi_pixel_clock;
++};
++
++struct encoder_pre_enable_output_param {
++ struct hw_crtc_timing crtc_timing;
++ struct link_settings link_settings;
++ struct encoder_context enc_ctx;
++};
++
++struct encoder_unblank_param {
++ struct hw_crtc_timing crtc_timing;
++ struct link_settings link_settings;
++ enum signal_type signal;
++};
++
++/*
++ * @brief
++ * Parameters to setup stereo 3D mode in Encoder:
++ * - source: used for side-band stereo sync (DVO/DAC);
++ * - engine_id: defines engine for this Encoder;
++ * - enable_inband: in-band stereo sync should be enabled;
++ * - enable_sideband: side-band stereo sync should be enabled.
++ */
++struct encoder_3d_setup {
++ enum engine_id engine;
++ enum sync_source source;
++ union {
++ struct {
++ uint32_t SETUP_SYNC_SOURCE:1;
++ uint32_t ENABLE_INBAND:1;
++ uint32_t ENABLE_SIDEBAND:1;
++ uint32_t DISABLE_INBAND:1;
++ uint32_t DISABLE_SIDEBAND:1;
++ } bits;
++ uint32_t raw;
++ } flags;
++};
++
++struct encoder_set_dp_phy_pattern_param {
++ enum dp_test_pattern dp_phy_pattern;
++ const uint8_t *custom_pattern;
++ uint32_t custom_pattern_size;
++ enum dp_panel_mode dp_panel_mode;
++};
++
++struct encoder_feature_support {
++ union {
++ struct {
++ /* 1 - external encoder; 0 - internal encoder */
++ uint32_t EXTERNAL_ENCODER:1;
++ uint32_t ANALOG_ENCODER:1;
++ uint32_t STEREO_SYNC:1;
++ /* check the DDC data pin
++ * when performing DP Sink detection */
++ uint32_t DP_SINK_DETECT_POLL_DATA_PIN:1;
++ /* CPLIB authentication
++ * for external DP chip supported */
++ uint32_t CPLIB_DP_AUTHENTICATION:1;
++ uint32_t IS_HBR2_CAPABLE:1;
++ uint32_t IS_HBR2_VALIDATED:1;
++ uint32_t IS_TPS3_CAPABLE:1;
++ uint32_t IS_AUDIO_CAPABLE:1;
++ uint32_t IS_VCE_SUPPORTED:1;
++ uint32_t IS_CONVERTER:1;
++ uint32_t IS_Y_ONLY_CAPABLE:1;
++ uint32_t IS_YCBCR_CAPABLE:1;
++ } bits;
++ uint32_t raw;
++ } flags;
++ /* maximum supported deep color depth */
++ enum dc_color_depth max_deep_color;
++ /* maximum supported clock */
++ uint32_t max_pixel_clock;
++};
++
++enum dig_encoder_mode {
++ DIG_ENCODER_MODE_DP,
++ DIG_ENCODER_MODE_LVDS,
++ DIG_ENCODER_MODE_DVI,
++ DIG_ENCODER_MODE_HDMI,
++ DIG_ENCODER_MODE_SDVO,
++ DIG_ENCODER_MODE_DP_WITH_AUDIO,
++ DIG_ENCODER_MODE_DP_MST,
++
++ /* direct HW translation ! */
++ DIG_ENCODER_MODE_TV = 13,
++ DIG_ENCODER_MODE_CV,
++ DIG_ENCODER_MODE_CRT
++};
++
++#endif
++
+diff --git a/drivers/gpu/drm/amd/dal/include/fixed31_32.h b/drivers/gpu/drm/amd/dal/include/fixed31_32.h
+new file mode 100644
+index 0000000..507f9f6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/fixed31_32.h
+@@ -0,0 +1,389 @@
++/*
++ * 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_FIXED31_32_H__
++#define __DAL_FIXED31_32_H__
++
++/*
++ * @brief
++ * Arithmetic operations on real numbers
++ * represented as fixed-point numbers.
++ * There are: 1 bit for sign,
++ * 31 bit for integer part,
++ * 32 bits for fractional part.
++ *
++ * @note
++ * Currently, overflows and underflows are asserted;
++ * no special result returned.
++ */
++
++struct fixed31_32 {
++ int64_t value;
++};
++
++/*
++ * @brief
++ * Useful constants
++ */
++
++static const struct fixed31_32 dal_fixed31_32_zero = { 0 };
++static const struct fixed31_32 dal_fixed31_32_epsilon = { 1LL };
++static const struct fixed31_32 dal_fixed31_32_half = { 0x80000000LL };
++static const struct fixed31_32 dal_fixed31_32_one = { 0x100000000LL };
++
++static const struct fixed31_32 dal_fixed31_32_pi = { 13493037705LL };
++static const struct fixed31_32 dal_fixed31_32_two_pi = { 26986075409LL };
++static const struct fixed31_32 dal_fixed31_32_e = { 11674931555LL };
++static const struct fixed31_32 dal_fixed31_32_ln2 = { 2977044471LL };
++static const struct fixed31_32 dal_fixed31_32_ln2_div_2 = { 1488522236LL };
++
++/*
++ * @brief
++ * Initialization routines
++ */
++
++/*
++ * @brief
++ * result = numerator / denominator
++ */
++struct fixed31_32 dal_fixed31_32_from_fraction(
++ int64_t numerator,
++ int64_t denominator);
++
++/*
++ * @brief
++ * result = arg
++ */
++struct fixed31_32 dal_fixed31_32_from_int(
++ int64_t arg);
++
++/*
++ * @brief
++ * Unary operators
++ */
++
++/*
++ * @brief
++ * result = -arg
++ */
++struct fixed31_32 dal_fixed31_32_neg(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * result = abs(arg) := (arg >= 0) ? arg : -arg
++ */
++struct fixed31_32 dal_fixed31_32_abs(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * Binary relational operators
++ */
++
++/*
++ * @brief
++ * result = arg1 < arg2
++ */
++bool dal_fixed31_32_lt(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * result = arg1 <= arg2
++ */
++bool dal_fixed31_32_le(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * result = arg1 == arg2
++ */
++bool dal_fixed31_32_eq(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * result = min(arg1, arg2) := (arg1 <= arg2) ? arg1 : arg2
++ */
++struct fixed31_32 dal_fixed31_32_min(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * result = max(arg1, arg2) := (arg1 <= arg2) ? arg2 : arg1
++ */
++struct fixed31_32 dal_fixed31_32_max(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * | min_value, when arg <= min_value
++ * result = | arg, when min_value < arg < max_value
++ * | max_value, when arg >= max_value
++ */
++struct fixed31_32 dal_fixed31_32_clamp(
++ struct fixed31_32 arg,
++ struct fixed31_32 min_value,
++ struct fixed31_32 max_value);
++
++/*
++ * @brief
++ * Binary shift operators
++ */
++
++/*
++ * @brief
++ * result = arg << shift
++ */
++struct fixed31_32 dal_fixed31_32_shl(
++ struct fixed31_32 arg,
++ uint8_t shift);
++
++/*
++ * @brief
++ * result = arg >> shift
++ */
++struct fixed31_32 dal_fixed31_32_shr(
++ struct fixed31_32 arg,
++ uint8_t shift);
++
++/*
++ * @brief
++ * Binary additive operators
++ */
++
++/*
++ * @brief
++ * result = arg1 + arg2
++ */
++struct fixed31_32 dal_fixed31_32_add(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * result = arg1 - arg2
++ */
++struct fixed31_32 dal_fixed31_32_sub_int(
++ struct fixed31_32 arg1,
++ int32_t arg2);
++
++/*
++ * @brief
++ * result = arg1 - arg2
++ */
++struct fixed31_32 dal_fixed31_32_sub(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * Binary multiplicative operators
++ */
++
++/*
++ * @brief
++ * result = arg1 * arg2
++ */
++struct fixed31_32 dal_fixed31_32_mul_int(
++ struct fixed31_32 arg1,
++ int32_t arg2);
++
++/*
++ * @brief
++ * result = arg1 * arg2
++ */
++struct fixed31_32 dal_fixed31_32_mul(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * result = square(arg) := arg * arg
++ */
++struct fixed31_32 dal_fixed31_32_sqr(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * result = arg1 / arg2
++ */
++struct fixed31_32 dal_fixed31_32_div_int(
++ struct fixed31_32 arg1,
++ int64_t arg2);
++
++/*
++ * @brief
++ * result = arg1 / arg2
++ */
++struct fixed31_32 dal_fixed31_32_div(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * Reciprocal function
++ */
++
++/*
++ * @brief
++ * result = reciprocal(arg) := 1 / arg
++ *
++ * @note
++ * No special actions taken in case argument is zero.
++ */
++struct fixed31_32 dal_fixed31_32_recip(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * Trigonometric functions
++ */
++
++/*
++ * @brief
++ * result = sinc(arg) := sin(arg) / arg
++ *
++ * @note
++ * Argument specified in radians,
++ * internally it's normalized to [-2pi...2pi] range.
++ */
++struct fixed31_32 dal_fixed31_32_sinc(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * result = sin(arg)
++ *
++ * @note
++ * Argument specified in radians,
++ * internally it's normalized to [-2pi...2pi] range.
++ */
++struct fixed31_32 dal_fixed31_32_sin(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * result = cos(arg)
++ *
++ * @note
++ * Argument specified in radians
++ * and should be in [-2pi...2pi] range -
++ * passing arguments outside that range
++ * will cause incorrect result!
++ */
++struct fixed31_32 dal_fixed31_32_cos(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * Transcendent functions
++ */
++
++/*
++ * @brief
++ * result = exp(arg)
++ *
++ * @note
++ * Currently, function is verified for abs(arg) <= 1.
++ */
++struct fixed31_32 dal_fixed31_32_exp(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * result = log(arg)
++ *
++ * @note
++ * Currently, abs(arg) should be less than 1.
++ * No normalization is done.
++ * Currently, no special actions taken
++ * in case of invalid argument(s). Take care!
++ */
++struct fixed31_32 dal_fixed31_32_log(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * Power function
++ */
++
++/*
++ * @brief
++ * result = pow(arg1, arg2)
++ *
++ * @note
++ * Currently, abs(arg1) should be less than 1. Take care!
++ */
++struct fixed31_32 dal_fixed31_32_pow(
++ struct fixed31_32 arg1,
++ struct fixed31_32 arg2);
++
++/*
++ * @brief
++ * Rounding functions
++ */
++
++/*
++ * @brief
++ * result = floor(arg) := greatest integer lower than or equal to arg
++ */
++int32_t dal_fixed31_32_floor(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * result = round(arg) := integer nearest to arg
++ */
++int32_t dal_fixed31_32_round(
++ struct fixed31_32 arg);
++
++/*
++ * @brief
++ * result = ceil(arg) := lowest integer greater than or equal to arg
++ */
++int32_t dal_fixed31_32_ceil(
++ struct fixed31_32 arg);
++
++/* the following two function are used in scaler hw programming to convert fixed
++ * point value to format 2 bits from integer part and 19 bits from fractional
++ * part. The same applies for u0d19, 0 bits from integer part and 19 bits from
++ * fractional
++ */
++
++uint32_t dal_fixed31_32_u2d19(
++ struct fixed31_32 arg);
++
++uint32_t dal_fixed31_32_u0d19(
++ struct fixed31_32 arg);
++
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/fixed32_32.h b/drivers/gpu/drm/amd/dal/include/fixed32_32.h
+new file mode 100644
+index 0000000..5fca957
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/fixed32_32.h
+@@ -0,0 +1,80 @@
++/*
++ * 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_FIXED32_32_H__
++#define __DAL_FIXED32_32_H__
++
++struct fixed32_32 {
++ uint64_t value;
++};
++
++static const struct fixed32_32 dal_fixed32_32_zero = { 0 };
++static const struct fixed32_32 dal_fixed32_32_one = { 0x100000000LL };
++static const struct fixed32_32 dal_fixed32_32_half = { 0x80000000LL };
++
++struct fixed32_32 dal_fixed32_32_from_fraction(uint32_t n, uint32_t d);
++struct fixed32_32 dal_fixed32_32_from_int(uint32_t value);
++struct fixed32_32 dal_fixed32_32_add(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs);
++struct fixed32_32 dal_fixed32_32_add_int(
++ struct fixed32_32 lhs,
++ uint32_t rhs);
++struct fixed32_32 dal_fixed32_32_sub(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs);
++struct fixed32_32 dal_fixed32_32_sub_int(
++ struct fixed32_32 lhs,
++ uint32_t rhs);
++struct fixed32_32 dal_fixed32_32_mul(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs);
++struct fixed32_32 dal_fixed32_32_mul_int(
++ struct fixed32_32 lhs,
++ uint32_t rhs);
++struct fixed32_32 dal_fixed32_32_div(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs);
++struct fixed32_32 dal_fixed32_32_div_int(
++ struct fixed32_32 lhs,
++ uint32_t rhs);
++struct fixed32_32 dal_fixed32_32_min(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs);
++struct fixed32_32 dal_fixed32_32_max(
++ struct fixed32_32 lhs,
++ struct fixed32_32 rhs);
++bool dal_fixed32_32_gt(struct fixed32_32 lhs, struct fixed32_32 rhs);
++bool dal_fixed32_32_gt_int(struct fixed32_32 lhs, uint32_t rhs);
++bool dal_fixed32_32_lt(struct fixed32_32 lhs, struct fixed32_32 rhs);
++bool dal_fixed32_32_lt_int(struct fixed32_32 lhs, uint32_t rhs);
++bool dal_fixed32_32_le(struct fixed32_32 lhs, struct fixed32_32 rhs);
++bool dal_fixed32_32_le_int(struct fixed32_32 lhs, uint32_t rhs);
++bool dal_fixed32_32_eq(struct fixed32_32 lhs, struct fixed32_32 rhs);
++uint32_t dal_fixed32_32_ceil(struct fixed32_32 value);
++uint32_t dal_fixed32_32_floor(struct fixed32_32 value);
++uint32_t dal_fixed32_32_round(struct fixed32_32 value);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/gpio_interface.h b/drivers/gpu/drm/amd/dal/include/gpio_interface.h
+new file mode 100644
+index 0000000..a084d79
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/gpio_interface.h
+@@ -0,0 +1,93 @@
++/*
++ * 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_GPIO_INTERFACE_H__
++#define __DAL_GPIO_INTERFACE_H__
++
++#include "gpio_types.h"
++#include "grph_object_defs.h"
++
++struct gpio;
++
++/* Open the handle for future use */
++enum gpio_result dal_gpio_open(
++ struct gpio *gpio,
++ enum gpio_mode mode);
++
++enum gpio_result dal_gpio_open_ex(
++ struct gpio *gpio,
++ enum gpio_mode mode,
++ void *options);
++
++/* Get high or low from the pin */
++enum gpio_result dal_gpio_get_value(
++ const struct gpio *gpio,
++ uint32_t *value);
++
++/* Set pin high or low */
++enum gpio_result dal_gpio_set_value(
++ const struct gpio *gpio,
++ uint32_t value);
++
++/* Get current mode */
++enum gpio_mode dal_gpio_get_mode(
++ const struct gpio *gpio);
++
++/* Change mode of the handle */
++enum gpio_result dal_gpio_change_mode(
++ struct gpio *gpio,
++ enum gpio_mode mode);
++
++/* Get the GPIO id */
++enum gpio_id dal_gpio_get_id(
++ const struct gpio *gpio);
++
++/* Get the GPIO enum */
++uint32_t dal_gpio_get_enum(
++ const struct gpio *gpio);
++
++/* Set the GPIO pin configuration */
++enum gpio_result dal_gpio_set_config(
++ struct gpio *gpio,
++ const struct gpio_config_data *config_data);
++
++/* Obtain GPIO pin info */
++enum gpio_result dal_gpio_get_pin_info(
++ const struct gpio *gpio,
++ struct gpio_pin_info *pin_info);
++
++/* Obtain GPIO sync source */
++enum sync_source dal_gpio_get_sync_source(
++ const struct gpio *gpio);
++
++/* Obtain GPIO pin output state (active low or active high) */
++enum gpio_pin_output_state dal_gpio_get_output_state(
++ const struct gpio *gpio);
++
++/* Close the handle */
++void dal_gpio_close(
++ struct gpio *gpio);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/gpio_service_interface.h b/drivers/gpu/drm/amd/dal/include/gpio_service_interface.h
+new file mode 100644
+index 0000000..b22bb1b
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/gpio_service_interface.h
+@@ -0,0 +1,94 @@
++/*
++ * 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_GPIO_SERVICE_INTERFACE_H__
++#define __DAL_GPIO_SERVICE_INTERFACE_H__
++
++#include "gpio_types.h"
++#include "gpio_interface.h"
++#include "dvo_interface.h"
++#include "ddc_interface.h"
++#include "irq_interface.h"
++
++struct gpio_service;
++
++struct gpio_service *dal_gpio_service_create(
++ enum dce_version dce_version,
++ struct dc_context *ctx);
++
++struct gpio *dal_gpio_service_create_gpio(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask,
++ enum gpio_pin_output_state output_state);
++
++struct gpio *dal_gpio_service_create_gpio_ex(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en,
++ enum gpio_pin_output_state output_state);
++
++void dal_gpio_service_destroy_gpio(
++ struct gpio **gpio);
++
++struct ddc *dal_gpio_service_create_ddc(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask,
++ struct gpio_ddc_hw_info *info);
++
++void dal_gpio_service_destroy_ddc(
++ struct ddc **ddc);
++
++struct dvo *dal_gpio_service_create_dvo(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask);
++
++struct dvo *dal_gpio_service_create_dvo_ex(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en);
++
++void dal_gpio_service_destroy_dvo(
++ struct dvo **ptr);
++
++struct irq *dal_gpio_service_create_irq(
++ struct gpio_service *service,
++ uint32_t offset,
++ uint32_t mask);
++
++struct irq *dal_gpio_service_create_irq_ex(
++ struct gpio_service *service,
++ enum gpio_id id,
++ uint32_t en);
++
++void dal_gpio_service_destroy_irq(
++ struct irq **ptr);
++
++void dal_gpio_service_destroy(
++ struct gpio_service **ptr);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/gpio_types.h b/drivers/gpu/drm/amd/dal/include/gpio_types.h
+new file mode 100644
+index 0000000..d616d62
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/gpio_types.h
+@@ -0,0 +1,393 @@
++/*
++ * 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_GPIO_TYPES_H__
++#define __DAL_GPIO_TYPES_H__
++
++#define BUNDLE_A_MASK 0x00FFF000L
++#define BUNDLE_B_MASK 0x00000FFFL
++
++/*
++ * gpio_result
++ *
++ * @brief
++ * The possible return codes that the GPIO object can return.
++ * These return codes can be generated
++ * directly by the GPIO object or from the GPIOPin object.
++ */
++enum gpio_result {
++ GPIO_RESULT_OK,
++ GPIO_RESULT_NULL_HANDLE,
++ GPIO_RESULT_INVALID_DATA,
++ GPIO_RESULT_DEVICE_BUSY,
++ GPIO_RESULT_OPEN_FAILED,
++ GPIO_RESULT_ALREADY_OPENED,
++ GPIO_RESULT_NON_SPECIFIC_ERROR
++};
++
++/*
++ * @brief
++ * Used to identify the specific GPIO device
++ *
++ * @notes
++ * These constants are used as indices in a vector.
++ * Thus they should start from zero and be contiguous.
++ */
++enum gpio_id {
++ GPIO_ID_UNKNOWN = (-1),
++ GPIO_ID_DVO1,
++ GPIO_ID_DVO12,
++ GPIO_ID_DVO24,
++ GPIO_ID_DDC_DATA,
++ GPIO_ID_DDC_CLOCK,
++ GPIO_ID_GENERIC,
++ GPIO_ID_HPD,
++ GPIO_ID_GPIO_PAD,
++ GPIO_ID_VIP_PAD,
++ GPIO_ID_SYNC,
++ GPIO_ID_GSL, /* global swap lock */
++ GPIO_ID_COUNT,
++ GPIO_ID_MIN = GPIO_ID_DVO1,
++ GPIO_ID_MAX = GPIO_ID_GSL
++};
++
++#define GPIO_ENUM_UNKNOWN \
++ 32
++
++struct gpio_pin_info {
++ uint32_t offset;
++ uint32_t offset_y;
++ uint32_t offset_en;
++ uint32_t offset_mask;
++
++ uint32_t mask;
++ uint32_t mask_y;
++ uint32_t mask_en;
++ uint32_t mask_mask;
++};
++
++enum gpio_pin_output_state {
++ GPIO_PIN_OUTPUT_STATE_ACTIVE_LOW,
++ GPIO_PIN_OUTPUT_STATE_ACTIVE_HIGH,
++ GPIO_PIN_OUTPUT_STATE_DEFAULT = GPIO_PIN_OUTPUT_STATE_ACTIVE_LOW
++};
++
++enum gpio_dvo1 {
++ GPIO_DVO1_UNKNOWN = (-1),
++ GPIO_DVO1_0,
++ GPIO_DVO1_1,
++ GPIO_DVO1_2,
++ GPIO_DVO1_3,
++ GPIO_DVO1_4,
++ GPIO_DVO1_5,
++ GPIO_DVO1_6,
++ GPIO_DVO1_7,
++ GPIO_DVO1_8,
++ GPIO_DVO1_9,
++ GPIO_DVO1_10,
++ GPIO_DVO1_11,
++ GPIO_DVO1_12,
++ GPIO_DVO1_13,
++ GPIO_DVO1_14,
++ GPIO_DVO1_15,
++ GPIO_DVO1_16,
++ GPIO_DVO1_17,
++ GPIO_DVO1_18,
++ GPIO_DVO1_19,
++ GPIO_DVO1_20,
++ GPIO_DVO1_21,
++ GPIO_DVO1_22,
++ GPIO_DVO1_23,
++ GPIO_DVO1_COUNT,
++ GPIO_DVO1_MIN = GPIO_DVO1_0,
++ GPIO_DVO1_MAX = GPIO_DVO1_23
++};
++
++enum gpio_dvo12 {
++ GPIO_DVO12_UNKNOWN = (-1),
++ GPIO_DVO12_A,
++ GPIO_DVO12_B,
++ GPIO_DVO12_COUNT,
++ GPIO_DVO12_MIN = GPIO_DVO12_A,
++ GPIO_DVO12_MAX = GPIO_DVO12_B
++};
++
++enum gpio_dvo24 {
++ GPIO_DVO24_UNKNOWN = (-1),
++ GPIO_DVO24_A,
++ GPIO_DVO24_COUNT,
++ GPIO_DVO24_MIN = GPIO_DVO24_A,
++ GPIO_DVO24_MAX = GPIO_DVO24_A
++};
++
++enum gpio_generic {
++ GPIO_GENERIC_UNKNOWN = (-1),
++ GPIO_GENERIC_A,
++ GPIO_GENERIC_B,
++ GPIO_GENERIC_C,
++ GPIO_GENERIC_D,
++ GPIO_GENERIC_E,
++ GPIO_GENERIC_F,
++ GPIO_GENERIC_G,
++ GPIO_GENERIC_COUNT,
++ GPIO_GENERIC_MIN = GPIO_GENERIC_A,
++ GPIO_GENERIC_MAX = GPIO_GENERIC_B
++};
++
++enum gpio_hpd {
++ GPIO_HPD_UNKNOWN = (-1),
++ GPIO_HPD_1,
++ GPIO_HPD_2,
++ GPIO_HPD_3,
++ GPIO_HPD_4,
++ GPIO_HPD_5,
++ GPIO_HPD_6,
++ GPIO_HPD_COUNT,
++ GPIO_HPD_MIN = GPIO_HPD_1,
++ GPIO_HPD_MAX = GPIO_HPD_6
++};
++
++enum gpio_gpio_pad {
++ GPIO_GPIO_PAD_UNKNOWN = (-1),
++ GPIO_GPIO_PAD_0,
++ GPIO_GPIO_PAD_1,
++ GPIO_GPIO_PAD_2,
++ GPIO_GPIO_PAD_3,
++ GPIO_GPIO_PAD_4,
++ GPIO_GPIO_PAD_5,
++ GPIO_GPIO_PAD_6,
++ GPIO_GPIO_PAD_7,
++ GPIO_GPIO_PAD_8,
++ GPIO_GPIO_PAD_9,
++ GPIO_GPIO_PAD_10,
++ GPIO_GPIO_PAD_11,
++ GPIO_GPIO_PAD_12,
++ GPIO_GPIO_PAD_13,
++ GPIO_GPIO_PAD_14,
++ GPIO_GPIO_PAD_15,
++ GPIO_GPIO_PAD_16,
++ GPIO_GPIO_PAD_17,
++ GPIO_GPIO_PAD_18,
++ GPIO_GPIO_PAD_19,
++ GPIO_GPIO_PAD_20,
++ GPIO_GPIO_PAD_21,
++ GPIO_GPIO_PAD_22,
++ GPIO_GPIO_PAD_23,
++ GPIO_GPIO_PAD_24,
++ GPIO_GPIO_PAD_25,
++ GPIO_GPIO_PAD_26,
++ GPIO_GPIO_PAD_27,
++ GPIO_GPIO_PAD_28,
++ GPIO_GPIO_PAD_29,
++ GPIO_GPIO_PAD_30,
++ GPIO_GPIO_PAD_COUNT,
++ GPIO_GPIO_PAD_MIN = GPIO_GPIO_PAD_0,
++ GPIO_GPIO_PAD_MAX = GPIO_GPIO_PAD_30
++};
++
++enum gpio_vip_pad {
++ GPIO_VIP_PAD_UNKNOWN = (-1),
++ /* following never used -
++ * GPIO_ID_DDC_CLOCK::GPIO_DDC_LINE_VIP_PAD defined instead */
++ GPIO_VIP_PAD_SCL,
++ /* following never used -
++ * GPIO_ID_DDC_DATA::GPIO_DDC_LINE_VIP_PAD defined instead */
++ GPIO_VIP_PAD_SDA,
++ GPIO_VIP_PAD_VHAD,
++ GPIO_VIP_PAD_VPHCTL,
++ GPIO_VIP_PAD_VIPCLK,
++ GPIO_VIP_PAD_VID,
++ GPIO_VIP_PAD_VPCLK0,
++ GPIO_VIP_PAD_DVALID,
++ GPIO_VIP_PAD_PSYNC,
++ GPIO_VIP_PAD_COUNT,
++ GPIO_VIP_PAD_MIN = GPIO_VIP_PAD_SCL,
++ GPIO_VIP_PAD_MAX = GPIO_VIP_PAD_PSYNC
++};
++
++enum gpio_sync {
++ GPIO_SYNC_UNKNOWN = (-1),
++ GPIO_SYNC_HSYNC_A,
++ GPIO_SYNC_VSYNC_A,
++ GPIO_SYNC_HSYNC_B,
++ GPIO_SYNC_VSYNC_B,
++ GPIO_SYNC_COUNT,
++ GPIO_SYNC_MIN = GPIO_SYNC_HSYNC_A,
++ GPIO_SYNC_MAX = GPIO_SYNC_VSYNC_B
++};
++
++enum gpio_gsl {
++ GPIO_GSL_UNKNOWN = (-1),
++ GPIO_GSL_GENLOCK_CLOCK,
++ GPIO_GSL_GENLOCK_VSYNC,
++ GPIO_GSL_SWAPLOCK_A,
++ GPIO_GSL_SWAPLOCK_B,
++ GPIO_GSL_COUNT,
++ GPIO_GSL_MIN = GPIO_GSL_GENLOCK_CLOCK,
++ GPIO_GSL_MAX = GPIO_GSL_SWAPLOCK_B
++};
++
++/*
++ * @brief
++ * Unique Id for DDC handle.
++ * Values are meaningful (used as indexes to array)
++ */
++enum gpio_ddc_line {
++ GPIO_DDC_LINE_UNKNOWN = (-1),
++ GPIO_DDC_LINE_DDC1,
++ GPIO_DDC_LINE_DDC2,
++ GPIO_DDC_LINE_DDC3,
++ GPIO_DDC_LINE_DDC4,
++ GPIO_DDC_LINE_DDC5,
++ GPIO_DDC_LINE_DDC6,
++ GPIO_DDC_LINE_DDC_VGA,
++ GPIO_DDC_LINE_VIP_PAD,
++ GPIO_DDC_LINE_I2C_PAD = GPIO_DDC_LINE_VIP_PAD,
++ GPIO_DDC_LINE_COUNT,
++ GPIO_DDC_LINE_MIN = GPIO_DDC_LINE_DDC1,
++ GPIO_DDC_LINE_MAX = GPIO_DDC_LINE_I2C_PAD
++};
++
++/*
++ * @brief
++ * Identifies the mode of operation to open a GPIO device.
++ * A GPIO device (pin) can be programmed in only one of these modes at a time.
++ */
++enum gpio_mode {
++ GPIO_MODE_UNKNOWN = (-1),
++ GPIO_MODE_INPUT,
++ GPIO_MODE_OUTPUT,
++ GPIO_MODE_FAST_OUTPUT,
++ GPIO_MODE_HARDWARE,
++ GPIO_MODE_INTERRUPT
++};
++
++/*
++ * @brief
++ * Identifies the source of the signal when GPIO is in HW mode.
++ * get_signal_source() will return GPIO_SYGNAL_SOURCE__UNKNOWN
++ * when one of the following holds:
++ * 1. GPIO is input GPIO
++ * 2. GPIO is not opened in HW mode
++ * 3. GPIO does not have fixed signal source
++ * (like DC_GenericA have mux instead fixed)
++ */
++enum gpio_signal_source {
++ GPIO_SIGNAL_SOURCE_UNKNOWN = (-1),
++ GPIO_SIGNAL_SOURCE_DACA_STEREO_SYNC,
++ GPIO_SIGNAL_SOURCE_PASS_THROUGH_STEREO_SYNC,
++ GPIO_SIGNAL_SOURCE_DACB_STEREO_SYNC,
++ GPIO_SIGNAL_SOURCE_DACA_HSYNC,
++ GPIO_SIGNAL_SOURCE_DACB_HSYNC,
++ GPIO_SIGNAL_SOURCE_DACA_VSYNC,
++ GPIO_SIGNAL_SOURCE_DACB_VSYNC,
++ GPIO_SIGNAL_SOURCE_DVO_STEREO_SYNC
++};
++
++enum gpio_stereo_source {
++ GPIO_STEREO_SOURCE_UNKNOWN = (-1),
++ GPIO_STEREO_SOURCE_D1,
++ GPIO_STEREO_SOURCE_D2,
++ GPIO_STEREO_SOURCE_D3,
++ GPIO_STEREO_SOURCE_D4,
++ GPIO_STEREO_SOURCE_D5,
++ GPIO_STEREO_SOURCE_D6
++};
++
++/*
++ * GPIO config
++ */
++
++enum gpio_config_type {
++ GPIO_CONFIG_TYPE_NONE,
++ GPIO_CONFIG_TYPE_DDC,
++ GPIO_CONFIG_TYPE_HPD,
++ GPIO_CONFIG_TYPE_GENERIC_MUX,
++ GPIO_CONFIG_TYPE_GSL_MUX,
++ GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE
++};
++
++/* DDC configuration */
++
++enum gpio_ddc_config_type {
++ GPIO_DDC_CONFIG_TYPE_MODE_AUX,
++ GPIO_DDC_CONFIG_TYPE_MODE_I2C,
++ GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT,
++ GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT,
++ GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING
++};
++
++struct gpio_ddc_config {
++ enum gpio_ddc_config_type type;
++ bool data_en_bit_present;
++ bool clock_en_bit_present;
++};
++
++/* HPD configuration */
++
++struct gpio_hpd_config {
++ uint32_t delay_on_connect; /* milliseconds */
++ uint32_t delay_on_disconnect; /* milliseconds */
++};
++
++struct gpio_generic_mux_config {
++ bool enable_output_from_mux;
++ enum gpio_signal_source mux_select;
++ enum gpio_stereo_source stereo_select;
++};
++
++enum gpio_gsl_mux_config_type {
++ GPIO_GSL_MUX_CONFIG_TYPE_DISABLE,
++ GPIO_GSL_MUX_CONFIG_TYPE_TIMING_SYNC,
++ GPIO_GSL_MUX_CONFIG_TYPE_FLIP_SYNC
++};
++
++struct gpio_gsl_mux_config {
++ enum gpio_gsl_mux_config_type type;
++ /* Actually sync_source type,
++ * however we want to avoid inter-component includes here */
++ uint32_t gsl_group;
++};
++
++struct gpio_config_data {
++ enum gpio_config_type type;
++ union {
++ struct gpio_ddc_config ddc;
++ struct gpio_hpd_config hpd;
++ struct gpio_generic_mux_config generic_mux;
++ struct gpio_gsl_mux_config gsl_mux;
++ } config;
++};
++
++struct gpio_ddc_hw_info {
++ bool hw_supported;
++ uint32_t ddc_channel;
++};
++
++struct gpio_ddc_open_options {
++ bool en_bit_present;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/gpu_clock_info.h b/drivers/gpu/drm/amd/dal/include/gpu_clock_info.h
+new file mode 100644
+index 0000000..c9b47b2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/gpu_clock_info.h
+@@ -0,0 +1,43 @@
++/*
++ * 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_GPU_CLOCK_INFO__
++#define __DAL_GPU_CLOCK_INFO__
++
++#include "include/gpu_interface.h"
++
++/*TODO this structures should be defined*/
++struct gpu_static_clk_info;
++struct gpu_dynamic_clk_info;
++
++bool init_static_clk_info(
++ struct gpu *gpu,
++ struct gpu_static_clk_info *st_clk_info);
++
++bool update_dynamic_clk_info(
++ struct gpu *gpu,
++ struct gpu_dynamic_clk_info *dyn_clk_info);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/gpu_interface.h b/drivers/gpu/drm/amd/dal/include/gpu_interface.h
+new file mode 100644
+index 0000000..63262c3
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/gpu_interface.h
+@@ -0,0 +1,91 @@
++/*
++ * 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_GPU_INTERFACE__
++#define __DAL_GPU_INTERFACE__
++
++#include "include/adapter_service_interface.h"
++#include "include/grph_object_ctrl_defs.h"
++
++enum gpu_clocks_state {
++ GPU_CLOCKS_STATE_INVALID,
++ GPU_CLOCKS_STATE_ULTRA_LOW,
++ GPU_CLOCKS_STATE_LOW,
++ GPU_CLOCKS_STATE_NOMINAL,
++ GPU_CLOCKS_STATE_PERFORMANCE
++};
++
++struct gpu_clock_info {
++ uint32_t min_sclk_khz;
++ uint32_t max_sclk_khz;
++
++ uint32_t min_mclk_khz;
++ uint32_t max_mclk_khz;
++
++ uint32_t min_dclk_khz;
++ uint32_t max_dclk_khz;
++};
++
++struct gpu;
++struct irq_manager;
++
++struct gpu_init_data {
++ struct dc_context *ctx;
++ struct adapter_service *adapter_service;
++ struct irq_manager *irq_manager;
++};
++
++struct gpu *dal_gpu_create(struct gpu_init_data *init_data);
++void dal_gpu_destroy(struct gpu **);
++
++void dal_gpu_power_up(struct gpu *);
++void dal_gpu_power_down(
++ struct gpu *gpu,
++ enum dc_video_power_state power_state);
++void dal_gpu_light_sleep_vbios_wa(struct gpu *gpu, bool enable);
++void dal_gpu_release_hw(struct gpu *gpu);
++
++uint32_t dal_gpu_get_num_of_functional_controllers(const struct gpu *gpu);
++uint32_t dal_gpu_get_max_num_of_primary_controllers(const struct gpu *gpu);
++uint32_t dal_gpu_get_max_num_of_underlay_controllers(const struct gpu *gpu);
++struct controller *dal_gpu_create_controller(
++ struct gpu *gpu,
++ uint32_t index);
++uint32_t dal_gpu_get_num_of_clock_sources(const struct gpu *gpu);
++struct clock_source *dal_gpu_create_clock_source(
++ struct gpu *gpu,
++ uint32_t index);
++
++/* gpu_clock_interface implementation */
++bool dal_gpu_init_static_clock_info(struct gpu *gpu,
++ struct gpu_clock_info *gpu_clk_info);
++
++bool dal_gpu_update_dynamic_clock_info(struct gpu *gpu,
++ struct gpu_clock_info *gpu_clk_info);
++
++void dal_gpu_get_static_clock_info(struct gpu *gpu,
++ struct gpu_clock_info *gpu_clk_info);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/grph_csc_types.h b/drivers/gpu/drm/amd/dal/include/grph_csc_types.h
+new file mode 100644
+index 0000000..711b458
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/grph_csc_types.h
+@@ -0,0 +1,98 @@
++/*
++ * 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_GRPH_CSC_TYPES_H__
++#define __DAL_GRPH_CSC_TYPES_H__
++
++#include "set_mode_types.h"
++
++enum color_space {
++ COLOR_SPACE_UNKNOWN,
++ COLOR_SPACE_SRGB_FULL_RANGE,
++ COLOR_SPACE_SRGB_LIMITED_RANGE,
++ COLOR_SPACE_YPBPR601,
++ COLOR_SPACE_YPBPR709,
++ COLOR_SPACE_YCBCR601,
++ COLOR_SPACE_YCBCR709,
++ COLOR_SPACE_YCBCR601_YONLY,
++ COLOR_SPACE_YCBCR709_YONLY,
++ COLOR_SPACE_N_MVPU_SUPER_AA,
++};
++
++enum grph_color_adjust_option {
++ GRPH_COLOR_MATRIX_HW_DEFAULT = 1,
++ GRPH_COLOR_MATRIX_SW
++};
++
++enum grph_csc_adjust_item {
++ GRPH_ADJUSTMENT_CONTRAST = 1,
++ GRPH_ADJUSTMENT_SATURATION,
++ GRPH_ADJUSTMENT_BRIGHTNESS,
++ GRPH_ADJUSTMENT_HUE,
++ GRPH_ADJUSTMENT_COLOR_TEMPERATURE
++};
++
++#define CSC_TEMPERATURE_MATRIX_SIZE 9
++
++enum graphics_csc_adjust_type {
++ GRAPHICS_CSC_ADJUST_TYPE_BYPASS = 0,
++ GRAPHICS_CSC_ADJUST_TYPE_HW, /* without adjustments */
++ GRAPHICS_CSC_ADJUST_TYPE_SW /*use adjustments */
++};
++
++enum graphics_gamut_adjust_type {
++ GRAPHICS_GAMUT_ADJUST_TYPE_BYPASS = 0,
++ GRAPHICS_GAMUT_ADJUST_TYPE_HW, /* without adjustments */
++ GRAPHICS_GAMUT_ADJUST_TYPE_SW /* use adjustments */
++};
++
++struct grph_csc_adjustment {
++ enum grph_color_adjust_option color_adjust_option;
++ enum color_space c_space;
++ int32_t grph_cont;
++ int32_t grph_sat;
++ int32_t grph_bright;
++ int32_t grph_hue;
++ int32_t adjust_divider;
++ int32_t temperature_matrix[CSC_TEMPERATURE_MATRIX_SIZE];
++ int32_t temperature_divider;
++ uint32_t lb_color_depth;
++ uint8_t gamma; /* gamma from Edid */
++ enum dc_color_depth color_depth; /* clean up to uint32_t */
++ enum pixel_format surface_pixel_format;
++ enum graphics_csc_adjust_type csc_adjust_type;
++ enum graphics_gamut_adjust_type gamut_adjust_type;
++};
++
++struct default_adjustment {
++ uint32_t lb_color_depth;
++ enum color_space color_space;
++ enum dc_color_depth color_depth;
++ enum pixel_format surface_pixel_format;
++ enum graphics_csc_adjust_type csc_adjust_type;
++ bool force_hw_default;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/dal/include/grph_object_ctrl_defs.h
+new file mode 100644
+index 0000000..d804109
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/grph_object_ctrl_defs.h
+@@ -0,0 +1,598 @@
++/*
++ * 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_GRPH_OBJECT_CTRL_DEFS_H__
++#define __DAL_GRPH_OBJECT_CTRL_DEFS_H__
++
++#include "grph_object_defs.h"
++
++/*
++ * #####################################################
++ * #####################################################
++ *
++ * These defines shared between asic_control/bios_parser and other
++ * DAL components
++ *
++ * #####################################################
++ * #####################################################
++ */
++
++enum tv_standard {
++ TV_STANDARD_UNKNOWN = 0, /* direct HW (mmBIOS_SCRATCH_2) translation! */
++ TV_STANDARD_NTSC,
++ TV_STANDARD_NTSCJ,
++ TV_STANDARD_PAL,
++ TV_STANDARD_PALM,
++ TV_STANDARD_PALCN,
++ TV_STANDARD_PALN,
++ TV_STANDARD_PAL60,
++ TV_STANDARD_SECAM
++};
++
++enum cv_standard {
++ CV_STANDARD_UNKNOWN = 0x0000,
++ CV_STANDARD_HD_MASK = 0x0800, /* Flag mask HDTV output */
++ CV_STANDARD_SD_NTSC_MASK = 0x1000, /* Flag mask NTSC output */
++ CV_STANDARD_SD_NTSC_M, /* NTSC (North America) output 1001 */
++ CV_STANDARD_SD_NTSC_J, /* NTSC (Japan) output 1002 */
++ CV_STANDARD_SD_480I, /* SDTV 480i output 1003 */
++ CV_STANDARD_SD_480P, /* SDTV 480p output 1004 */
++ CV_STANDARD_HD_720_60P = 0x1800,/* HDTV 720/60p output 1800 */
++ CV_STANDARD_HD_1080_60I, /* HDTV 1080/60i output 1801 */
++ CV_STANDARD_SD_PAL_MASK = 0x2000,/* Flag mask PAL output */
++ CV_STANDARD_SD_PAL_B, /* PAL B output 2001 */
++ CV_STANDARD_SD_PAL_D, /* PAL D output 2002 */
++ CV_STANDARD_SD_PAL_G, /* PAL G output 2003 */
++ CV_STANDARD_SD_PAL_H, /* PAL H output 2004 */
++ CV_STANDARD_SD_PAL_I, /* PAL I output 2005 */
++ CV_STANDARD_SD_PAL_M, /* PAL M output 2006 */
++ CV_STANDARD_SD_PAL_N, /* PAL N output 2007 */
++ CV_STANDARD_SD_PAL_N_COMB, /* PAL Combination N output 2008 */
++ CV_STANDARD_SD_PAL_60, /* PAL 60 output (test mode) 2009 */
++ CV_STANDARD_SD_576I, /* SDTV 576i output 2010 */
++ CV_STANDARD_SD_576P, /* SDTV 576p output 2011 */
++ CV_STANDARD_HD_720_50P = 0x2800,/* HDTV 720/50p output 2800 */
++ CV_STANDARD_HD_1080_50I, /* HDTV 1080/50i output 2801 */
++ CV_STANDARD_SD_SECAM_MASK = 0x4000, /* Flag mask SECAM output */
++ CV_STANDARD_SD_SECAM_B, /* SECAM B output 4001 */
++ CV_STANDARD_SD_SECAM_D, /* SECAM D output 4002 */
++ CV_STANDARD_SD_SECAM_G, /* SECAM G output 4003 */
++ CV_STANDARD_SD_SECAM_H, /* SECAM H output 4004 */
++ CV_STANDARD_SD_SECAM_K, /* SECAM K output 4005 */
++ CV_STANDARD_SD_SECAM_K1, /* SECAM K1 output 4006 */
++ CV_STANDARD_SD_SECAM_L, /* SECAM L output 4007 */
++ CV_STANDARD_SD_SECAM_L1 /* SECAM L1 output 4009 */
++};
++
++enum disp_pll_config {
++ DISP_PLL_CONFIG_UNKNOWN = 0,
++ DISP_PLL_CONFIG_DVO_DDR_MODE_LOW_12BIT,
++ DISP_PLL_CONFIG_DVO_DDR_MODE_UPPER_12BIT,
++ DISP_PLL_CONFIG_DVO_DDR_MODE_24BIT
++};
++
++enum display_output_bit_depth {
++ PANEL_UNDEFINE = 0,
++ PANEL_6BIT_COLOR = 1,
++ PANEL_8BIT_COLOR = 2,
++ PANEL_10BIT_COLOR = 3,
++ PANEL_12BIT_COLOR = 4,
++ PANEL_16BIT_COLOR = 5,
++};
++
++enum lcd_scale {
++ /* No request to turn on LCD SCALER (Centering or Replication) */
++ LCD_SCALE_NONE = 0,
++ /* Request LCD SCALER in full panel mode */
++ LCD_SCALE_FULLPANEL,
++ /* Request LCD SCALER in aspect-ratio mode */
++ LCD_SCALE_ASPECTRATIO,
++
++ LCD_SCALE_UNKNOWN = (-1L),
++};
++
++/* Device type as abstracted by ATOM BIOS */
++enum dal_device_type {
++ DEVICE_TYPE_UNKNOWN = 0,
++ DEVICE_TYPE_LCD,
++ DEVICE_TYPE_CRT,
++ DEVICE_TYPE_DFP,
++ DEVICE_TYPE_CV,
++ DEVICE_TYPE_TV,
++ DEVICE_TYPE_CF,
++ DEVICE_TYPE_WIRELESS
++};
++
++/* Device ID as abstracted by ATOM BIOS */
++struct device_id {
++ enum dal_device_type device_type:16;
++ uint32_t enum_id:16; /* 1 based enum */
++};
++
++struct graphics_object_i2c_info {
++ struct gpio_info {
++ uint32_t clk_mask_register_index;
++ uint32_t clk_en_register_index;
++ uint32_t clk_y_register_index;
++ uint32_t clk_a_register_index;
++ uint32_t data_mask_register_index;
++ uint32_t data_en_register_index;
++ uint32_t data_y_register_index;
++ uint32_t data_a_register_index;
++
++ uint32_t clk_mask_shift;
++ uint32_t clk_en_shift;
++ uint32_t clk_y_shift;
++ uint32_t clk_a_shift;
++ uint32_t data_mask_shift;
++ uint32_t data_en_shift;
++ uint32_t data_y_shift;
++ uint32_t data_a_shift;
++ } gpio_info;
++
++ bool i2c_hw_assist;
++ uint32_t i2c_line;
++ uint32_t i2c_engine_id;
++ uint32_t i2c_slave_address;
++};
++
++
++struct graphics_object_hpd_info {
++ uint8_t hpd_int_gpio_uid;
++ uint8_t hpd_active;
++};
++
++struct connector_device_tag_info {
++ uint32_t acpi_device;
++ struct device_id dev_id;
++};
++
++struct device_timing {
++ struct misc_info {
++ uint32_t HORIZONTAL_CUT_OFF:1;
++ /* 0=Active High, 1=Active Low */
++ uint32_t H_SYNC_POLARITY:1;
++ /* 0=Active High, 1=Active Low */
++ uint32_t V_SYNC_POLARITY:1;
++ uint32_t VERTICAL_CUT_OFF:1;
++ uint32_t H_REPLICATION_BY2:1;
++ uint32_t V_REPLICATION_BY2:1;
++ uint32_t COMPOSITE_SYNC:1;
++ uint32_t INTERLACE:1;
++ uint32_t DOUBLE_CLOCK:1;
++ uint32_t RGB888:1;
++ uint32_t GREY_LEVEL:2;
++ uint32_t SPATIAL:1;
++ uint32_t TEMPORAL:1;
++ uint32_t API_ENABLED:1;
++ } misc_info;
++
++ uint32_t pixel_clk; /* in KHz */
++ uint32_t horizontal_addressable;
++ uint32_t horizontal_blanking_time;
++ uint32_t vertical_addressable;
++ uint32_t vertical_blanking_time;
++ uint32_t horizontal_sync_offset;
++ uint32_t horizontal_sync_width;
++ uint32_t vertical_sync_offset;
++ uint32_t vertical_sync_width;
++ uint32_t horizontal_border;
++ uint32_t vertical_border;
++};
++
++struct supported_refresh_rate {
++ uint32_t REFRESH_RATE_30HZ:1;
++ uint32_t REFRESH_RATE_40HZ:1;
++ uint32_t REFRESH_RATE_48HZ:1;
++ uint32_t REFRESH_RATE_50HZ:1;
++ uint32_t REFRESH_RATE_60HZ:1;
++};
++
++struct embedded_panel_info {
++ struct device_timing lcd_timing;
++ uint32_t ss_id;
++ struct supported_refresh_rate supported_rr;
++ uint32_t drr_enabled;
++ uint32_t min_drr_refresh_rate;
++};
++
++struct embedded_panel_patch_mode {
++ uint32_t width;
++ uint32_t height;
++};
++
++struct firmware_info {
++ struct pll_info {
++ uint32_t crystal_frequency; /* in KHz */
++ uint32_t min_input_pxl_clk_pll_frequency; /* in KHz */
++ uint32_t max_input_pxl_clk_pll_frequency; /* in KHz */
++ uint32_t min_output_pxl_clk_pll_frequency; /* in KHz */
++ uint32_t max_output_pxl_clk_pll_frequency; /* in KHz */
++ } pll_info;
++
++ struct firmware_feature {
++ uint32_t memory_clk_ss_percentage;
++ uint32_t engine_clk_ss_percentage;
++ } feature;
++
++ uint32_t default_display_engine_pll_frequency; /* in KHz */
++ uint32_t external_clock_source_frequency_for_dp; /* in KHz */
++ uint32_t smu_gpu_pll_output_freq; /* in KHz */
++ uint8_t min_allowed_bl_level;
++ uint8_t remote_display_config;
++};
++
++/* direct HW (mmBIOS_SCRATCH_2) translation! */
++union tv_standard_support {
++ uint8_t u_all;
++ struct {
++ bool TV_SUPPORT_NTSC:1;
++ bool TV_SUPPORT_NTSCJ:1;
++
++ bool TV_SUPPORT_PAL:1;
++ bool TV_SUPPORT_PALM:1;
++ bool TV_SUPPORT_PALCN:1;
++ bool TV_SUPPORT_PALN:1;
++ bool TV_SUPPORT_PAL60:1;
++
++ bool TV_SUPPORT_SECAM:1;
++ } bits;
++};
++
++struct analog_tv_info {
++ union tv_standard_support tv_suppported;
++ union tv_standard_support tv_boot_up_default;
++};
++
++struct spread_spectrum_info {
++ struct spread_spectrum_type {
++ bool CENTER_MODE:1;
++ bool EXTERNAL:1;
++ bool STEP_AND_DELAY_INFO:1;
++ } type;
++
++ /* in unit of 0.01% (spreadPercentageDivider = 100),
++ otherwise in 0.001% units (spreadPercentageDivider = 1000); */
++ uint32_t spread_spectrum_percentage;
++ uint32_t spread_percentage_divider; /* 100 or 1000 */
++ uint32_t spread_spectrum_range; /* modulation freq (HZ)*/
++
++ union {
++ struct step_and_delay_info {
++ uint32_t step;
++ uint32_t delay;
++ uint32_t recommended_ref_div;
++ } step_and_delay_info;
++ /* For mem/engine/uvd, Clock Out frequence (VCO ),
++ in unit of kHz. For TMDS/HDMI/LVDS, it is pixel clock,
++ for DP, it is link clock ( 270000 or 162000 ) */
++ uint32_t target_clock_range; /* in KHz */
++ };
++
++};
++
++struct graphics_object_encoder_cap_info {
++ uint32_t dp_hbr2_cap:1;
++ uint32_t dp_hbr2_validated:1;
++ uint32_t reserved:15;
++};
++
++struct din_connector_info {
++ uint32_t gpio_id;
++ bool gpio_tv_active_state;
++};
++
++/* Invalid channel mapping */
++enum { INVALID_DDI_CHANNEL_MAPPING = 0x0 };
++
++/**
++ * DDI PHY channel mapping reflecting XBAR setting
++ */
++union ddi_channel_mapping {
++ struct mapping {
++ uint8_t lane0:2; /* Mapping for lane 0 */
++ uint8_t lane1:2; /* Mapping for lane 1 */
++ uint8_t lane2:2; /* Mapping for lane 2 */
++ uint8_t lane3:2; /* Mapping for lane 3 */
++ } mapping;
++ uint8_t raw;
++};
++
++/**
++* Transmitter output configuration description
++*/
++struct transmitter_configuration_info {
++ /* DDI PHY ID for the transmitter */
++ enum transmitter transmitter_phy_id;
++ /* DDI PHY channel mapping reflecting crossbar setting */
++ union ddi_channel_mapping output_channel_mapping;
++};
++
++struct transmitter_configuration {
++ /* Configuration for the primary transmitter */
++ struct transmitter_configuration_info primary_transmitter_config;
++ /* Secondary transmitter configuration for Dual-link DVI */
++ struct transmitter_configuration_info secondary_transmitter_config;
++};
++
++
++/* These size should be sufficient to store info coming from BIOS */
++#define NUMBER_OF_UCHAR_FOR_GUID 16
++#define MAX_NUMBER_OF_EXT_DISPLAY_PATH 7
++#define NUMBER_OF_CSR_M3_ARB 10
++#define NUMBER_OF_DISP_CLK_VOLTAGE 4
++#define NUMBER_OF_AVAILABLE_SCLK 5
++
++/* V6 */
++struct integrated_info {
++ struct clock_voltage_caps {
++ /* The Voltage Index indicated by FUSE, same voltage index
++ shared with SCLK DPM fuse table */
++ uint32_t voltage_index;
++ /* Maximum clock supported with specified voltage index */
++ uint32_t max_supported_clk; /* in KHz */
++ } disp_clk_voltage[NUMBER_OF_DISP_CLK_VOLTAGE];
++
++ struct display_connection_info {
++ struct external_display_path {
++ /* A bit vector to show what devices are supported */
++ uint32_t device_tag;
++ /* 16bit device ACPI id. */
++ uint32_t device_acpi_enum;
++ /* A physical connector for displays to plug in,
++ using object connector definitions */
++ struct graphics_object_id device_connector_id;
++ /* An index into external AUX/DDC channel LUT */
++ uint8_t ext_aux_ddc_lut_index;
++ /* An index into external HPD pin LUT */
++ uint8_t ext_hpd_pin_lut_index;
++ /* external encoder object id */
++ struct graphics_object_id ext_encoder_obj_id;
++ /* XBAR mapping of the PHY channels */
++ union ddi_channel_mapping channel_mapping;
++ } path[MAX_NUMBER_OF_EXT_DISPLAY_PATH];
++
++ uint8_t gu_id[NUMBER_OF_UCHAR_FOR_GUID];
++ uint8_t checksum;
++ } ext_disp_conn_info; /* exiting long long time */
++
++ struct available_s_clk_list {
++ /* Maximum clock supported with specified voltage index */
++ uint32_t supported_s_clk; /* in KHz */
++ /* The Voltage Index indicated by FUSE for specified SCLK */
++ uint32_t voltage_index;
++ /* The Voltage ID indicated by FUSE for specified SCLK */
++ uint32_t voltage_id;
++ } avail_s_clk[NUMBER_OF_AVAILABLE_SCLK];
++
++ uint8_t memory_type;
++ uint8_t ma_channel_number;
++ uint32_t boot_up_engine_clock; /* in KHz */
++ uint32_t dentist_vco_freq; /* in KHz */
++ uint32_t boot_up_uma_clock; /* in KHz */
++ uint32_t boot_up_req_display_vector;
++ uint32_t other_display_misc;
++ uint32_t gpu_cap_info;
++ uint32_t sb_mmio_base_addr;
++ uint32_t system_config;
++ uint32_t cpu_cap_info;
++ uint32_t max_nb_voltage;
++ uint32_t min_nb_voltage;
++ uint32_t boot_up_nb_voltage;
++ uint32_t ext_disp_conn_info_offset;
++ uint32_t csr_m3_arb_cntl_default[NUMBER_OF_CSR_M3_ARB];
++ uint32_t csr_m3_arb_cntl_uvd[NUMBER_OF_CSR_M3_ARB];
++ uint32_t csr_m3_arb_cntl_fs3d[NUMBER_OF_CSR_M3_ARB];
++ uint32_t gmc_restore_reset_time;
++ uint32_t minimum_n_clk;
++ uint32_t idle_n_clk;
++ uint32_t ddr_dll_power_up_time;
++ uint32_t ddr_pll_power_up_time;
++ /* start for V6 */
++ uint32_t pcie_clk_ss_type;
++ uint32_t lvds_ss_percentage;
++ uint32_t lvds_sspread_rate_in_10hz;
++ uint32_t hdmi_ss_percentage;
++ uint32_t hdmi_sspread_rate_in_10hz;
++ uint32_t dvi_ss_percentage;
++ uint32_t dvi_sspread_rate_in_10_hz;
++ uint32_t sclk_dpm_boost_margin;
++ uint32_t sclk_dpm_throttle_margin;
++ uint32_t sclk_dpm_tdp_limit_pg;
++ uint32_t sclk_dpm_tdp_limit_boost;
++ uint32_t boost_engine_clock;
++ uint32_t boost_vid_2bit;
++ uint32_t enable_boost;
++ uint32_t gnb_tdp_limit;
++ /* Start from V7 */
++ uint32_t max_lvds_pclk_freq_in_single_link;
++ uint32_t lvds_misc;
++ uint32_t lvds_pwr_on_seq_dig_on_to_de_in_4ms;
++ uint32_t lvds_pwr_on_seq_de_to_vary_bl_in_4ms;
++ uint32_t lvds_pwr_off_seq_vary_bl_to_de_in4ms;
++ uint32_t lvds_pwr_off_seq_de_to_dig_on_in4ms;
++ uint32_t lvds_off_to_on_delay_in_4ms;
++ uint32_t lvds_pwr_on_seq_vary_bl_to_blon_in_4ms;
++ uint32_t lvds_pwr_off_seq_blon_to_vary_bl_in_4ms;
++ uint32_t lvds_reserved1;
++ uint32_t lvds_bit_depth_control_val;
++};
++
++/**
++* Power source ids.
++*/
++enum power_source {
++ POWER_SOURCE_AC = 0,
++ POWER_SOURCE_DC,
++ POWER_SOURCE_LIMITED_POWER,
++ POWER_SOURCE_LIMITED_POWER_2,
++ POWER_SOURCE_MAX
++};
++
++struct bios_event_info {
++ uint32_t thermal_state;
++ uint32_t backlight_level;
++ enum power_source powerSource;
++ bool has_thermal_state_changed;
++ bool has_power_source_changed;
++ bool has_forced_mode_changed;
++ bool forced_mode;
++ bool backlight_changed;
++};
++
++union stereo_3d_support {
++ struct {
++ /* HW can alter left and right image sequentially */
++ uint32_t FRAME_ALTERNATE:1;
++ /* Frame Alternate + HW can integrate stereosync
++ signal into TMDS stream */
++ uint32_t DVI_FRAME_ALT:1;
++ /* Frame Alternate + HW can integrate stereosync
++ signal into DP stream */
++ uint32_t DISPLAY_PORT_FRAME_ALT:1;
++ /* Frame Alternate + HW can drive stereosync signal
++ on separate line */
++ uint32_t SIDEBAND_FRAME_ALT:1;
++ /* SW allowed to pack left and right image into single frame.
++ Used for HDMI only, DP has it's own flags. */
++ uint32_t SW_FRAME_PACK:1;
++ /* HW can pack left and right image into single HDMI frame */
++ uint32_t PROGRESSIVE_FRAME_PACK:1;
++ /* HW can pack left and right interlaced images into
++ single HDMI frame */
++ uint32_t INTERLACE_FRAME_PACK:1;
++ /* HW can pack left and right images into single DP frame */
++ uint32_t DISPLAY_PORT_FRAME_PACK:1;
++ /* SW can pack left and right images into single DP frame */
++ uint32_t DISPLAY_PORT_SW_FRAME_PACK:1;
++ /* HW can mix left and right images into single image */
++ uint32_t INTERLEAVE:1;
++ /* HW can mix left and right interlaced images
++ into single image */
++ uint32_t INTERLACE_INTERLEAVE:1;
++ /* Allow display-based formats (whatever supported)
++ in WS stereo mode */
++ uint32_t DISPLAY_3DIN_WS_MODE:1;
++ /* Side-by-side, packed by application/driver into 2D frame */
++ uint32_t SIDE_BY_SIDE_SW_PACKED:1;
++ /* Top-and-bottom, packed by application/driver into 2D frame */
++ uint32_t TOP_AND_BOTTOM_SW_PACKED:1;
++ } bits;
++ uint32_t u_all;
++};
++
++/* Bitvector and bitfields of possible optimizations
++ #IMPORTANT# Keep bitfields match bitvector! */
++enum optimization_feature {
++ /* Don't do HW programming on panels that were enabled by VBIOS */
++ OF_SKIP_HW_PROGRAMMING_ON_ENABLED_EMBEDDED_DISPLAY = 0x1,
++ OF_SKIP_RESET_OF_ALL_HW_ON_S3RESUME = 0x2,
++ OF_SKIP_HW_RESET_OF_EMBEDDED_DISPLAY_ON_S3RESUME = 0x4,
++ OF_SKIP_POWER_UP_VBIOS_ENABLED_ENCODER = 0x8,
++ /* Do not turn off VCC while powering down on boot or resume */
++ OF_KEEP_VCC_DURING_POWER_DOWN_ON_BOOT_OR_RESUME = 0x10,
++ /* Do not turn off VCC while performing SetMode */
++ OF_KEEP_VCC_DURING_SET_MODE = 0x20,
++ OF_DO_NOT_WAIT_FOR_HPD_LOW = 0x40,
++ OF_SKIP_POWER_DOWN_INACTIVE_ENCODER = 0x80
++};
++
++union optimization_flags {
++ struct {
++ /* Don't do HW programming if panels were enabled by VBIOS */
++ uint32_t SKIP_HW_PROGRAMMING_ON_ENABLED_EMBEDDED_DISPLAY:1;
++ uint32_t SKIP_RESET_OF_ALL_HW_ON_S3RESUME:1;
++ uint32_t SKIP_HW_RESET_OF_EMBEDDED_DISPLAY_ON_S3RESUME:1;
++ uint32_t SKIP_POWER_UP_VBIOS_ENABLED_ENCODER:1;
++ /* Do not turn off VCC while powering down on boot or resume */
++ uint32_t KEEP_VCC_DURING_POWER_DOWN_ON_BOOT_OR_RESUME:1;
++ /* Do not turn off VCC while performing SetMode */
++ uint32_t KEEP_VCC_DURING_SET_MODE:1;
++ uint32_t DO_NOT_WAIT_FOR_HPD_LOW:1;
++ } bits;
++ uint32_t u_all;
++};
++
++/* Bitvector and bitfields of performance measurements
++ #IMPORTANT# Keep bitfields match bitvector! */
++enum perf_measure {
++ PERF_MEASURE_ADAPTER_POWER_STATE = 0x1,
++ PERF_MEASURE_DISPLAY_POWER_STATE = 0x2,
++ PERF_MEASURE_SET_MODE_SEQ = 0x4,
++ PERF_MEASURE_DETECT_AT_RESUME = 0x8,
++ PERF_MEASURE_MEMORY_READ_CONTROL = 0x10,
++};
++
++union perf_measure_flags {
++ struct {
++ uint32_t ADAPTER_POWER_STATE:1;
++ uint32_t DISPLAY_POWER_STATE:1;
++ uint32_t SET_MODE_SEQ:1;
++ uint32_t DETECT_AT_RESUME:1;
++ uint32_t MEMORY_READ_CONTROL:1;
++
++ } bits;
++ uint32_t u_all;
++};
++
++enum {
++ PERF_MEASURE_POWERCODE_OFFSET = 0x0,
++ PERF_MEASURE_POWER_CODE_MASK = 0xFF,
++ PERF_MEASURE_POWER_STATE_OFFSET = 8,
++ PERF_MEASURE_POWER_STATE_MASK = 0x000FF00,
++ PERF_MEASURE_PREV_POWER_STATE_OFFSET = 16,
++ PERF_MEASURE_PREV_POWER_STATE_MASK = 0x00FF0000,
++ PERF_MEASURE_DISPLAY_INDEX_OFFSET = 24,
++ PERF_MEASURE_DISPLAY_INDEX_MASK = 0xFF000000
++};
++
++enum {
++ HDMI_PIXEL_CLOCK_IN_KHZ_297 = 297000,
++ TMDS_PIXEL_CLOCK_IN_KHZ_165 = 165000
++};
++
++/*
++ * DFS-bypass flag
++ */
++/* Copy of SYS_INFO_GPUCAPS__ENABEL_DFS_BYPASS from atombios.h */
++enum {
++ DFS_BYPASS_ENABLE = 0x10
++};
++
++enum {
++ INVALID_BACKLIGHT = -1
++};
++
++struct panel_backlight_boundaries {
++ uint32_t min_signal_level;
++ uint32_t max_signal_level;
++};
++
++struct panel_backlight_default_levels {
++ uint32_t ac_level_percentage;
++ uint32_t dc_level_percentage;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/grph_object_defs.h b/drivers/gpu/drm/amd/dal/include/grph_object_defs.h
+new file mode 100644
+index 0000000..a1e468f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/grph_object_defs.h
+@@ -0,0 +1,328 @@
++/*
++ * 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_GRPH_OBJECT_DEFS_H__
++#define __DAL_GRPH_OBJECT_DEFS_H__
++
++#include "grph_object_id.h"
++
++/* ********************************************************************
++ * ********************************************************************
++ *
++ * These defines shared between All Graphics Objects
++ *
++ * ********************************************************************
++ * ********************************************************************
++ */
++
++/* HPD unit id - HW direct translation */
++enum hpd_source_id {
++ HPD_SOURCEID1 = 0,
++ HPD_SOURCEID2,
++ HPD_SOURCEID3,
++ HPD_SOURCEID4,
++ HPD_SOURCEID5,
++ HPD_SOURCEID6,
++
++ HPD_SOURCEID_COUNT,
++ HPD_SOURCEID_UNKNOWN
++};
++
++/* DDC unit id - HW direct translation */
++enum channel_id {
++ CHANNEL_ID_UNKNOWN = 0,
++ CHANNEL_ID_DDC1,
++ CHANNEL_ID_DDC2,
++ CHANNEL_ID_DDC3,
++ CHANNEL_ID_DDC4,
++ CHANNEL_ID_DDC5,
++ CHANNEL_ID_DDC6,
++ CHANNEL_ID_DDC_VGA,
++ CHANNEL_ID_I2C_PAD,
++ CHANNEL_ID_COUNT
++};
++
++#define DECODE_CHANNEL_ID(ch_id) \
++ (ch_id) == CHANNEL_ID_DDC1 ? "CHANNEL_ID_DDC1" : \
++ (ch_id) == CHANNEL_ID_DDC2 ? "CHANNEL_ID_DDC2" : \
++ (ch_id) == CHANNEL_ID_DDC3 ? "CHANNEL_ID_DDC3" : \
++ (ch_id) == CHANNEL_ID_DDC4 ? "CHANNEL_ID_DDC4" : \
++ (ch_id) == CHANNEL_ID_DDC5 ? "CHANNEL_ID_DDC5" : \
++ (ch_id) == CHANNEL_ID_DDC6 ? "CHANNEL_ID_DDC6" : \
++ (ch_id) == CHANNEL_ID_DDC_VGA ? "CHANNEL_ID_DDC_VGA" : \
++ (ch_id) == CHANNEL_ID_I2C_PAD ? "CHANNEL_ID_I2C_PAD" : "Invalid"
++
++enum transmitter {
++ TRANSMITTER_UNKNOWN = (-1L),
++ TRANSMITTER_UNIPHY_A,
++ TRANSMITTER_UNIPHY_B,
++ TRANSMITTER_UNIPHY_C,
++ TRANSMITTER_UNIPHY_D,
++ TRANSMITTER_UNIPHY_E,
++ TRANSMITTER_UNIPHY_F,
++ TRANSMITTER_NUTMEG_CRT,
++ TRANSMITTER_TRAVIS_CRT,
++ TRANSMITTER_TRAVIS_LCD,
++ TRANSMITTER_UNIPHY_G,
++ TRANSMITTER_COUNT
++};
++
++enum physical_phy_id {
++ PHY_ID_UNKNOWN = (-1L),
++ PHY_ID_0,
++ PHY_ID_1,
++ PHY_ID_2,
++ PHY_ID_3,
++ PHY_ID_4,
++ PHY_ID_5,
++ PHY_ID_6,
++ PHY_ID_7,
++ PHY_ID_8,
++ PHY_ID_9,
++ PHY_ID_COUNT
++};
++
++/* Generic source of the synchronisation input/output signal */
++/* Can be used for flow control, stereo sync, timing sync, frame sync, etc */
++enum sync_source {
++ SYNC_SOURCE_NONE = 0,
++
++ /* Source based on controllers */
++ SYNC_SOURCE_CONTROLLER0,
++ SYNC_SOURCE_CONTROLLER1,
++ SYNC_SOURCE_CONTROLLER2,
++ SYNC_SOURCE_CONTROLLER3,
++ SYNC_SOURCE_CONTROLLER4,
++ SYNC_SOURCE_CONTROLLER5,
++
++ /* Source based on GSL group */
++ SYNC_SOURCE_GSL_GROUP0,
++ SYNC_SOURCE_GSL_GROUP1,
++ SYNC_SOURCE_GSL_GROUP2,
++
++ /* Source based on GSL IOs */
++ /* These IOs normally used as GSL input/output */
++ SYNC_SOURCE_GSL_IO_FIRST,
++ SYNC_SOURCE_GSL_IO_GENLOCK_CLOCK = SYNC_SOURCE_GSL_IO_FIRST,
++ SYNC_SOURCE_GSL_IO_GENLOCK_VSYNC,
++ SYNC_SOURCE_GSL_IO_SWAPLOCK_A,
++ SYNC_SOURCE_GSL_IO_SWAPLOCK_B,
++ SYNC_SOURCE_GSL_IO_LAST = SYNC_SOURCE_GSL_IO_SWAPLOCK_B,
++
++ /* Source based on regular IOs */
++ SYNC_SOURCE_IO_FIRST,
++ SYNC_SOURCE_IO_GENERIC_A = SYNC_SOURCE_IO_FIRST,
++ SYNC_SOURCE_IO_GENERIC_B,
++ SYNC_SOURCE_IO_GENERIC_C,
++ SYNC_SOURCE_IO_GENERIC_D,
++ SYNC_SOURCE_IO_GENERIC_E,
++ SYNC_SOURCE_IO_GENERIC_F,
++ SYNC_SOURCE_IO_HPD1,
++ SYNC_SOURCE_IO_HPD2,
++ SYNC_SOURCE_IO_HSYNC_A,
++ SYNC_SOURCE_IO_VSYNC_A,
++ SYNC_SOURCE_IO_HSYNC_B,
++ SYNC_SOURCE_IO_VSYNC_B,
++ SYNC_SOURCE_IO_LAST = SYNC_SOURCE_IO_VSYNC_B,
++
++ /* Misc. flow control sources */
++ SYNC_SOURCE_DUAL_GPU_PIN
++};
++
++enum trigger_edge {
++ TRIGGER_EDGE_RISING = 0,
++ TRIGGER_EDGE_FALLING,
++ TRIGGER_EDGE_BOTH,
++ TRIGGER_EDGE_DEFAULT
++};
++
++/* Parameters to enable CRTC trigger */
++struct trigger_params {
++ enum sync_source source;
++ enum trigger_edge edge;
++};
++
++/* CRTC Static Screen event triggers */
++struct static_screen_events {
++ union {
++ /* event mask to enable/disable various
++ trigger sources for static screen detection */
++ struct {
++ /* Force event high */
++ uint32_t FRAME_START:1;
++ /* Cursor register change */
++ uint32_t CURSOR_MOVE:1;
++ /* Memory write to any client other than MCIF */
++ uint32_t MEM_WRITE:1;
++ /* Memory write to hit memory region 0 */
++ uint32_t MEM_REGION0_WRITE:1;
++ /* Memory write to hit memory region 1 */
++ uint32_t MEM_REGION1_WRITE:1;
++ /* Memory write to hit memory region 2 */
++ uint32_t MEM_REGION2_WRITE:1;
++ /* Memory write to hit memory region 3 */
++ uint32_t MEM_REGION3_WRITE:1;
++ /* Graphics Surface Update Pending */
++ uint32_t GFX_UPDATE:1;
++ /* Overlay Surface Update Pending */
++ uint32_t OVL_UPDATE:1;
++ /* Compressed surface invalidated in FBC */
++ uint32_t INVALIDATE_FBC_SURFACE:1;
++ /* Register pending update in any double buffered
++ register group in the display pipe
++ (i.e. Blender, DCP, or SCL) */
++ uint32_t REG_PENDING_UPDATE:1;
++ /* Crtc_trig_a: Based on signal from any other CRTC */
++ uint32_t CRTC_TRIG_A:1;
++ /* Crtc_trig_b: Based on signal from any other CRTC */
++ uint32_t CRTC_TRIG_B:1;
++ /* Readback of CRTC nominal vertical count register
++ by driver indicates that OS may be trying to change
++ mode or contents of the display therefore need to
++ switch to higher refresh rate */
++ uint32_t READBACK_NOMINAL_VERTICAL:1;
++ /* Readback of CRTC dynamic vertical count register
++ by driver indicates that OS may be trying to change
++ mode or contents of the display therefore need to
++ switch to higher refresh rate */
++ uint32_t READBACK_DYNAMIC_VERTICAL:1;
++ /* Reserved */
++ uint32_t RESERVED:1;
++ } bits;
++ uint32_t u_all;
++ };
++};
++
++
++/*
++ * ***************************************************************
++ * ********************* Register programming sequences ********
++ * ***************************************************************
++ */
++
++/* GPIO/Register access sequences */
++enum io_register_sequence {
++ /* GLSync sequences to access SwapReady & SwapRequest
++ GPIOs - GLSync Connector parameter */
++ IO_REG_SEQUENCE_SWAPREADY_SET = 0,
++ IO_REG_SEQUENCE_SWAPREADY_RESET,
++ IO_REG_SEQUENCE_SWAPREADY_READ,
++ IO_REG_SEQUENCE_SWAPREQUEST_SET,
++ IO_REG_SEQUENCE_SWAPREQUEST_RESET,
++ IO_REG_SEQUENCE_SWAPREQUEST_READ,
++
++ /* Frame synchronization start/stop - display index parameter */
++ IO_REG_SEQUENCE_FRAMELOCK_STOP,
++ IO_REG_SEQUENCE_FRAMELOCK_START,
++
++ /* Flip lock/unlock - GLSync Connector parameter */
++ IO_REG_SEQUENCE_GLOBALSWAP_LOCK,
++ IO_REG_SEQUENCE_GLOBALSWAP_UNLOCK,
++
++ IO_REG_SEQUENCEENUM_MAX
++};
++
++#define IO_REGISTER_SEQUENCE_MAX_LENGTH 5
++
++/*
++ *****************************************************************************
++ * struct io_register
++ *****************************************************************************
++ * Generic struct for read/write register or GPIO.
++ * It allows controlling only some bit section of register, rather then the
++ * whole one.
++ * For write operation should be used as following:
++ * 1. data = READ(Base + RegisterOffset)
++ * 2. data &= ANDMask
++ * 3. data |= ORMask
++ * 4. WRITE(Base + RegisterOffset, data)
++ *
++ * Note: In case of regular register, ANDMask will be typically 0.
++ * In case of GPIO, ANDMask will have typically all bits set
++ * except the specific GPIO bit.
++ *
++ * For read operation should be used as following:
++ * 1. data = READ(Base + RegisterOffset)
++ * 2. data &= ANDMask
++ * 3. data >>= BitShift
++ *
++ * Note: In case of regular register, ANDMask will be typically 0xFFFFFFFF.
++ * In case of GPIO, ANDMask will have typically only specific GPIO bit set
++ *
++ * Note: Base Address is not exposed in this structure due to
++ * security consideration.
++ */
++
++/*
++ * The generic sequence to program/access registers or GPIOs.
++ * There could be 2 types of sequences - read and write.
++ * Read sequence may have 0 or more writes and in the end one read
++ * Write sequence may have 1 or more writes.
++ */
++struct io_reg_sequence {
++ /* Ordered array of register to program */
++ struct {
++ /* Offset of memory mapped register or GPIO */
++ uint32_t register_offset;
++ /* Mask to use at AND operation (Mandatory, comes
++ before OR operation) */
++ uint32_t and_mask;
++ union {
++ /* Mask to use at OR operation (For write
++ sequence only, comes after AND operation) */
++ uint32_t or_mask;
++ /* Number of bits to shift to get the actual value
++ (For read sequence only, comes after AND operation) */
++ uint32_t bit_shift;
++ };
++ } io_registers[IO_REGISTER_SEQUENCE_MAX_LENGTH];
++
++ uint32_t steps_num; /* Total number of r/w steps in the sequence */
++};
++
++/* Sequence ID - uniqly defines sequence on single adapter */
++struct io_reg_sequence_id {
++ enum io_register_sequence sequence; /* Sequence enumeration Index/ID */
++ union {
++ /* Refers to object to which the sequence applies.*/
++ uint32_t index;
++ uint32_t display_index;
++ uint32_t controller_index;
++ uint32_t glsync_connector_index;
++ };
++};
++
++struct fbc_info {
++ bool fbc_enable;
++ bool lpt_enable;
++};
++
++/* Event to request TM change IRQ registration state */
++struct hotplug_irq_data {
++ bool disable;
++ struct graphics_object_id connector;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/grph_object_id.h b/drivers/gpu/drm/amd/dal/include/grph_object_id.h
+new file mode 100644
+index 0000000..fcf3eea
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/grph_object_id.h
+@@ -0,0 +1,285 @@
++/*
++ * 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_GRPH_OBJECT_ID_H__
++#define __DAL_GRPH_OBJECT_ID_H__
++
++/* Types of graphics objects */
++enum object_type {
++ OBJECT_TYPE_UNKNOWN = 0,
++
++ /* Direct ATOM BIOS translation */
++ OBJECT_TYPE_GPU,
++ OBJECT_TYPE_ENCODER,
++ OBJECT_TYPE_CONNECTOR,
++ OBJECT_TYPE_ROUTER,
++ OBJECT_TYPE_GENERIC,
++
++ /* Driver specific */
++ OBJECT_TYPE_AUDIO,
++ OBJECT_TYPE_CONTROLLER,
++ OBJECT_TYPE_CLOCK_SOURCE,
++ OBJECT_TYPE_ENGINE,
++
++ OBJECT_TYPE_COUNT
++};
++
++/* Enumeration inside one type of graphics objects */
++enum object_enum_id {
++ ENUM_ID_UNKNOWN = 0,
++ ENUM_ID_1,
++ ENUM_ID_2,
++ ENUM_ID_3,
++ ENUM_ID_4,
++ ENUM_ID_5,
++ ENUM_ID_6,
++ ENUM_ID_7,
++
++ ENUM_ID_COUNT
++};
++
++/* Generic object ids */
++enum generic_id {
++ GENERIC_ID_UNKNOWN = 0,
++ GENERIC_ID_MXM_OPM,
++ GENERIC_ID_GLSYNC,
++ GENERIC_ID_STEREO,
++
++ GENERIC_ID_COUNT
++};
++
++/* Controller object ids */
++enum controller_id {
++ CONTROLLER_ID_UNDEFINED = 0,
++ CONTROLLER_ID_D0,
++ CONTROLLER_ID_D1,
++ CONTROLLER_ID_D2,
++ CONTROLLER_ID_D3,
++ CONTROLLER_ID_D4,
++ CONTROLLER_ID_D5,
++ CONTROLLER_ID_UNDERLAY0,
++ CONTROLLER_ID_MAX = CONTROLLER_ID_UNDERLAY0
++};
++
++#define IS_UNDERLAY_CONTROLLER(ctrlr_id) (ctrlr_id >= CONTROLLER_ID_UNDERLAY0)
++
++/*
++ * ClockSource object ids.
++ * We maintain the order matching (more or less) ATOM BIOS
++ * to improve optimized acquire
++ */
++enum clock_source_id {
++ CLOCK_SOURCE_ID_UNDEFINED = 0,
++ CLOCK_SOURCE_ID_PLL0,
++ CLOCK_SOURCE_ID_PLL1,
++ CLOCK_SOURCE_ID_PLL2,
++ CLOCK_SOURCE_ID_EXTERNAL, /* ID (Phy) ref. clk. for DP */
++ CLOCK_SOURCE_ID_DCPLL,
++ CLOCK_SOURCE_ID_DFS, /* DENTIST */
++ CLOCK_SOURCE_ID_VCE, /* VCE does not need a real PLL */
++ CLOCK_SOURCE_ID_DP_DTO, /* Used to distinguish between */
++ /* programming pixel clock */
++ /* and ID (Phy) clock */
++};
++
++
++/* Encoder object ids */
++enum encoder_id {
++ ENCODER_ID_UNKNOWN = 0,
++
++ /* Radeon Class Display Hardware */
++ ENCODER_ID_INTERNAL_LVDS,
++ ENCODER_ID_INTERNAL_TMDS1,
++ ENCODER_ID_INTERNAL_TMDS2,
++ ENCODER_ID_INTERNAL_DAC1,
++ ENCODER_ID_INTERNAL_DAC2, /* TV/CV DAC */
++ ENCODER_ID_INTERNAL_SDVOA,
++ ENCODER_ID_INTERNAL_SDVOB,
++
++ /* External Third Party Encoders */
++ ENCODER_ID_EXTERNAL_SI170B,
++ ENCODER_ID_EXTERNAL_CH7303,
++ ENCODER_ID_EXTERNAL_CH7301, /* 10 in decimal */
++ ENCODER_ID_INTERNAL_DVO1, /* Belongs to Radeon Display Hardware */
++ ENCODER_ID_EXTERNAL_SDVOA,
++ ENCODER_ID_EXTERNAL_SDVOB,
++ ENCODER_ID_EXTERNAL_TITFP513,
++ ENCODER_ID_INTERNAL_LVTM1, /* not used for Radeon */
++ ENCODER_ID_EXTERNAL_VT1623,
++ ENCODER_ID_EXTERNAL_SI1930, /* HDMI */
++ ENCODER_ID_INTERNAL_HDMI,
++
++ /* Kaledisope (KLDSCP) Class Display Hardware */
++ ENCODER_ID_INTERNAL_KLDSCP_TMDS1,
++ ENCODER_ID_INTERNAL_KLDSCP_DVO1,
++ ENCODER_ID_INTERNAL_KLDSCP_DAC1,
++ ENCODER_ID_INTERNAL_KLDSCP_DAC2, /* Shared with CV/TV and CRT */
++ /* External TMDS (dual link) */
++ ENCODER_ID_EXTERNAL_SI178,
++ ENCODER_ID_EXTERNAL_MVPU_FPGA, /* MVPU FPGA chip */
++ ENCODER_ID_INTERNAL_DDI,
++ ENCODER_ID_EXTERNAL_VT1625,
++ ENCODER_ID_EXTERNAL_SI1932,
++ ENCODER_ID_EXTERNAL_AN9801, /* External Display Port */
++ ENCODER_ID_EXTERNAL_DP501, /* External Display Port */
++ ENCODER_ID_INTERNAL_UNIPHY,
++ ENCODER_ID_INTERNAL_KLDSCP_LVTMA,
++ ENCODER_ID_INTERNAL_UNIPHY1,
++ ENCODER_ID_INTERNAL_UNIPHY2,
++ ENCODER_ID_EXTERNAL_NUTMEG,
++ ENCODER_ID_EXTERNAL_TRAVIS,
++
++ ENCODER_ID_INTERNAL_WIRELESS, /* Internal wireless display encoder */
++ ENCODER_ID_INTERNAL_UNIPHY3,
++
++ ENCODER_ID_EXTERNAL_GENERIC_DVO = 0xFF
++};
++
++
++/* Connector object ids */
++enum connector_id {
++ CONNECTOR_ID_UNKNOWN = 0,
++ CONNECTOR_ID_SINGLE_LINK_DVII,
++ CONNECTOR_ID_DUAL_LINK_DVII,
++ CONNECTOR_ID_SINGLE_LINK_DVID,
++ CONNECTOR_ID_DUAL_LINK_DVID,
++ CONNECTOR_ID_VGA,
++ CONNECTOR_ID_HDMI_TYPE_A,
++ CONNECTOR_ID_NOT_USED,
++ CONNECTOR_ID_LVDS,
++ CONNECTOR_ID_PCIE,
++ CONNECTOR_ID_HARDCODE_DVI,
++ CONNECTOR_ID_DISPLAY_PORT,
++ CONNECTOR_ID_EDP,
++ CONNECTOR_ID_MXM,
++ CONNECTOR_ID_WIRELESS, /* wireless display pseudo-connector */
++ CONNECTOR_ID_MIRACAST, /* used for VCE encode display path
++ * for Miracast */
++
++ CONNECTOR_ID_COUNT
++};
++
++
++/* Audio object ids */
++enum audio_id {
++ AUDIO_ID_UNKNOWN = 0,
++ AUDIO_ID_INTERNAL_AZALIA
++};
++
++
++/* Engine object ids */
++enum engine_id {
++ ENGINE_ID_DIGA,
++ ENGINE_ID_DIGB,
++ ENGINE_ID_DIGC,
++ ENGINE_ID_DIGD,
++ ENGINE_ID_DIGE,
++ ENGINE_ID_DIGF,
++ ENGINE_ID_DIGG,
++ ENGINE_ID_DVO,
++ ENGINE_ID_DACA,
++ ENGINE_ID_DACB,
++ ENGINE_ID_VCE, /* wireless display pseudo-encoder */
++
++ ENGINE_ID_COUNT,
++ ENGINE_ID_UNKNOWN = (-1L)
++};
++
++union supported_stream_engines {
++ struct {
++ uint32_t ENGINE_ID_DIGA:1;
++ uint32_t ENGINE_ID_DIGB:1;
++ uint32_t ENGINE_ID_DIGC:1;
++ uint32_t ENGINE_ID_DIGD:1;
++ uint32_t ENGINE_ID_DIGE:1;
++ uint32_t ENGINE_ID_DIGF:1;
++ uint32_t ENGINE_ID_DIGG:1;
++ uint32_t ENGINE_ID_DVO:1;
++ uint32_t ENGINE_ID_DACA:1;
++ uint32_t ENGINE_ID_DACB:1;
++ uint32_t ENGINE_ID_VCE:1;
++ } engine;
++ uint32_t u_all;
++};
++
++
++/*
++ *****************************************************************************
++ * graphics_object_id struct
++ *
++ * graphics_object_id is a very simple struct wrapping 32bit Graphics
++ * Object identication
++ *
++ * This struct should stay very simple
++ * No dependencies at all (no includes)
++ * No debug messages or asserts
++ * No #ifndef and preprocessor directives
++ * No grow in space (no more data member)
++ *****************************************************************************
++ */
++
++struct graphics_object_id {
++ uint32_t id:8;
++ uint32_t enum_id:4;
++ uint32_t type:4;
++ uint32_t reserved:16; /* for padding. total size should be u32 */
++};
++
++/* some simple functions for convenient graphics_object_id handle */
++
++static inline struct graphics_object_id dal_graphics_object_id_init(
++ uint32_t id,
++ enum object_enum_id enum_id,
++ enum object_type type)
++{
++ struct graphics_object_id result = {
++ id, enum_id, type, 0
++ };
++
++ return result;
++}
++
++bool dal_graphics_object_id_is_valid(
++ struct graphics_object_id id);
++bool dal_graphics_object_id_is_equal(
++ struct graphics_object_id id1,
++ struct graphics_object_id id2);
++uint32_t dal_graphics_object_id_to_uint(
++ struct graphics_object_id id);
++
++
++enum controller_id dal_graphics_object_id_get_controller_id(
++ struct graphics_object_id id);
++enum clock_source_id dal_graphics_object_id_get_clock_source_id(
++ struct graphics_object_id id);
++enum encoder_id dal_graphics_object_id_get_encoder_id(
++ struct graphics_object_id id);
++enum connector_id dal_graphics_object_id_get_connector_id(
++ struct graphics_object_id id);
++enum audio_id dal_graphics_object_id_get_audio_id(
++ struct graphics_object_id id);
++enum engine_id dal_graphics_object_id_get_engine_id(
++ struct graphics_object_id id);
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/hw_adjustment_set.h b/drivers/gpu/drm/amd/dal/include/hw_adjustment_set.h
+new file mode 100644
+index 0000000..10fb8e2
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/hw_adjustment_set.h
+@@ -0,0 +1,50 @@
++/*
++ * 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_HW_ADJUSTMENT_SET_H__
++#define __DAL_HW_ADJUSTMENT_SET_H__
++
++#include "include/hw_adjustment_types.h"
++
++struct hw_adjustment_gamma_ramp;
++
++struct hw_adjustment_set {
++ struct hw_adjustment_gamma_ramp *gamma_ramp;
++ struct hw_adjustment_deflicker *deflicker_filter;
++ struct hw_adjustment_value *coherent;
++ struct hw_adjustment_value *h_sync;
++ struct hw_adjustment_value *v_sync;
++ struct hw_adjustment_value *composite_sync;
++ struct hw_adjustment_value *backlight;
++ struct hw_adjustment_value *vb_level;
++ struct hw_adjustment_color_control *color_control;
++ union hw_adjustment_bit_depth_reduction *bit_depth;
++};
++/*
++struct hw_adjustment *dal_adjustment_set_get_by_id(
++ struct hw_adjustment_set *adjustment_set,
++ enum hw_adjustment_id id);*/
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/hw_adjustment_types.h b/drivers/gpu/drm/amd/dal/include/hw_adjustment_types.h
+new file mode 100644
+index 0000000..cfae832
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/hw_adjustment_types.h
+@@ -0,0 +1,205 @@
++#ifndef __DAL_HW_ADJUSTMENT_TYPES_H__
++#define __DAL_HW_ADJUSTMENT_TYPES_H__
++
++#include "hw_sequencer_types.h"
++
++enum hw_adjustment_id {
++ HW_ADJUSTMENT_ID_COLOR_CONTROL,
++ HW_ADJUSTMENT_ID_GAMMA_LUT,
++ HW_ADJUSTMENT_ID_GAMMA_RAMP,
++ HW_ADJUSTMENT_ID_DEFLICKER,
++ HW_ADJUSTMENT_ID_SHARPNESS_CONTROL,
++ HW_ADJUSTMENT_ID_TIMING,
++ HW_ADJUSTMENT_ID_TIMING_AND_PIXEL_CLOCK,
++ HW_ADJUSTMENT_ID_OVERSCAN,
++ HW_ADJUSTMENT_ID_UNDERSCAN_TYPE,
++ HW_ADJUSTMENT_ID_VERTICAL_SYNC,
++ HW_ADJUSTMENT_ID_HORIZONTAL_SYNC,
++ HW_ADJUSTMENT_ID_COMPOSITE_SYNC,
++ HW_ADJUSTMENT_ID_VIDEO_STANDARD,
++ HW_ADJUSTMENT_ID_BACKLIGHT,
++ HW_ADJUSTMENT_ID_BIT_DEPTH_REDUCTION,
++ HW_ADJUSTMENT_ID_REDUCED_BLANKING,
++ HW_ADJUSTMENT_ID_COHERENT,
++ /* OVERLAY ADJUSTMENTS*/
++ HW_ADJUSTMENT_ID_OVERLAY,
++ HW_ADJUSTMENT_ID_OVERLAY_ALPHA,
++ HW_ADJUSTMENT_ID_OVERLAY_VARIABLE_GAMMA,
++ HW_ADJUSTMENT_ID_COUNT,
++ HW_ADJUSTMENT_ID_UNDEFINED,
++};
++
++struct hw_adjustment_deflicker {
++ int32_t hp_factor;
++ uint32_t hp_divider;
++ int32_t lp_factor;
++ uint32_t lp_divider;
++ int32_t sharpness;
++ bool enable_sharpening;
++};
++
++struct hw_adjustment_value {
++ union {
++ uint32_t ui_value;
++ int32_t i_value;
++ };
++};
++
++enum hw_color_adjust_option {
++ HWS_COLOR_MATRIX_HW_DEFAULT = 1,
++ HWS_COLOR_MATRIX_SW
++};
++
++enum {
++ HW_TEMPERATURE_MATRIX_SIZE = 9,
++ HW_TEMPERATURE_MATRIX_SIZE_WITH_OFFSET = 12
++};
++
++struct hw_adjustment_color_control {
++ enum hw_color_space color_space;
++ enum hw_color_adjust_option option;
++ enum pixel_format surface_pixel_format;
++ enum dc_color_depth color_depth;
++ uint32_t lb_color_depth;
++ int32_t contrast;
++ int32_t saturation;
++ int32_t brightness;
++ int32_t hue;
++ uint32_t adjust_divider;
++ uint32_t temperature_divider;
++ uint32_t temperature_matrix[HW_TEMPERATURE_MATRIX_SIZE];
++};
++
++struct hw_underscan_adjustment {
++ struct hw_adjustment_deflicker deflicker;
++ struct overscan_info hw_overscan;
++};
++
++struct hw_underscan_adjustment_data {
++ enum hw_adjustment_id hw_adj_id;
++ struct hw_underscan_adjustment hw_underscan_adj;
++};
++
++union hw_adjustment_bit_depth_reduction {
++ uint32_t raw;
++ struct {
++ uint32_t TRUNCATE_ENABLED:1;
++ uint32_t TRUNCATE_DEPTH:2;
++ uint32_t TRUNCATE_MODE:1;
++ uint32_t SPATIAL_DITHER_ENABLED:1;
++ uint32_t SPATIAL_DITHER_DEPTH:2;
++ uint32_t SPATIAL_DITHER_MODE:2;
++ uint32_t RGB_RANDOM:1;
++ uint32_t FRAME_RANDOM:1;
++ uint32_t HIGHPASS_RANDOM:1;
++ uint32_t FRAME_MODULATION_ENABLED:1;
++ uint32_t FRAME_MODULATION_DEPTH:2;
++ uint32_t TEMPORAL_LEVEL:1;
++ uint32_t FRC_25:2;
++ uint32_t FRC_50:2;
++ uint32_t FRC_75:2;
++ } bits;
++};
++
++struct hw_color_control_range {
++ struct hw_adjustment_range contrast;
++ struct hw_adjustment_range saturation;
++ struct hw_adjustment_range brightness;
++ struct hw_adjustment_range hue;
++ struct hw_adjustment_range temperature;
++};
++
++enum hw_surface_type {
++ HW_OVERLAY_SURFACE = 1,
++ HW_GRAPHIC_SURFACE
++};
++
++/* LUT type for GammaCorrection */
++struct hw_gamma_lut {
++ uint32_t red;
++ uint32_t green;
++ uint32_t blue;
++};
++
++struct hw_devc_lut {
++ uint8_t red;
++ uint8_t green;
++ uint8_t blue;
++ uint8_t reserved;
++};
++
++struct hw_adjustment_gamma_lut {
++ struct hw_gamma_lut *pGammaLut;
++ uint32_t size_in_elements;
++ enum pixel_format surface_pixel_format;
++};
++
++
++enum hw_gamma_ramp_type {
++ HW_GAMMA_RAMP_UNITIALIZED = 0,
++ HW_GAMMA_RAMP_DEFAULT,
++ HW_GAMMA_RAMP_RBG_256x3x16,
++ HW_GAMMA_RAMP_RBG_DXGI_1
++};
++
++#define HW_GAMMA_RAMP_RBG_256 256
++
++struct hw_gamma_ramp_rgb256x3x16 {
++ unsigned short red[HW_GAMMA_RAMP_RBG_256];
++ unsigned short green[HW_GAMMA_RAMP_RBG_256];
++ unsigned short blue[HW_GAMMA_RAMP_RBG_256];
++};
++
++union hw_gamma_flags {
++ uint32_t raw;
++ struct {
++ uint32_t gamma_ramp_array :1;
++ uint32_t graphics_degamma_srgb :1;
++ uint32_t overlay_degamma_srgb :1;
++ uint32_t apply_degamma :1;
++ uint32_t reserved :28;
++ } bits;
++};
++
++struct hw_regamma_coefficients {
++ int32_t gamma[3];
++ int32_t a0[3];
++ int32_t a1[3];
++ int32_t a2[3];
++ int32_t a3[3];
++};
++
++struct hw_regamma_ramp {
++ /* Gamma ramp packed as RGB */
++ unsigned short gamma[256 * 3];
++};
++
++struct hw_regamma_lut {
++ union hw_gamma_flags flags;
++ union {
++ struct hw_regamma_ramp gamma;
++ struct hw_regamma_coefficients coeff;
++ };
++};
++
++union hw_gamma_flag {
++ uint32_t uint;
++ struct {
++ uint32_t config_is_changed :1;
++ uint32_t regamma_update :1;
++ uint32_t gamma_update :1;
++ uint32_t reserved :29;
++ } bits;
++};
++
++struct hw_adjustment_gamma_ramp {
++ uint32_t size;
++ enum hw_gamma_ramp_type type;
++ enum pixel_format surface_pixel_format;
++ enum hw_color_space color_space;
++ struct hw_regamma_lut regamma;
++ union hw_gamma_flag flag;
++ struct hw_gamma_ramp_rgb256x3x16 gamma_ramp_rgb256x3x16;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/hw_path_mode_set_interface.h b/drivers/gpu/drm/amd/dal/include/hw_path_mode_set_interface.h
+new file mode 100644
+index 0000000..28ac018
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/hw_path_mode_set_interface.h
+@@ -0,0 +1,48 @@
++/*
++ * 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_HW_PATH_MODE_SET_INTERFACE_H__
++#define __DAL_HW_PATH_MODE_SET_INTERFACE_H__
++
++struct hw_path_mode;
++struct hw_path_mode_set;
++
++struct hw_path_mode_set *dal_hw_path_mode_set_create(void);
++
++void dal_hw_path_mode_set_destroy(struct hw_path_mode_set **set);
++
++bool dal_hw_path_mode_set_add(
++ struct hw_path_mode_set *set,
++ struct hw_path_mode *path_mode,
++ uint32_t *index);
++
++struct hw_path_mode *dal_hw_path_mode_set_get_path_by_index(
++ const struct hw_path_mode_set *set,
++ uint32_t index);
++
++uint32_t dal_hw_path_mode_set_get_paths_number(
++ const struct hw_path_mode_set *set);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/hw_sequencer_interface.h b/drivers/gpu/drm/amd/dal/include/hw_sequencer_interface.h
+new file mode 100644
+index 0000000..ddd78d6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/hw_sequencer_interface.h
+@@ -0,0 +1,388 @@
++/*
++ * 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_HW_SEQUENCER_INTERFACE_H__
++#define __DAL_HW_SEQUENCER_INTERFACE_H__
++
++#include "hw_sequencer_types.h"
++#include "hw_adjustment_types.h"
++#include "include/display_clock_interface.h"
++#include "include/scaler_types.h"
++#include "include/grph_csc_types.h"
++#include "plane_types.h"
++
++#include "adapter_service_interface.h"
++
++enum hwss_result {
++ HWSS_RESULT_OK,
++ HWSS_RESULT_ERROR,
++ HWSS_RESULT_NO_BANDWIDTH,
++ HWSS_RESULT_OUT_OF_RANGE,
++ HWSS_RESULT_NOT_SUPPORTED,
++ HWSS_RESULT_UNKNOWN
++};
++
++struct hws_init_data {
++ struct adapter_service *as;
++ struct dal_context *dal_context;
++};
++
++/* TODO: below is three almost equal structures.
++ * We should decide what to do with them */
++struct blank_stream_param {
++ struct display_path *display_path;
++ uint32_t link_idx;
++ struct hw_crtc_timing timing;
++ struct link_settings link_settings;
++};
++
++struct enable_stream_param {
++ struct display_path *display_path;
++ uint32_t link_idx;
++ struct hw_crtc_timing timing;
++ struct link_settings link_settings;
++
++ const struct hw_path_mode *path_mode;
++};
++
++struct enable_link_param {
++ struct display_path *display_path;
++ uint32_t link_idx;
++ struct hw_crtc_timing timing;
++ struct link_settings link_settings;
++
++ bool optimized_programming;
++ const struct hw_path_mode *path_mode;
++};
++
++struct validate_link_param {
++ const struct display_path *display_path;
++ uint32_t link_idx;
++ struct link_settings link_settings;
++};
++
++struct set_dp_phy_pattern_param {
++ struct display_path *display_path;
++ uint32_t link_idx;
++ enum dp_test_pattern test_pattern;
++ const uint8_t *custom_pattern;
++ uint32_t cust_pattern_size;
++};
++
++struct hw_global_objects;
++struct hw_sequencer;
++struct hw_adjustment;
++struct hw_path_mode_set;
++struct hw_path_mode;
++struct hwss_build_params;
++struct controller;
++
++void dal_hw_sequencer_mute_audio_endpoint(
++ struct hw_sequencer *hws,
++ struct display_path *display_path,
++ bool mute);
++
++void dal_hw_sequencer_enable_audio_endpoint(
++ struct hw_sequencer *hws,
++ struct link_settings *ls,
++ struct display_path *display_path,
++ bool enable);
++
++enum hwss_result dal_hw_sequencer_reset_audio_device(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++enum hwss_result dal_hw_sequencer_validate_link(
++ struct hw_sequencer *hws,
++ const struct validate_link_param *param);
++
++bool dal_hw_sequencer_is_supported_dp_training_pattern3(
++ struct hw_sequencer *hws,
++ struct display_path *display_path,
++ uint32_t link_idx);
++
++enum hwss_result dal_hw_sequencer_set_dp_phy_pattern(
++ struct hw_sequencer *hws,
++ const struct set_dp_phy_pattern_param *param);
++
++enum hwss_result dal_hw_sequencer_set_lane_settings(
++ struct hw_sequencer *hws,
++ struct display_path *display_path,
++ const struct link_training_settings *link_settings);
++
++void dal_hw_sequencer_set_test_pattern(
++ struct hw_sequencer *hws,
++ struct hw_path_mode *path_mode,
++ enum dp_test_pattern test_pattern,
++ const struct link_training_settings *link_settings,
++ const uint8_t *custom_pattern,
++ uint8_t cust_pattern_size);
++
++bool dal_hw_sequencer_has_audio_bandwidth_changed(
++ struct hw_sequencer *hws,
++ const struct hw_path_mode *old,
++ const struct hw_path_mode *new);
++
++void dal_hw_sequencer_enable_azalia_audio_jack_presence(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++void dal_hw_sequencer_disable_azalia_audio_jack_presence(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++void dal_hw_sequencer_enable_memory_requests(
++ struct hw_sequencer *hws,
++ struct hw_path_mode *path_mode);
++
++void dal_hw_sequencer_update_info_packets(
++ struct hw_sequencer *hws,
++ struct hw_path_mode *path_mode);
++
++/* Static validation for a SINGLE path mode.
++ * Already "active" paths (if any) are NOT taken into account. */
++enum hwss_result dal_hw_sequencer_validate_display_path_mode(
++ struct hw_sequencer *hws,
++ const struct hw_path_mode *path_mode);
++
++/* Validation for a SET of path modes, including Video Memory Bandwidth
++ * validation. */
++enum hwss_result dal_hw_sequencer_validate_display_hwpms(
++ struct hw_sequencer *hws,
++ struct hw_path_mode_set *path_set);
++
++struct hw_adjustment_gamma_ramp;
++
++enum hwss_result dal_hw_sequencer_set_gamma_ramp_adjustment(
++ struct hw_sequencer *hws,
++ const struct display_path *display_path,
++ struct hw_adjustment_gamma_ramp *adjusment);
++
++enum hwss_result dal_hw_sequencer_set_color_control_adjustment(
++ struct hw_sequencer *hws,
++ struct controller *crtc,
++ struct hw_adjustment_color_control *adjustment);
++
++enum hwss_result dal_hw_sequencer_set_vertical_sync_adjustment(
++ struct hw_sequencer *hws,
++ struct display_path *display_path,
++ struct hw_adjustment_value *adjustment);
++
++enum hwss_result dal_hw_sequencer_set_horizontal_sync_adjustment(
++ struct hw_sequencer *hws,
++ struct display_path *display_path,
++ struct hw_adjustment_value *adjustment);
++
++enum hwss_result dal_hw_sequencer_set_composite_sync_adjustment(
++ struct hw_sequencer *hws,
++ struct display_path *display_path,
++ struct hw_adjustment_value *adjustment);
++
++enum hwss_result dal_hw_sequencer_enable_sync_output(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++enum hwss_result dal_hw_sequencer_disable_sync_output(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++enum hwss_result dal_hw_sequencer_set_backlight_adjustment(
++ struct hw_sequencer *hws,
++ struct display_path *display_path,
++ struct hw_adjustment_value *adjustment);
++
++void dal_hw_sequencer_disable_memory_requests(
++ struct hw_sequencer *hws,
++ const struct hw_path_mode *path_mode);
++
++enum hwss_result dal_hw_sequencer_enable_link(
++ struct hw_sequencer *hws,
++ const struct enable_link_param *in);
++
++void dal_hw_sequencer_disable_link(
++ struct hw_sequencer *hws,
++ const struct enable_link_param *in);
++
++void dal_hw_sequencer_enable_stream(
++ struct hw_sequencer *hws,
++ const struct enable_stream_param *in);
++
++void dal_hw_sequencer_disable_stream(
++ struct hw_sequencer *hws,
++ const struct enable_stream_param *in);
++
++void dal_hw_sequencer_blank_stream(
++ struct hw_sequencer *hws,
++ const struct blank_stream_param *in);
++
++void dal_hw_sequencer_unblank_stream(
++ struct hw_sequencer *hws,
++ const struct blank_stream_param *in);
++
++enum hwss_result dal_hw_sequencer_set_clocks_and_clock_state(
++ struct hw_sequencer *hws,
++ struct hw_global_objects *g_obj,
++ const struct minimum_clocks_calculation_result *min_clk_in,
++ enum clocks_state required_clocks_state);
++
++enum hwss_result dal_hw_sequencer_set_mode(
++ struct hw_sequencer *hws,
++ struct hw_path_mode_set *path_set);
++
++enum signal_type dal_hw_sequencer_detect_sink(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++enum signal_type dal_hw_sequencer_detect_load(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++bool dal_hw_sequencer_is_sink_present(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++void dal_hw_sequencer_psr_setup(
++ struct hw_sequencer *hws,
++ const struct hw_path_mode *path_mode,
++ const struct psr_caps *psr_caps);
++
++void dal_hw_sequencer_psr_enable(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++void dal_hw_sequencer_psr_disable(
++ struct hw_sequencer *hws,
++ struct display_path *display_path);
++
++void dal_hw_sequencer_program_drr(
++ struct hw_sequencer *hws,
++ const struct hw_path_mode *path_mode);
++
++enum hwss_result dal_hw_sequencer_set_safe_displaymark(
++ struct hw_sequencer *hws,
++ struct hw_path_mode_set *path_set);
++
++enum hwss_result dal_hw_sequencer_set_displaymark(
++ struct hw_sequencer *hws,
++ struct hw_path_mode_set *path_set);
++
++void dal_hw_sequencer_destroy(struct hw_sequencer **hws);
++
++struct hw_sequencer *dal_hw_sequencer_create(
++ struct hws_init_data *hws_init_data);
++
++enum hwss_result dal_hw_sequencer_set_overscan_adj(
++ struct hw_sequencer *hws,
++ struct hw_path_mode_set *set,
++ struct hw_underscan_adjustment_data *hw_underscan);
++
++bool dal_hw_sequencer_enable_line_buffer_power_gating(
++ struct line_buffer *lb,
++ enum controller_id id,
++ enum pixel_type pixel_type,
++ uint32_t src_pixel_width,
++ uint32_t dst_pixel_width,
++ struct scaling_taps *taps,
++ enum lb_pixel_depth lb_depth,
++ uint32_t src_height,
++ uint32_t dst_height,
++ bool interlaced);
++
++void dal_hw_sequencer_build_scaler_parameter(
++ const struct hw_path_mode *path_mode,
++ const struct scaling_taps *taps,
++ bool build_timing_required,
++ struct scaler_data *scaler_data);
++
++void dal_hw_sequencer_update_info_frame(
++ const struct hw_path_mode *hw_path_mode);
++
++enum hwss_result dal_hw_sequencer_set_bit_depth_reduction_adj(
++ struct hw_sequencer *hws,
++ struct display_path *disp_path,
++ union hw_adjustment_bit_depth_reduction *bit_depth);
++
++bool dal_hw_sequencer_is_support_custom_gamut_adj(
++ struct hw_sequencer *hws,
++ struct display_path *disp_path,
++ enum hw_surface_type surface_type);
++
++enum hwss_result dal_hw_sequencer_get_hw_color_adj_range(
++ struct hw_sequencer *hws,
++ struct display_path *disp_path,
++ struct hw_color_control_range *hw_color_range);
++
++bool dal_hw_sequencer_is_support_custom_gamma_coefficients(
++ struct hw_sequencer *hws,
++ struct display_path *disp_path,
++ enum hw_surface_type surface_type);
++
++enum hwss_result dal_hw_sequencer_build_csc_adjust(
++ struct hw_sequencer *hws,
++ struct hw_adjustment_color_control *color_control,
++ struct grph_csc_adjustment *adjust);
++
++void dal_hw_sequencer_build_gamma_ramp_adj_params(
++ const struct hw_adjustment_gamma_ramp *adjusment,
++ struct gamma_parameters *gamma_param,
++ struct gamma_ramp *ramp);
++
++void translate_from_hw_to_controller_regamma(
++ const struct hw_regamma_lut *hw_regamma,
++ struct regamma_lut *regamma);
++
++void dal_hw_sequencer_enable_wireless_idle_detection(
++ struct hw_sequencer *hws,
++ bool enable);
++
++/* Cursor interface */
++enum hwss_result dal_hw_sequencer_set_cursor_position(
++ struct hw_sequencer *hws,
++ struct display_path *dp,
++ const struct dc_cursor_position *position);
++
++enum hwss_result dal_hw_sequencer_set_cursor_attributes(
++ struct hw_sequencer *hws,
++ struct display_path *dp,
++ const struct dc_cursor_attributes *attributes);
++
++/* Underlay/MPO interface */
++enum hwss_result dal_hw_sequencer_set_plane_config(
++ struct hw_sequencer *hws,
++ struct hw_path_mode_set *path_set,
++ uint32_t display_index);
++
++bool dal_hw_sequencer_update_plane_address(
++ struct hw_sequencer *hws,
++ struct display_path *dp,
++ uint32_t num_planes,
++ struct plane_addr_flip_info *info);
++
++void dal_hw_sequencer_prepare_to_release_planes(
++ struct hw_sequencer *hws,
++ struct hw_path_mode_set *path_set,
++ uint32_t display_index);
++
++#endif /* __DAL_HW_SEQUENCER_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/hw_sequencer_types.h b/drivers/gpu/drm/amd/dal/include/hw_sequencer_types.h
+new file mode 100644
+index 0000000..d5d7059
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/hw_sequencer_types.h
+@@ -0,0 +1,305 @@
++/*
++ * 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_HW_SEQUENCER_TYPES_H__
++#define __DAL_HW_SEQUENCER_TYPES_H__
++
++#include "signal_types.h"
++#include "grph_object_defs.h"
++#include "link_service_types.h"
++#include "plane_types.h"
++
++struct color_quality {
++ uint32_t bpp_graphics;
++ uint32_t bpp_backend_video;
++};
++
++enum {
++ HW_MAX_NUM_VIEWPORTS = 2,
++ HW_CURRENT_PIPE_INDEX = 0,
++ HW_OTHER_PIPE_INDEX = 1
++};
++
++struct hw_view_port_adjustment {
++ int32_t start_adjustment;
++ int32_t width;
++
++ enum controller_id controller_id;
++};
++
++struct hw_view_port_adjustments {
++ uint32_t view_ports_num;
++ struct hw_view_port_adjustment adjustments[HW_MAX_NUM_VIEWPORTS];
++};
++
++/* Timing standard */
++enum hw_timing_standard {
++ HW_TIMING_STANDARD_UNDEFINED,
++ HW_TIMING_STANDARD_DMT,
++ HW_TIMING_STANDARD_GTF,
++ HW_TIMING_STANDARD_CVT,
++ HW_TIMING_STANDARD_CVT_RB,
++ HW_TIMING_STANDARD_CEA770,
++ HW_TIMING_STANDARD_CEA861,
++ HW_TIMING_STANDARD_HDMI,
++ HW_TIMING_STANDARD_TV_NTSC,
++ HW_TIMING_STANDARD_TV_NTSC_J,
++ HW_TIMING_STANDARD_TV_PAL,
++ HW_TIMING_STANDARD_TV_PAL_M,
++ HW_TIMING_STANDARD_TV_PAL_CN,
++ HW_TIMING_STANDARD_TV_SECAM,
++ /* for explicit timings from VBIOS, EDID etc. */
++ HW_TIMING_STANDARD_EXPLICIT
++};
++
++/* identical to struct crtc_ranged_timing_control
++ * defined in controller\timing_generator_types.h */
++struct hw_ranged_timing_control {
++ /* set to 1 to force dynamic counter V_COUNT
++ * to lock to constant rate counter V_COUNT_NOM
++ * on page flip event in dynamic refresh mode
++ * when switching from a low refresh rate to nominal refresh rate */
++ bool force_lock_on_event;
++ /* set to 1 to force CRTC2 (slave) to lock to CRTC1 (master) VSync
++ * in order to overlap their blank regions for MC clock changes */
++ bool lock_to_master_vsync;
++
++ /* set to 1 to program Static Screen Detection Masks
++ * without enabling dynamic refresh rate */
++ bool program_static_screen_mask;
++ /* set to 1 to program Dynamic Refresh Rate */
++ bool program_dynamic_refresh_rate;
++ /* set to 1 to force disable Dynamic Refresh Rate */
++ bool force_disable_drr;
++
++ /* event mask to enable/disable various trigger sources
++ * for static screen detection */
++ struct static_screen_events event_mask;
++
++ /* Number of consecutive static screen frames before static state is
++ * asserted. */
++ uint32_t static_frame_count;
++};
++
++/* define the structure of Dynamic Refresh Mode */
++struct hw_ranged_timing {
++ /* defines the minimum possible vertical dimension of display timing
++ * for CRTC as supported by the panel */
++ uint32_t vertical_total_min;
++ /* defines the maximum possible vertical dimension of display timing
++ * for CRTC as supported by the panel */
++ uint32_t vertical_total_max;
++
++ struct hw_ranged_timing_control control;
++};
++
++/* CRTC timing structure */
++struct hw_crtc_timing {
++ uint32_t h_total;
++ uint32_t h_addressable;
++ uint32_t h_overscan_left;
++ uint32_t h_overscan_right;
++ uint32_t h_sync_start;
++ uint32_t h_sync_width;
++
++ uint32_t v_total;
++ uint32_t v_addressable;
++ uint32_t v_overscan_top;
++ uint32_t v_overscan_bottom;
++ uint32_t v_sync_start;
++ uint32_t v_sync_width;
++
++ struct hw_ranged_timing ranged_timing;
++
++ /* in KHz */
++ uint32_t pixel_clock;
++
++ enum hw_timing_standard timing_standard;
++ enum dc_color_depth color_depth;
++ enum dc_pixel_encoding pixel_encoding;
++
++ struct {
++ uint32_t INTERLACED:1;
++ uint32_t DOUBLESCAN:1;
++ uint32_t PIXEL_REPETITION:4; /* 1...10 */
++ uint32_t HSYNC_POSITIVE_POLARITY:1;
++ uint32_t VSYNC_POSITIVE_POLARITY:1;
++ /* frame should be packed for 3D
++ * (currently this refers to HDMI 1.4a FramePacking format */
++ uint32_t HORZ_COUNT_BY_TWO:1;
++ uint32_t PACK_3D_FRAME:1;
++ /* 0 - left eye polarity, 1 - right eye polarity */
++ uint32_t RIGHT_EYE_3D_POLARITY:1;
++ /* DVI-DL High-Color mode */
++ uint32_t HIGH_COLOR_DL_MODE:1;
++ uint32_t Y_ONLY:1;
++ /* HDMI 2.0 - Support scrambling for TMDS character
++ * rates less than or equal to 340Mcsc */
++ uint32_t LTE_340MCSC_SCRAMBLE:1;
++ } flags;
++};
++
++struct hw_scaling_info {
++ struct view src;
++ struct view dst;
++ enum signal_type signal;
++};
++
++enum hw_color_space {
++ HW_COLOR_SPACE_UNKNOWN = 0,
++ HW_COLOR_SPACE_SRGB_FULL_RANGE,
++ HW_COLOR_SPACE_SRGB_LIMITED_RANGE,
++ HW_COLOR_SPACE_YPBPR601,
++ HW_COLOR_SPACE_YPBPR709,
++ HW_COLOR_SPACE_YCBCR601,
++ HW_COLOR_SPACE_YCBCR709,
++ HW_COLOR_SPACE_YCBCR601_YONLY,
++ HW_COLOR_SPACE_YCBCR709_YONLY,
++ HW_COLOR_SPACE_NMVPU_SUPERAA,
++};
++
++enum hw_overlay_color_space {
++ HW_OVERLAY_COLOR_SPACE_UNKNOWN,
++ HW_OVERLAY_COLOR_SPACE_BT709,
++ HW_OVERLAY_COLOR_SPACE_BT601,
++ HW_OVERLAY_COLOR_SPACE_SMPTE240,
++ HW_OVERLAY_COLOR_SPACE_RGB
++};
++
++enum hw_overlay_backend_bpp {
++ HW_OVERLAY_BACKEND_BPP_UNKNOWN,
++ HW_OVERLAY_BACKEND_BPP32_FULL_BANDWIDTH,
++ HW_OVERLAY_BACKEND_BPP16_FULL_BANDWIDTH,
++ HW_OVERLAY_BACKEND_BPP32_HALF_BANDWIDTH,
++};
++enum hw_overlay_format {
++ HW_OVERLAY_FORMAT_UNKNOWN,
++ HW_OVERLAY_FORMAT_YUY2,
++ HW_OVERLAY_FORMAT_UYVY,
++ HW_OVERLAY_FORMAT_RGB565,
++ HW_OVERLAY_FORMAT_RGB555,
++ HW_OVERLAY_FORMAT_RGB32,
++ HW_OVERLAY_FORMAT_YUV444,
++ HW_OVERLAY_FORMAT_RGB32_2101010
++};
++
++enum hw_scale_options {
++ HW_SCALE_OPTION_UNKNOWN,
++ HW_SCALE_OPTION_OVERSCAN, /* multimedia pass through mode */
++ HW_SCALE_OPTION_UNDERSCAN
++};
++
++enum hw_stereo_format {
++ HW_STEREO_FORMAT_NONE = 0,
++ HW_STEREO_FORMAT_SIDE_BY_SIDE = 1,
++ HW_STEREO_FORMAT_TOP_AND_BOTTOM = 2,
++ HW_STEREO_FORMAT_FRAME_ALTERNATE = 3,
++ HW_STEREO_FORMAT_ROW_INTERLEAVED = 5,
++ HW_STEREO_FORMAT_COLUMN_INTERLEAVED = 6,
++ HW_STEREO_FORMAT_CHECKER_BOARD = 7 /* the same as pixel interleave */
++};
++
++enum hw_dithering_options {
++ HW_DITHERING_OPTION_UNKNOWN,
++ HW_DITHERING_OPTION_SKIP_PROGRAMMING,
++ HW_DITHERING_OPTION_ENABLE,
++ HW_DITHERING_OPTION_DISABLE
++};
++
++struct hw_stereo_mixer_params {
++ bool sub_sampling;
++ bool single_pipe;
++};
++
++
++
++struct hw_action_flags {
++ uint32_t RESYNC_PATH:1;
++ uint32_t TIMING_CHANGED:1;
++ uint32_t PIXEL_ENCODING_CHANGED:1;
++ uint32_t GAMUT_CHANGED:1;
++ uint32_t TURN_OFF_VCC:1;
++};
++
++enum hw_sync_request {
++ HW_SYNC_REQUEST_NONE = 0,
++ HW_SYNC_REQUEST_SET_INTERPATH,
++ HW_SYNC_REQUEST_SET_GL_SYNC_GENLOCK,
++ HW_SYNC_REQUEST_SET_GL_SYNC_FREE_RUN,
++ HW_SYNC_REQUEST_SET_GL_SYNC_SHADOW,
++ HW_SYNC_REQUEST_RESET_GLSYNC,
++ HW_SYNC_REQUEST_RESYNC_GLSYNC,
++ HW_SYNC_REQUEST_SET_STEREO3D
++};
++
++struct hw_sync_info {
++ enum hw_sync_request sync_request;
++ uint32_t target_pixel_clock; /* in KHz */
++ enum sync_source sync_source;
++};
++
++/* TODO hw_info_frame and hw_info_packet structures are same as in encoder
++ * merge it*/
++struct hw_info_packet {
++ bool valid;
++ uint8_t hb0;
++ uint8_t hb1;
++ uint8_t hb2;
++ uint8_t hb3;
++ uint8_t sb[28];
++};
++
++struct hw_info_frame {
++ /* Auxiliary Video Information */
++ struct hw_info_packet avi_info_packet;
++ struct hw_info_packet gamut_packet;
++ struct hw_info_packet vendor_info_packet;
++ /* Source Product Description */
++ struct hw_info_packet spd_packet;
++ /* Video Stream Configuration */
++ struct hw_info_packet vsc_packet;
++};
++
++
++enum channel_command_type {
++ CHANNEL_COMMAND_I2C,
++ CHANNEL_COMMAND_I2C_OVER_AUX,
++ CHANNEL_COMMAND_AUX
++};
++
++
++/* maximum TMDS transmitter pixel clock is 165 MHz. So it is KHz */
++#define TMDS_MAX_PIXEL_CLOCK_IN_KHZ 165000
++#define NATIVE_HDMI_MAX_PIXEL_CLOCK_IN_KHZ 297000
++
++struct hw_adjustment_range {
++ int32_t hw_default;
++ int32_t min;
++ int32_t max;
++ int32_t step;
++ uint32_t divider; /* (actually HW range is min/divider; divider !=0) */
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/i2caux_interface.h b/drivers/gpu/drm/amd/dal/include/i2caux_interface.h
+new file mode 100644
+index 0000000..b961d24
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/i2caux_interface.h
+@@ -0,0 +1,127 @@
++/*
++ * 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_I2CAUX_INTERFACE_H__
++#define __DAL_I2CAUX_INTERFACE_H__
++
++#include "ddc_interface.h"
++#include "adapter_service_interface.h"
++
++struct i2c_payload {
++ bool write;
++ uint8_t address;
++ uint8_t length;
++ uint8_t *data;
++};
++
++enum i2c_command_engine {
++ I2C_COMMAND_ENGINE_DEFAULT,
++ I2C_COMMAND_ENGINE_SW,
++ I2C_COMMAND_ENGINE_HW
++};
++
++struct i2c_command {
++ struct i2c_payload *payloads;
++ uint8_t number_of_payloads;
++
++ enum i2c_command_engine engine;
++
++ /* expressed in KHz
++ * zero means "use default value" */
++ uint32_t speed;
++};
++
++#define DEFAULT_AUX_MAX_DATA_SIZE 16
++#define AUX_MAX_DEFER_WRITE_RETRY 20
++
++struct aux_payload {
++ /* set following flag to read/write I2C data,
++ * reset it to read/write DPCD data */
++ bool i2c_over_aux;
++ /* set following flag to write data,
++ * reset it to read data */
++ bool write;
++ uint32_t address;
++ uint8_t length;
++ uint8_t *data;
++};
++
++struct aux_command {
++ struct aux_payload *payloads;
++ uint8_t number_of_payloads;
++
++ /* expressed in milliseconds
++ * zero means "use default value" */
++ uint32_t defer_delay;
++
++ /* zero means "use default value" */
++ uint32_t max_defer_write_retry;
++};
++
++union aux_config {
++ struct {
++ uint32_t ALLOW_AUX_WHEN_HPD_LOW:1;
++ } bits;
++ uint32_t raw;
++};
++
++struct i2caux;
++
++struct i2caux *dal_i2caux_create(
++ struct adapter_service *as,
++ struct dc_context *ctx);
++
++bool dal_i2caux_submit_i2c_command(
++ struct i2caux *i2caux,
++ struct ddc *ddc,
++ struct i2c_command *cmd);
++
++bool dal_i2caux_submit_aux_command(
++ struct i2caux *i2caux,
++ struct ddc *ddc,
++ struct aux_command *cmd);
++
++void dal_i2caux_keep_engine_power_up(
++ struct i2caux *i2caux,
++ struct ddc *ddc,
++ bool keep_power_up);
++
++bool dal_i2caux_start_gtc_sync(
++ struct i2caux *i2caux,
++ struct ddc *ddc);
++
++bool dal_i2caux_stop_gtc_sync(
++ struct i2caux *i2caux,
++ struct ddc *ddc);
++
++void dal_i2caux_configure_aux(
++ struct i2caux *i2caux,
++ struct ddc *ddc,
++ union aux_config cfg);
++
++void dal_i2caux_destroy(
++ struct i2caux **ptr);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/irq_interface.h b/drivers/gpu/drm/amd/dal/include/irq_interface.h
+new file mode 100644
+index 0000000..0faa48f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/irq_interface.h
+@@ -0,0 +1,53 @@
++/*
++ * 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_IRQ_INTERFACE_H__
++#define __DAL_IRQ_INTERFACE_H__
++
++#include "gpio_types.h"
++
++struct irq;
++
++enum gpio_result dal_irq_open(
++ struct irq *irq);
++
++enum gpio_result dal_irq_get_value(
++ const struct irq *irq,
++ uint32_t *value);
++
++enum dc_irq_source dal_irq_get_source(
++ const struct irq *irq);
++
++enum dc_irq_source dal_irq_get_rx_source(
++ const struct irq *irq);
++
++enum gpio_result dal_irq_setup_hpd_filter(
++ struct irq *irq,
++ struct gpio_hpd_config *config);
++
++void dal_irq_close(
++ struct irq *irq);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/irq_service_interface.h b/drivers/gpu/drm/amd/dal/include/irq_service_interface.h
+new file mode 100644
+index 0000000..7ae4aeb
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/irq_service_interface.h
+@@ -0,0 +1,55 @@
++/*
++ * 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_IRQ_SERVICE_INTERFACE_H__
++#define __DAL_IRQ_SERVICE_INTERFACE_H__
++
++#include "include/adapter_service_types.h"
++
++struct irq_service_init_data {
++ struct dc_context *ctx;
++};
++
++struct irq_service *dal_irq_service_create(
++ enum dce_version version,
++ struct irq_service_init_data *init_data);
++
++void dal_irq_service_destroy(struct irq_service **irq_service);
++
++bool dal_irq_service_set(
++ struct irq_service *irq_service,
++ enum dc_irq_source source,
++ bool enable);
++
++bool dal_irq_service_ack(
++ struct irq_service *irq_service,
++ enum dc_irq_source source);
++
++enum dc_irq_source dal_irq_service_to_irq_source(
++ struct irq_service *irq_service,
++ uint32_t src_id,
++ uint32_t ext_id);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/isr_config_types.h b/drivers/gpu/drm/amd/dal/include/isr_config_types.h
+new file mode 100644
+index 0000000..2e822f0
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/isr_config_types.h
+@@ -0,0 +1,157 @@
++/*
++ * 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_ISR_TYPES_H__
++#define __DAL_ISR_TYPES_H__
++
++#include "grph_object_id.h"
++#include "dc_types.h"
++
++struct plane_config;
++enum {
++ /*move to common*/
++ MAX_COFUNC_PATH_COMMON = 6,
++ /*CZ worst case*/
++ MAX_NUM_PLANES = 4
++};
++
++enum plane_type {
++ PLANE_TYPE_GRPH = 0,
++ PLANE_TYPE_VIDEO
++};
++
++struct plane_id {
++ enum plane_type select;
++ enum controller_id controller_id;
++};
++
++union display_plane_mask {
++ struct {
++ uint32_t CLONE_PRIMARY_CONTROLLER_ID_SET:1;
++ uint32_t INTERLEAVED_CONTROLLER_ID_SET:1;
++ uint32_t RESERVED:30;
++ } bits;
++ uint32_t value;
++};
++
++struct display_plane_format {
++ /* always valid */
++ union display_plane_mask mask;
++ /* always valid */
++ uint32_t display_index;
++ /* always valid */
++ enum dc_timing_3d_format format;
++ /* always valid */
++ enum controller_id controller_id;
++ /* valid only if CLONE_PRIMARY_CONTROLLER_ID_SET on */
++ enum controller_id clone_primary_controller_id;
++ /* valid only if stereo interleave mode is on */
++ enum controller_id interleave_controller_id;
++ /* valid only if crtc stereo is on */
++ uint32_t right_eye_3d_polarity:1;
++};
++
++struct display_plane_set {
++ struct display_plane_format
++ set_mode_formats[MAX_COFUNC_PATH_COMMON];
++ uint32_t reset_mode_index[
++ MAX_COFUNC_PATH_COMMON];
++ uint32_t num_set_mode_formats;
++ uint32_t num_reset_mode_index;
++};
++
++enum layers_setup {
++ LAYERS_SETUP_NOTHING = 0,
++ LAYERS_SETUP_SET,
++ LAYERS_SETUP_FREE
++};
++
++union plane_cfg_internal_flags {
++ struct {
++ uint32_t PLANE_OWNS_CRTC:1;
++ uint32_t RESERVED:31;
++ } bits;
++ uint32_t value;
++};
++
++
++struct plane_cfg_internal {
++ const struct plane_config *config;
++ enum layers_setup setup;
++ union plane_cfg_internal_flags flags;
++};
++
++enum lock_type {
++ LOCK_TYPE_GRPH = 0,
++ LOCK_TYPE_SURF,
++ LOCK_TYPE_SCL,
++ LOCK_TYPE_BLND,
++ /* lock the given pipe with options above */
++ LOCK_TYPE_THIS
++};
++
++enum alpha_mode {
++ ALPHA_MODE_PIXEL = 0,
++ ALPHA_MODE_PIXEL_AND_GLOBAL = 1,
++ ALPHA_MODE_GLOBAL = 2
++};
++
++union alpha_mode_cfg_flag {
++ struct {
++ uint32_t MODE_IS_SET:1;
++ uint32_t MODE_MULTIPLIED_IS_SET:1;
++ uint32_t GLOBAL_ALPHA_IS_SET:1;
++ uint32_t GLOBAL_ALPHA_GAIN_IS_SET:1;
++
++ uint32_t MULTIPLIED_MODE:1;
++ uint32_t GLOBAL_ALPHA:8;
++ /* total 21 bits! */
++ uint32_t GLOBAL_ALPHA_GAIN:8;
++ } bits;
++ uint32_t value;
++};
++
++struct alpha_mode_cfg {
++ union alpha_mode_cfg_flag flags;
++ enum alpha_mode mode;
++};
++
++union pending_cfg_changes {
++ struct {
++ uint32_t SCL_UNLOCK_REQUIRED:1;
++ uint32_t BLND_UNLOCK_REQUIRED:1;
++ uint32_t INPUT_CSC_SWITCH_REQUIRED:1;
++ uint32_t OUTPUT_CSC_SWITCH_REQUIRED:1;
++ } bits;
++ uint32_t value;
++};
++
++struct pending_plane_changes {
++ union pending_cfg_changes changes;
++ struct plane_id id;
++};
++
++
++#endif /* __DAL_ISR_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/link_encoder_types.h b/drivers/gpu/drm/amd/dal/include/link_encoder_types.h
+new file mode 100644
+index 0000000..2a59902
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/link_encoder_types.h
+@@ -0,0 +1,32 @@
++/*
++ * link_encoder_types.h
++ *
++ * Created on: Oct 6, 2015
++ * Author: yonsun
++ */
++
++#ifndef DRIVERS_GPU_DRM_AMD_DAL_DEV_INCLUDE_LINK_ENCODER_TYPES_H_
++#define DRIVERS_GPU_DRM_AMD_DAL_DEV_INCLUDE_LINK_ENCODER_TYPES_H_
++
++#include "encoder_interface.h"
++
++struct link_enc_status {
++ int dummy; /*TODO*/
++};
++struct link_encoder {
++ struct adapter_service *adapter_service;
++ int32_t be_engine_offset;
++ int32_t aux_channel_offset;
++ int32_t transmitter_offset;
++ struct dc_context *ctx;
++ struct graphics_object_id id;
++ struct graphics_object_id connector;
++ uint32_t input_signals;
++ uint32_t output_signals;
++ enum engine_id preferred_engine;
++ struct encoder_feature_support features;
++ enum transmitter transmitter;
++ enum hpd_source_id hpd_source;
++};
++
++#endif /* DRIVERS_GPU_DRM_AMD_DAL_DEV_INCLUDE_LINK_ENCODER_TYPES_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/include/link_service_interface.h b/drivers/gpu/drm/amd/dal/include/link_service_interface.h
+new file mode 100644
+index 0000000..2ac9311
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/link_service_interface.h
+@@ -0,0 +1,202 @@
++/*
++ * 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_LINK_SERVICE_INTERFACE_H__
++#define __DAL_LINK_SERVICE_INTERFACE_H__
++
++#include "include/link_service_types.h"
++
++/* forward declaration */
++struct link_service;
++struct hw_crtc_timing;
++struct hw_path_mode;
++struct display_path;
++struct hw_path_mode_set;
++struct link_training_preference;
++enum ddc_result;
++
++struct link_service *dal_link_service_create(
++ struct link_service_init_data *init_data);
++
++void dal_link_service_destroy(
++ struct link_service **ls);
++
++enum link_service_type dal_ls_get_link_service_type(
++ struct link_service *link_service);
++
++bool dal_ls_validate_mode_timing(
++ struct link_service *ls,
++ uint32_t display_index,
++ const struct hw_crtc_timing *timing,
++ struct link_validation_flags flags);
++
++bool dal_ls_get_mst_sink_info(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct mst_sink_info *sink_info);
++
++bool dal_ls_get_gtc_sync_status(
++ struct link_service *ls);
++
++bool dal_ls_enable_stream(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct hw_path_mode *path_mode);
++
++bool dal_ls_disable_stream(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct hw_path_mode *poath_mode);
++
++bool dal_ls_optimized_enable_stream(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct display_path *display_path);
++
++void dal_ls_update_stream_features(
++ struct link_service *ls,
++ const struct hw_path_mode *path_mode);
++
++bool dal_ls_blank_stream(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct hw_path_mode *path_mode);
++
++bool dal_ls_unblank_stream(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct hw_path_mode *path_mode);
++
++bool dal_ls_pre_mode_change(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct hw_path_mode *path_mode);
++
++bool dal_ls_post_mode_change(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct hw_path_mode *path_mode);
++
++bool dal_ls_power_on_stream(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct hw_path_mode *path_mode);
++
++bool dal_ls_power_off_stream(
++ struct link_service *ls,
++ uint32_t display_index,
++ struct hw_path_mode *path_mode);
++
++void dal_ls_retrain_link(
++ struct link_service *ls,
++ struct hw_path_mode_set *path_set);
++
++bool dal_ls_get_current_link_setting(
++ struct link_service *ls,
++ struct link_settings *link_settings);
++
++void dal_ls_connect_link(
++ struct link_service *ls,
++ const struct display_path *display_path,
++ bool initial_detection);
++
++void dal_ls_disconnect_link(
++ struct link_service *ls);
++
++bool dal_ls_is_mst_network_present(
++ struct link_service *ls);
++
++void dal_ls_invalidate_down_stream_devices(
++ struct link_service *ls);
++
++bool dal_ls_are_mst_displays_cofunctional(
++ struct link_service *ls,
++ const uint32_t *array_display_index,
++ uint32_t len);
++
++bool dal_ls_is_sink_present_at_display_index(
++ struct link_service *ls,
++ uint32_t display_index);
++
++struct ddc_service *dal_ls_obtain_mst_ddc_service(
++ struct link_service *ls,
++ uint32_t display_index);
++
++void dal_ls_release_mst_ddc_service(
++ struct link_service *ls,
++ struct ddc_service *ddc_service);
++
++void dal_ls_release_hw(
++ struct link_service *ls);
++
++bool dal_ls_associate_link(
++ struct link_service *ls,
++ uint32_t display_index,
++ uint32_t link_index,
++ bool is_internal_link);
++
++bool dal_dpsst_ls_set_overridden_trained_link_settings(
++ struct link_service *ls,
++ const struct link_settings *link_settings);
++
++void dal_dpsst_ls_set_link_training_preference(
++ struct link_service *ls,
++ const struct link_training_preference *ltp);
++
++struct link_training_preference
++ dal_dpsst_ls_get_link_training_preference(
++ struct link_service *ls);
++
++bool dal_ls_should_send_notification(
++ struct link_service *ls);
++
++uint32_t dal_ls_get_notification_display_index(
++ struct link_service *ls);
++
++enum ddc_result dal_dpsst_ls_read_dpcd_data(
++ struct link_service *ls,
++ uint32_t address,
++ uint8_t *data,
++ uint32_t size);
++
++enum ddc_result dal_dpsst_ls_write_dpcd_data(
++ struct link_service *ls,
++ uint32_t address,
++ const uint8_t *data,
++ uint32_t size);
++
++bool dal_ls_is_link_psr_supported(struct link_service *ls);
++
++bool dal_ls_is_stream_drr_supported(struct link_service *ls);
++
++void dal_ls_set_link_psr_capabilities(
++ struct link_service *ls,
++ struct psr_caps *psr_caps);
++
++void dal_ls_get_link_psr_capabilities(
++ struct link_service *ls,
++ struct psr_caps *psr_caps);
++
++#endif /* __DAL_LINK_SERVICE_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/link_service_types.h b/drivers/gpu/drm/amd/dal/include/link_service_types.h
+new file mode 100644
+index 0000000..0df5687
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/link_service_types.h
+@@ -0,0 +1,428 @@
++/*
++ * 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_LINK_SERVICE_TYPES_H__
++#define __DAL_LINK_SERVICE_TYPES_H__
++
++#include "dal_services_types.h"
++
++#include "grph_object_id.h"
++#include "dpcd_defs.h"
++#include "dal_types.h"
++#include "irq_types.h"
++
++/*struct mst_mgr_callback_object;*/
++struct ddc;
++struct irq_manager;
++
++enum link_service_type {
++ LINK_SERVICE_TYPE_LEGACY = 0,
++ LINK_SERVICE_TYPE_DP_SST,
++ LINK_SERVICE_TYPE_DP_MST,
++ LINK_SERVICE_TYPE_MAX
++};
++
++struct link_validation_flags {
++ uint32_t DYNAMIC_VALIDATION:1;
++ uint32_t CANDIDATE_TIMING:1;
++ uint32_t START_OF_VALIDATION:1;
++};
++
++/* Post Cursor 2 is optional for transmitter
++ * and it applies only to the main link operating at HBR2
++ */
++enum post_cursor2 {
++ POST_CURSOR2_DISABLED = 0, /* direct HW translation! */
++ POST_CURSOR2_LEVEL1,
++ POST_CURSOR2_LEVEL2,
++ POST_CURSOR2_LEVEL3,
++ POST_CURSOR2_MAX_LEVEL = POST_CURSOR2_LEVEL3,
++};
++
++enum voltage_swing {
++ VOLTAGE_SWING_LEVEL0 = 0, /* direct HW translation! */
++ VOLTAGE_SWING_LEVEL1,
++ VOLTAGE_SWING_LEVEL2,
++ VOLTAGE_SWING_LEVEL3,
++ VOLTAGE_SWING_MAX_LEVEL = VOLTAGE_SWING_LEVEL3
++};
++
++enum pre_emphasis {
++ PRE_EMPHASIS_DISABLED = 0, /* direct HW translation! */
++ PRE_EMPHASIS_LEVEL1,
++ PRE_EMPHASIS_LEVEL2,
++ PRE_EMPHASIS_LEVEL3,
++ PRE_EMPHASIS_MAX_LEVEL = PRE_EMPHASIS_LEVEL3
++};
++
++enum dpcd_value_mask {
++ DPCD_VALUE_MASK_MAX_LANE_COUNT_LANE_COUNT = 0x1F,
++ DPCD_VALUE_MASK_MAX_LANE_COUNT_TPS3_SUPPORTED = 0x40,
++ DPCD_VALUE_MASK_MAX_LANE_COUNT_ENHANCED_FRAME_EN = 0x80,
++ DPCD_VALUE_MASK_MAX_DOWNSPREAD = 0x01,
++ DPCD_VALUE_MASK_LANE_ALIGN_STATUS_INTERLANE_ALIGN_DONE = 0x01
++};
++
++enum dp_power_state {
++ DP_POWER_STATE_D0 = 1,
++ DP_POWER_STATE_D3
++};
++
++enum dpcd_downstream_port_types {
++ DPCD_DOWNSTREAM_DP,
++ DPCD_DOWNSTREAM_VGA,
++ DPCD_DOWNSTREAM_DVI_HDMI,
++ /* has no EDID (TV, CV) */
++ DPCD_DOWNSTREAM_NON_DDC
++};
++
++enum edp_revision {
++ /* eDP version 1.1 or lower */
++ EDP_REVISION_11 = 0x00,
++ /* eDP version 1.2 */
++ EDP_REVISION_12 = 0x01,
++ /* eDP version 1.3 */
++ EDP_REVISION_13 = 0x02
++};
++
++enum lane_count {
++ LANE_COUNT_UNKNOWN = 0,
++ LANE_COUNT_ONE = 1,
++ LANE_COUNT_TWO = 2,
++ LANE_COUNT_FOUR = 4,
++ LANE_COUNT_EIGHT = 8,
++ LANE_COUNT_DP_MAX = LANE_COUNT_FOUR
++};
++
++/* This is actually a reference clock (27MHz) multiplier
++ * 162MBps bandwidth for 1.62GHz like rate,
++ * 270MBps for 2.70GHz,
++ * 324MBps for 3.24Ghz,
++ * 540MBps for 5.40GHz
++ */
++enum link_rate {
++ LINK_RATE_UNKNOWN = 0,
++ LINK_RATE_LOW = 0x06,
++ LINK_RATE_HIGH = 0x0A,
++ LINK_RATE_RBR2 = 0x0C,
++ LINK_RATE_HIGH2 = 0x14
++};
++
++enum {
++ LINK_RATE_REF_FREQ_IN_KHZ = 27000 /*27MHz*/
++};
++
++enum link_spread {
++ LINK_SPREAD_DISABLED = 0x00,
++ /* 0.5 % downspread 30 kHz */
++ LINK_SPREAD_05_DOWNSPREAD_30KHZ = 0x10,
++ /* 0.5 % downspread 33 kHz */
++ LINK_SPREAD_05_DOWNSPREAD_33KHZ = 0x11
++};
++
++/* DPCD_ADDR_DOWNSTREAM_PORT_PRESENT register value */
++union dpcd_downstream_port {
++ struct {
++#if defined(LITTLEENDIAN_CPU)
++ uint8_t PRESENT:1;
++ uint8_t TYPE:2;
++ uint8_t FORMAT_CONV:1;
++ uint8_t RESERVED:4;
++#elif defined(BIGENDIAN_CPU)
++ uint8_t RESERVED:4;
++ uint8_t FORMAT_CONV:1;
++ uint8_t TYPE:2;
++ uint8_t PRESENT:1;
++#else
++ #error ARCH not defined!
++#endif
++ } bits;
++
++ uint8_t raw;
++};
++
++/* DPCD_ADDR_SINK_COUNT register value */
++union dpcd_sink_count {
++ struct {
++#if defined(LITTLEENDIAN_CPU)
++ uint8_t SINK_COUNT:6;
++ uint8_t CP_READY:1;
++ uint8_t RESERVED:1;
++#elif defined(BIGENDIAN_CPU)
++ uint8_t RESERVED:1;
++ uint8_t CP_READY:1;
++ uint8_t SINK_COUNT:6;
++#else
++ #error ARCH not defined!
++#endif
++ } bits;
++
++ uint8_t raw;
++};
++
++struct link_settings {
++ enum lane_count lane_count;
++ enum link_rate link_rate;
++ enum link_spread link_spread;
++};
++
++struct lane_settings {
++ enum voltage_swing VOLTAGE_SWING;
++ enum pre_emphasis PRE_EMPHASIS;
++ enum post_cursor2 POST_CURSOR2;
++};
++
++struct link_training_settings {
++ struct link_settings link_settings;
++ struct lane_settings lane_settings[LANE_COUNT_DP_MAX];
++ bool allow_invalid_msa_timing_param;
++};
++
++enum hw_dp_training_pattern {
++ HW_DP_TRAINING_PATTERN_1 = 0,
++ HW_DP_TRAINING_PATTERN_2,
++ HW_DP_TRAINING_PATTERN_3
++};
++
++/*TODO: Move this enum test harness*/
++/* Test patterns*/
++enum dp_test_pattern {
++ /* Input data is pass through Scrambler
++ * and 8b10b Encoder straight to output*/
++ DP_TEST_PATTERN_VIDEO_MODE = 0,
++ /* phy test patterns*/
++ DP_TEST_PATTERN_D102,
++ DP_TEST_PATTERN_SYMBOL_ERROR,
++ DP_TEST_PATTERN_PRBS7,
++
++ DP_TEST_PATTERN_80BIT_CUSTOM,
++ DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE,
++
++ /* Link Training Patterns */
++ DP_TEST_PATTERN_TRAINING_PATTERN1,
++ DP_TEST_PATTERN_TRAINING_PATTERN2,
++ DP_TEST_PATTERN_TRAINING_PATTERN3,
++
++ /* link test patterns*/
++ DP_TEST_PATTERN_COLOR_SQUARES,
++ DP_TEST_PATTERN_COLOR_SQUARES_CEA,
++ DP_TEST_PATTERN_VERTICAL_BARS,
++ DP_TEST_PATTERN_HORIZONTAL_BARS,
++ DP_TEST_PATTERN_COLOR_RAMP,
++
++ /* audio test patterns*/
++ DP_TEST_PATTERN_AUDIO_OPERATOR_DEFINED,
++ DP_TEST_PATTERN_AUDIO_SAWTOOTH,
++
++ DP_TEST_PATTERN_UNSUPPORTED
++};
++
++enum dp_panel_mode {
++ /* not required */
++ DP_PANEL_MODE_DEFAULT,
++ /* standard mode for eDP */
++ DP_PANEL_MODE_EDP,
++ /* external chips specific settings */
++ DP_PANEL_MODE_SPECIAL
++};
++
++/**
++ * @brief LinkServiceInitOptions to set certain bits
++ */
++struct link_service_init_options {
++ uint32_t APPLY_MISALIGNMENT_BUG_WORKAROUND:1;
++};
++
++/**
++ * @brief data required to initialize LinkService
++ */
++struct link_service_init_data {
++ /* number of displays indices which the MST Mgr would manange*/
++ uint32_t num_of_displays;
++ enum link_service_type link_type;
++ /*struct mst_mgr_callback_object*topology_change_callback;*/
++ /* native aux access */
++ struct ddc_service *dpcd_access_srv;
++ /* for calling HWSS to program HW */
++ struct hw_sequencer *hwss;
++ /* the source which to register IRQ on */
++ enum dc_irq_source irq_src_hpd_rx;
++ enum dc_irq_source irq_src_dp_sink;
++ /* other init options such as SW Workarounds */
++ struct link_service_init_options init_options;
++ uint32_t connector_enum_id;
++ struct graphics_object_id connector_id;
++ struct adapter_service *adapter_service;
++ struct dc_context *ctx;
++ struct topology_mgr *tm;
++};
++
++/**
++ * @brief LinkServiceInitOptions to set certain bits
++ */
++struct LinkServiceInitOptions {
++ uint32_t APPLY_MISALIGNMENT_BUG_WORKAROUND:1;
++};
++
++/* DPCD_ADDR_TRAINING_LANEx_SET registers value */
++union dpcd_training_lane_set {
++ struct {
++#if defined(LITTLEENDIAN_CPU)
++ uint8_t VOLTAGE_SWING_SET:2;
++ uint8_t MAX_SWING_REACHED:1;
++ uint8_t PRE_EMPHASIS_SET:2;
++ uint8_t MAX_PRE_EMPHASIS_REACHED:1;
++ /* following is reserved in DP 1.1 */
++ uint8_t POST_CURSOR2_SET:2;
++#elif defined(BIGENDIAN_CPU)
++ uint8_t POST_CURSOR2_SET:2;
++ uint8_t MAX_PRE_EMPHASIS_REACHED:1;
++ uint8_t PRE_EMPHASIS_SET:2;
++ uint8_t MAX_SWING_REACHED:1;
++ uint8_t VOLTAGE_SWING_SET:2;
++#else
++ #error ARCH not defined!
++#endif
++ } bits;
++
++ uint8_t raw;
++};
++
++/* DPCD_ADDR_TRAINING_LANEx_SET2 registers value - since DP 1.2 */
++union dpcd_training_lanes_set2 {
++ struct {
++#if defined(LITTLEENDIAN_CPU)
++ uint8_t LANE0_POST_CURSOR2_SET:2;
++ uint8_t LANE0_MAX_POST_CURSOR2_REACHED:1;
++ uint8_t LANE0_RESERVED:1;
++ uint8_t LANE1_POST_CURSOR2_SET:2;
++ uint8_t LANE1_MAX_POST_CURSOR2_REACHED:1;
++ uint8_t LANE1_RESERVED:1;
++#elif defined(BIGENDIAN_CPU)
++ uint8_t LANE1_RESERVED:1;
++ uint8_t LANE1_MAX_POST_CURSOR2_REACHED:1;
++ uint8_t LANE1_POST_CURSOR2_SET:2;
++ uint8_t LANE0_RESERVED:1;
++ uint8_t LANE0_MAX_POST_CURSOR2_REACHED:1;
++ uint8_t LANE0_POST_CURSOR2_SET:2;
++#else
++ #error ARCH not defined!
++#endif
++ } bits;
++
++ uint8_t raw;
++};
++
++/**
++ * @brief represent the 16 byte
++ * global unique identifier
++ */
++struct mst_guid {
++ uint8_t ids[16];
++};
++
++/**
++ * @brief represents the relative address used
++ * to identify a node in MST topology network
++ */
++struct mst_rad {
++ /* number of links. rad[0] up to
++ * rad [linkCount - 1] are valid. */
++ uint32_t rad_link_count;
++ /* relative address. rad[0] is the
++ * first device connected to the source. */
++ uint8_t rad[15];
++ /* extra 10 bytes for underscores; for e.g.:2_1_8*/
++ int8_t rad_str[25];
++};
++
++/**
++ * @brief this structure is used to report
++ * properties associated to a sink device
++ */
++struct mst_sink_info {
++ /* global unique identifier */
++ struct mst_guid guid;
++ /* relative address */
++ struct mst_rad rad;
++ /* total bandwidth available on the DP connector */
++ uint32_t total_available_bandwidth_in_mbps;
++ /* bandwidth allocated to the sink device. */
++ uint32_t allocated_bandwidth_in_mbps;
++ /* bandwidth consumed to support for the current mode. */
++ uint32_t consumed_bandwidth_in_mbps;
++};
++
++/**
++ * @brief represent device information in MST topology
++ */
++struct mst_device_info {
++ /* global unique identifier*/
++ struct mst_guid guid;
++ /* relative address*/
++ struct mst_rad rad;
++};
++
++/* DP MST stream allocation (payload bandwidth number) */
++struct dp_mst_stream_allocation {
++ /* stream engine id (DIG) */
++ enum engine_id engine;
++ /* number of slots required for the DP stream in
++ * transport packet */
++ uint32_t slot_count;
++ uint32_t pbn;
++ uint32_t pbn_per_slot;
++};
++
++/* DP MST stream allocation table */
++struct dp_mst_stream_allocation_table {
++ /* number of DP video streams */
++ uint32_t stream_count;
++ /* array of stream allocations */
++ struct dp_mst_stream_allocation stream_allocations[1];
++};
++
++struct dp_test_event_data {
++ /*size of parameters (starting from params) in bytes*/
++ uint32_t size;
++ /*parameters block*/
++ uint32_t params[1];
++};
++
++struct psr_caps {
++ /* These parameters are from PSR capabilities reported by Sink DPCD. */
++ uint8_t psr_version;
++ uint32_t psr_rfb_setup_time;
++ bool psr_exit_link_training_req;
++
++ /* These parameters are calculated in Driver, based on display timing
++ * and Sink capabilities.
++ * If VBLANK region is too small and Sink takes a long time to power up
++ * Remote Frame Buffer, it may take an extra frame to enter PSR */
++ bool psr_frame_capture_indication_req;
++ uint32_t psr_sdp_transmit_line_num_deadline;
++};
++
++#endif /*__DAL_LINK_SERVICE_TYPES_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/include/logger_interface.h b/drivers/gpu/drm/amd/dal/include/logger_interface.h
+new file mode 100644
+index 0000000..4d945ea
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/logger_interface.h
+@@ -0,0 +1,153 @@
++/*
++ * 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_INTERFACE_H__
++#define __DAL_LOGGER_INTERFACE_H__
++
++#include "logger_types.h"
++
++struct dal_logger;
++struct dc_context;
++union logger_flags;
++
++/*
++ * TODO: This logger functionality needs to be implemented and reworked.
++ */
++
++
++/*
++ *
++ * DAL logger functionality
++ *
++ */
++
++struct dal_logger *dal_logger_create(struct dc_context *ctx);
++
++uint32_t dal_logger_destroy(struct dal_logger **logger);
++
++uint32_t dal_logger_get_mask(
++ struct dal_logger *logger,
++ enum log_major lvl_major, enum log_minor lvl_minor);
++
++uint32_t dal_logger_set_mask(
++ struct dal_logger *logger,
++ enum log_major lvl_major, enum log_minor lvl_minor);
++
++uint32_t dal_logger_get_masks(
++ struct dal_logger *logger,
++ enum log_major lvl_major);
++
++void dal_logger_set_masks(
++ struct dal_logger *logger,
++ enum log_major lvl_major, uint32_t log_mask);
++
++uint32_t dal_logger_unset_mask(
++ struct dal_logger *logger,
++ enum log_major lvl_major, enum log_minor lvl_minor);
++
++bool dal_logger_should_log(
++ struct dal_logger *logger,
++ enum log_major major,
++ enum log_minor minor);
++
++uint32_t dal_logger_get_flags(
++ struct dal_logger *logger);
++
++void dal_logger_set_flags(
++ struct dal_logger *logger,
++ union logger_flags flags);
++
++void dal_logger_write(
++ struct dal_logger *logger,
++ enum log_major major,
++ enum log_minor minor,
++ const char *msg,
++ ...);
++
++void dal_logger_append(
++ struct log_entry *entry,
++ const char *msg,
++ ...);
++
++uint32_t dal_logger_read(
++ struct dal_logger *logger,
++ uint32_t output_buffer_size,
++ char *output_buffer,
++ uint32_t *bytes_read,
++ bool single_line);
++
++void dal_logger_open(
++ struct dal_logger *logger,
++ struct log_entry *entry,
++ enum log_major major,
++ enum log_minor minor);
++
++void dal_logger_close(struct log_entry *entry);
++
++uint32_t dal_logger_get_buffer_size(struct dal_logger *logger);
++
++uint32_t dal_logger_set_buffer_size(
++ struct dal_logger *logger,
++ uint32_t new_size);
++
++const struct log_major_info *dal_logger_enum_log_major_info(
++ struct dal_logger *logger,
++ unsigned int enum_index);
++
++const struct log_minor_info *dal_logger_enum_log_minor_info(
++ struct dal_logger *logger,
++ enum log_major major,
++ unsigned int enum_index);
++
++/* Any function which is empty or have incomplete implementation should be
++ * marked by this macro.
++ * Note that the message will be printed exactly once for every function
++ * it is used in order to avoid repeating of the same message. */
++#define DAL_LOGGER_NOT_IMPL(log_minor, fmt, ...) \
++{ \
++ static bool print_not_impl = true; \
++\
++ if (print_not_impl == true) { \
++ print_not_impl = false; \
++ dal_logger_write(ctx->logger, LOG_MAJOR_WARNING, \
++ log_minor, "DAL_NOT_IMPL: " fmt, ##__VA_ARGS__); \
++ } \
++}
++
++/******************************************************************************
++ * Convenience macros to save on typing.
++ *****************************************************************************/
++
++#define DC_ERROR(...) \
++ dal_logger_write(dc_ctx->logger, \
++ LOG_MAJOR_ERROR, LOG_MINOR_COMPONENT_DC, \
++ __VA_ARGS__);
++
++#define DC_SYNC_INFO(...) \
++ dal_logger_write(dc_ctx->logger, \
++ LOG_MAJOR_SYNC, LOG_MINOR_SYNC_TIMING, \
++ __VA_ARGS__);
++
++#endif /* __DAL_LOGGER_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/logger_types.h b/drivers/gpu/drm/amd/dal/include/logger_types.h
+new file mode 100644
+index 0000000..6147999
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/logger_types.h
+@@ -0,0 +1,356 @@
++/*
++ * 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_TYPES_H__
++#define __DAL_LOGGER_TYPES_H__
++
++
++/*
++ * TODO: This logger functionality needs to be implemented and reworked.
++ */
++
++
++struct dal_logger;
++
++enum log_major {
++/*00*/
++ LOG_MAJOR_ERROR = 0, /*< DAL subcomponent error MSG*/
++/*01*/ LOG_MAJOR_WARNING, /*< DAL subcomponent warning MSG*/
++/*02*/ LOG_MAJOR_INTERFACE_TRACE,/*< DAL subcomponent interface tracing*/
++/*03*/ LOG_MAJOR_HW_TRACE, /*< Log ASIC register read/write,
++ * ATOMBIOS exec table call and delays*/
++
++/*04*/ LOG_MAJOR_MST, /*< related to multi-stream*/
++/*05*/ LOG_MAJOR_DCS, /*< related to Dcs*/
++/*06*/ LOG_MAJOR_DCP, /*< related to Dcp grph and ovl,gamam and csc*/
++/*07*/ LOG_MAJOR_BIOS, /*< related to BiosParser*/
++/*08*/ LOG_MAJOR_REGISTER, /*< register access*/
++/*09*/ LOG_MAJOR_INFO_PACKETS, /*< info packets*/
++/*10*/ LOG_MAJOR_DSAT, /*< related
++ * to Display System Analysis Tool*/
++/*11*/ LOG_MAJOR_EC, /*< External Components - MCIL Events/queries,
++ * PPLib notifications/queries*/
++/*12*/ LOG_MAJOR_BWM, /*< related to Bandwidth Manager*/
++/*13*/ LOG_MAJOR_MODE_ENUM, /*< related to mode enumeration*/
++/*14*/ LOG_MAJOR_I2C_AUX, /*< i2c and aux channel log*/
++/*15*/ LOG_MAJOR_LINE_BUFFER, /*< Line Buffer object logging activity*/
++/*16*/ LOG_MAJOR_HWSS, /*< HWSS object logging activity*/
++/*17*/ LOG_MAJOR_OPTIMIZATION, /*< Optimization code path*/
++/*18*/ LOG_MAJOR_PERF_MEASURE, /*< Performance measurement dumps*/
++/*19*/ LOG_MAJOR_SYNC, /*< related to HW and SW Synchronization*/
++/*20*/ LOG_MAJOR_BACKLIGHT, /*< related to backlight */
++/*21*/ LOG_MAJOR_INTERRUPTS, /*< logging for all interrupts */
++
++/*22*/ LOG_MAJOR_TM, /*< related to Topology Manager*/
++/*23*/ LOG_MAJOR_DISPLAY_SERVICE, /*< related to Display Service*/
++/*24*/ LOG_MAJOR_FEATURE_OVERRIDE, /*< related to features*/
++/*25*/ LOG_MAJOR_DETECTION, /*< related to detection*/
++ LOG_MAJOR_COUNT, /*< count of the Major categories*/
++};
++
++/**
++* @brief defines minor switch for logging. each of these define sub category
++* of log message per LogMajor
++*/
++
++
++enum log_minor {
++
++ /* Special case for 'all' checkbox */
++ LOG_MINOR_MASK_ALL = (uint32_t)-1, /* 0xFFFFFFFF */
++/**
++* @brief defines minor category for
++* LOG_MAJOR_ERROR,
++* LOG_MAJOR_WARNING,
++* LOG_MAJOR_INTERFACE_TRACE
++*
++* @note each DAL subcomponent should have a corresponding enum
++*/
++ LOG_MINOR_COMPONENT_LINK_SERVICE = 0,
++ LOG_MINOR_COMPONENT_DAL_INTERFACE,
++ LOG_MINOR_COMPONENT_HWSS,
++ LOG_MINOR_COMPONENT_ADAPTER_SERVICE,
++ LOG_MINOR_COMPONENT_DISPLAY_SERVICE,
++ LOG_MINOR_COMPONENT_TOPOLOGY_MANAGER,
++ LOG_MINOR_COMPONENT_ENCODER,
++ LOG_MINOR_COMPONENT_I2C_AUX,
++ LOG_MINOR_COMPONENT_AUDIO,
++ LOG_MINOR_COMPONENT_DISPLAY_CAPABILITY_SERVICE,
++ LOG_MINOR_COMPONENT_DMCU,
++ LOG_MINOR_COMPONENT_GPU,
++ LOG_MINOR_COMPONENT_CONTROLLER,
++ LOG_MINOR_COMPONENT_ISR,
++ LOG_MINOR_COMPONENT_BIOS,
++ LOG_MINOR_COMPONENT_DC,
++ LOG_MINOR_COMPONENT_IRQ_SERVICE,
++
++/**
++* @brief define minor category for LogMajor_HardwareTrace
++*
++* @note defines functionality based HW programming trace
++*/
++ LOG_MINOR_HW_TRACE_MST = 0,
++ LOG_MINOR_HW_TRACE_TRAVIS,
++ LOG_MINOR_HW_TRACE_HOTPLUG,
++ LOG_MINOR_HW_TRACE_LINK_TRAINING,
++ LOG_MINOR_HW_TRACE_SET_MODE,
++ LOG_MINOR_HW_TRACE_RESUME_S3,
++ LOG_MINOR_HW_TRACE_RESUME_S4,
++ LOG_MINOR_HW_TRACE_BOOTUP,
++ LOG_MINOR_HW_TRACE_AUDIO,
++ LOG_MINOR_HW_TRACE_HPD_IRQ,
++ LOG_MINOR_HW_TRACE_INTERRUPT,
++ LOG_MINOR_HW_TRACE_MPO,
++
++/**
++* @brief defines minor category for LogMajor_Mst
++*
++* @note define sub functionality related to MST
++*/
++ LOG_MINOR_MST_IRQ_HPD_RX = 0,
++ LOG_MINOR_MST_IRQ_TIMER,
++ LOG_MINOR_MST_NATIVE_AUX,
++ LOG_MINOR_MST_SIDEBAND_MSG,
++ LOG_MINOR_MST_MSG_TRANSACTION,
++ LOG_MINOR_MST_SIDEBAND_MSG_PARSED,
++ LOG_MINOR_MST_MSG_TRANSACTION_PARSED,
++ LOG_MINOR_MST_AUX_MSG_DPCD_ACCESS,
++ LOG_MINOR_MST_PROGRAMMING,
++ LOG_MINOR_MST_TOPOLOGY_DISCOVERY,
++ LOG_MINOR_MST_CONVERTER_CAPS,
++
++/**
++* @brief defines minor category for LogMajor_DCS
++*
++* @note should define sub functionality related to Dcs
++*/
++ LOG_MINOR_DCS_EDID_EMULATOR = 0,
++ LOG_MINOR_DCS_DONGLE_DETECTION,
++
++/**
++* @brief defines minor category for DCP
++*
++* @note should define sub functionality related to Dcp
++*/
++ LOG_MINOR_DCP_GAMMA_GRPH = 0,
++ LOG_MINOR_DCP_GAMMA_OVL,
++ LOG_MINOR_DCP_CSC_GRPH,
++ LOG_MINOR_DCP_CSC_OVL,
++ LOG_MINOR_DCP_SCALER,
++ LOG_MINOR_DCP_SCALER_TABLES,
++/**
++* @brief defines minor category for LogMajor_Bios
++*
++* @note define sub functionality related to BiosParser
++*/
++ LOG_MINOR_BIOS_CMD_TABLE = 0,
++/**
++* @brief defines minor category for LogMajor_Bios
++*
++* @note define sub functionality related to BiosParser
++*/
++ LOG_MINOR_REGISTER_INDEX = 0,
++/**
++* @brief defines minor category for info packets
++*
++*/
++ LOG_MINOR_INFO_PACKETS_HDMI = 0,
++
++/**
++* @brief defines minor category for LOG_MAJOR_DSAT
++*
++* @note define sub functionality related to Display System Analysis Tool
++*/
++ LOG_MINOR_DSAT_LOGGER = 0,
++ LOG_MINOR_DSAT_GET_EDID,
++ LOG_MINOR_DSAT_EDID_OVERRIDE,
++ LOG_MINOR_DSAT_SET_ADJUSTMENTS,
++ LOG_MINOR_DSAT_GET_ADJUSTMENTS,
++
++/**
++* @brief defines minor category for LOG_MAJOR_EC
++*
++* @note define sub functionality related to External components notifications
++*/
++ LOG_MINOR_EC_PPLIB_NOTIFY = 0,
++ LOG_MINOR_EC_PPLIB_QUERY,
++
++/**
++* @brief defines minor category for LOG_MAJOR_BWM
++*
++* @note define sub functionality related to Bandwidth Manager
++*/
++ LOG_MINOR_BWM_MODE_VALIDATION = 0,
++ LOG_MINOR_BWM_REQUIRED_BANDWIDTH_CALCS,
++
++/**
++* @brief define minor category for LogMajor_ModeEnum
++*
++* @note defines functionality mode enumeration trace
++*/
++ LOG_MINOR_MODE_ENUM_BEST_VIEW_CANDIDATES = 0,
++ LOG_MINOR_MODE_ENUM_VIEW_SOLUTION,
++ LOG_MINOR_MODE_ENUM_TS_LIST_BUILD,
++ LOG_MINOR_MODE_ENUM_TS_LIST,
++ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST,
++ LOG_MINOR_MODE_ENUM_MASTER_VIEW_LIST_UPDATE,
++
++/**
++* @brief defines minor category for LogMajor_I2C_AUX
++*
++* @note define sub functionality related to I2c and Aux Channel Log
++*/
++ LOG_MINOR_I2C_AUX_LOG = 0,
++ LOG_MINOR_I2C_AUX_AUX_TIMESTAMP,
++ LOG_MINOR_I2C_AUX_CFG,
++
++/**
++* @brief defines minor category for LogMajor_LineBuffer
++*
++* @note define sub functionality related to LineBuffer
++*/
++ LOG_MINOR_LINE_BUFFER_POWERGATING = 0,
++
++/**
++* @brief defines minor category for LogMajor_HWSS
++*
++* @note define sub functionality related to HWSS
++*/
++ LOG_MINOR_HWSS_TAPS_VALIDATION = 0,
++
++/**
++* @brief defines minor category for LogMajor_Optimization
++*
++* @note define sub functionality related to Optimization
++*/
++ LOG_MINOR_OPTMZ_GENERAL = 0,
++ LOG_MINOR_OPTMZ_DO_NOT_TURN_OFF_VCC_DURING_SET_MODE,
++
++/**
++* @brief defines minor category for LogMajor_PerfMeasure
++*
++* @note define sub functionality related to Performance measurement dumps
++*/
++ LOG_MINOR_PERF_MEASURE_GENERAL = 0,
++ LOG_MINOR_PERF_MEASURE_HEAP_MEMORY,
++
++/**
++* @brief defines minor category for LogMajor_Sync
++*
++* @note define sub functionality related to HW and SW Synchronization
++*/
++ LOG_MINOR_SYNC_HW_CLOCK_ADJUST = 0,
++ LOG_MINOR_SYNC_TIMING,
++
++/**
++* @brief defines minor category for LogMajor_Backlight
++*
++* @note define sub functionality related to backlight (including VariBright)
++*/
++ LOG_MINOR_BACKLIGHT_BRIGHTESS_CAPS = 0,
++ LOG_MINOR_BACKLIGHT_DMCU_DELTALUT,
++ LOG_MINOR_BACKLIGHT_DMCU_BUILD_DELTALUT,
++ LOG_MINOR_BACKLIGHT_INTERFACE,
++ LOG_MINOR_BACKLIGHT_LID,
++
++/**
++* @brief defines minor category for LOG_MAJOR_TM
++*
++* @note define sub functionality related to Topology Manager
++*/
++ LOG_MINOR_TM_INFO = 0,
++ LOG_MINOR_TM_IFACE_TRACE,
++ LOG_MINOR_TM_RESOURCES,
++ LOG_MINOR_TM_ENCODER_CTL,
++ LOG_MINOR_TM_ENG_ASN,
++ LOG_MINOR_TM_CONTROLLER_ASN,
++ LOG_MINOR_TM_PWR_GATING,
++ LOG_MINOR_TM_BUILD_DSP_PATH,
++ LOG_MINOR_TM_DISPLAY_DETECT,
++ LOG_MINOR_TM_LINK_SRV,
++ LOG_MINOR_TM_NOT_IMPLEMENTED,
++ LOG_MINOR_TM_COFUNC_PATH,
++
++/**
++* @brief defines minor category for LOG_MAJOR_DISPLAY_SERVICE
++*
++* @note define sub functionality related to Display Service
++*/
++ LOG_MINOR_DS_MODE_SETTING = 0,
++
++/**
++* @brief defines minor category for LOG_MAJOR_FEATURE_OVERRIDE
++*
++* @note define sub functionality related to features in adapter service
++*/
++ LOG_MINOR_FEATURE_OVERRIDE = 0,
++
++/**
++* @brief defines minor category for LOG_MAJOR_DETECTION
++*
++* @note define sub functionality related to detection
++*/
++ LOG_MINOR_DETECTION_EDID_PARSER = 0,
++ LOG_MINOR_DETECTION_DP_CAPS,
++};
++
++union logger_flags {
++ struct {
++ uint32_t ENABLE_CONSOLE:1; /* Print to console */
++ uint32_t ENABLE_BUFFER:1; /* Print to buffer */
++ uint32_t RESERVED:30;
++ } bits;
++ uint32_t value;
++};
++
++struct log_entry {
++
++ struct dal_logger *logger;
++ enum log_major major;
++ enum log_minor minor;
++
++ char *buf;
++ uint32_t buf_offset;
++ uint32_t max_buf_bytes;
++};
++
++/**
++* Structure for enumerating LogMajors and LogMinors
++*/
++
++#define MAX_MAJOR_NAME_LEN 32
++#define MAX_MINOR_NAME_LEN 32
++
++struct log_major_info {
++ enum log_major major;
++ char major_name[MAX_MAJOR_NAME_LEN];
++};
++
++struct log_minor_info {
++ enum log_minor minor;
++ char minor_name[MAX_MINOR_NAME_LEN];
++};
++
++#endif /* __DAL_LOGGER_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/mode_manager_types.h b/drivers/gpu/drm/amd/dal/include/mode_manager_types.h
+new file mode 100644
+index 0000000..576b21f
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/mode_manager_types.h
+@@ -0,0 +1,71 @@
++/*
++ * 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_MODE_MANAGER_TYPES_H__
++#define __DAL_MODE_MANAGER_TYPES_H__
++
++#include "bit_set.h"
++#include "dc_types.h"
++
++static inline void stereo_3d_view_reset(struct stereo_3d_view *stereo_3d_view)
++{
++ stereo_3d_view->view_3d_format = VIEW_3D_FORMAT_NONE;
++ stereo_3d_view->flags.raw = 0;
++}
++
++bool dal_refresh_rate_is_equal(
++ const struct refresh_rate *lhs,
++ const struct refresh_rate *rhs);
++
++bool dal_refresh_rate_less_than(
++ const struct refresh_rate *lhs,
++ const struct refresh_rate *rhs);
++
++void refresh_rate_from_mode_info(
++ struct refresh_rate *,
++ const struct dc_mode_info *);
++bool dal_solution_less_than(const void *lhs, const void *rhs);
++bool dal_view_is_equal(const struct view *lhs, const struct view *rhs);
++
++struct pixel_format_list {
++ uint32_t set;
++ struct bit_set_iterator_32 iter;
++};
++
++void dal_pixel_format_list_reset_iterator(struct pixel_format_list *pfl);
++void dal_pixel_format_list_zero_iterator(struct pixel_format_list *pfl);
++
++void dal_pixel_format_list_construct(
++ struct pixel_format_list *pfl,
++ uint32_t mask);
++
++uint32_t dal_pixel_format_list_next(struct pixel_format_list *pfl);
++
++uint32_t dal_pixel_format_list_get_count(
++ const struct pixel_format_list *pfl);
++enum pixel_format dal_pixel_format_list_get_pixel_format(
++ const struct pixel_format_list *pfl);
++
++#endif /* __DAL_MODE_MANAGER_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/mode_query_interface.h b/drivers/gpu/drm/amd/dal/include/mode_query_interface.h
+new file mode 100644
+index 0000000..1d20e73
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/mode_query_interface.h
+@@ -0,0 +1,93 @@
++/*
++ * 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_MODE_QUERY_INTERFACE_H__
++#define __DAL_MODE_QUERY_INTERFACE_H__
++
++#include "include/set_mode_types.h"
++#include "include/mode_manager_types.h"
++
++enum query_option {
++ QUERY_OPTION_ALLOW_PAN,
++ QUERY_OPTION_ALLOW_PAN_NO_VIEW_RESTRICTION,
++ QUERY_OPTION_PAN_ON_LIMITED_RESOLUTION_DISP_PATH,
++ QUERY_OPTION_NO_PAN,
++ QUERY_OPTION_NO_PAN_NO_DISPLAY_VIEW_RESTRICTION,
++ QUERY_OPTION_3D_LIMITED_CANDIDATES,
++ QUERY_OPTION_TILED_DISPLAY_PREFERRED,
++ QUERY_OPTION_MAX,
++};
++
++struct topology {
++ uint32_t disp_path_num;
++ uint32_t display_index[MAX_COFUNC_PATH];
++};
++
++struct path_mode;
++struct mode_query;
++
++bool dal_mode_query_pin_path_mode(
++ struct mode_query *mq,
++ const struct path_mode *path_mode);
++
++const struct render_mode *dal_mode_query_get_current_render_mode(
++ const struct mode_query *mq);
++
++const struct stereo_3d_view *dal_mode_query_get_current_3d_view(
++ const struct mode_query *mq);
++
++const struct refresh_rate *dal_mode_query_get_current_refresh_rate(
++ const struct mode_query *mq);
++
++const struct path_mode_set *dal_mode_query_get_current_path_mode_set(
++ const struct mode_query *mq);
++
++bool dal_mode_query_select_first(struct mode_query *mq);
++bool dal_mode_query_select_next_render_mode(struct mode_query *mq);
++
++bool dal_mode_query_select_render_mode(struct mode_query *mq,
++ const struct render_mode *render_mode);
++
++bool dal_mode_query_select_next_view_3d_format(struct mode_query *mq);
++bool dal_mode_query_select_view_3d_format(
++ struct mode_query *mq,
++ enum view_3d_format format);
++
++bool dal_mode_query_select_refresh_rate(struct mode_query *mq,
++ const struct refresh_rate *refresh_rate);
++
++bool dal_mode_query_select_refresh_rate_ex(struct mode_query *mq,
++ uint32_t refresh_rate,
++ bool interlaced);
++
++bool dal_mode_query_select_next_scaling(struct mode_query *mq);
++
++bool dal_mode_query_select_next_refresh_rate(struct mode_query *mq);
++
++bool dal_mode_query_base_select_next_scaling(struct mode_query *mq);
++
++void dal_mode_query_destroy(struct mode_query **mq);
++
++#endif /* __DAL_MODE_QUERY_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/mode_timing_list_interface.h b/drivers/gpu/drm/amd/dal/include/mode_timing_list_interface.h
+new file mode 100644
+index 0000000..a558fec
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/mode_timing_list_interface.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DAL_MODE_TIMING_LIST_INTERFACE_H__
++#define __DAL_MODE_TIMING_LIST_INTERFACE_H__
++
++
++struct mode_timing_filter;
++struct mode_timing_list;
++
++struct mode_timing_list *dal_mode_timing_list_create(
++ struct dal_context *ctx,
++ uint32_t display_index,
++ const struct mode_timing_filter *mt_filter);
++
++void dal_mode_timing_list_destroy(struct mode_timing_list **mtl);
++
++
++uint32_t dal_mode_timing_list_get_count(
++ const struct mode_timing_list *mode_timing_list);
++
++const struct dc_mode_timing *dal_mode_timing_list_get_timing_at_index(
++ const struct mode_timing_list *mode_timing_list,
++ uint32_t index);
++
++const struct dc_mode_timing *dal_mode_timing_list_get_single_selected_mode_timing(
++ const struct mode_timing_list *mode_timing_list);
++
++#endif /*__DAL_MODE_TIMING_LIST_INTERFACE_H__*/
+diff --git a/drivers/gpu/drm/amd/dal/include/overlay_interface.h b/drivers/gpu/drm/amd/dal/include/overlay_interface.h
+new file mode 100644
+index 0000000..c33bd73
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/overlay_interface.h
+@@ -0,0 +1,137 @@
++/*
++ * 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_OVERLAY_INTERFACE_H__
++#define __DAL_OVERLAY_INTERFACE_H__
++
++#include "include/overlay_types.h"
++#include "include/display_service_types.h"
++
++struct ds_overlay;
++struct path_mode_set;
++struct path_mode;
++struct view;
++
++bool dal_ds_overlay_is_active(
++ struct ds_overlay *ovl,
++ uint32_t display_index);
++
++uint32_t dal_ds_overlay_get_controller_handle(
++ struct ds_overlay *ovl,
++ uint32_t display_index);
++
++enum ds_return dal_ds_overlay_alloc(
++ struct ds_overlay *ovl,
++ struct path_mode_set *path_mode_set,
++ uint32_t display_index,
++ struct view *view,
++ struct overlay_data *data);
++
++enum ds_return dal_ds_overlay_validate(
++ struct ds_overlay *ovl,
++ struct path_mode_set *path_mode_set,
++ uint32_t display_index,
++ struct view *view,
++ struct overlay_data *data);
++
++enum ds_return dal_ds_overlay_free(
++ struct ds_overlay *ovl,
++ struct path_mode_set *path_mode_set,
++ uint32_t display_index);
++
++enum ds_return dal_ds_overlay_get_info(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ enum overlay_color_space *color_space,
++ enum overlay_backend_bpp *backend_bpp,
++ enum overlay_alloc_option *alloc_option,
++ enum overlay_format *surface_format);
++
++enum ds_return dal_ds_overlay_set_otm(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ const struct path_mode *current_path_mode);
++
++enum ds_return dal_ds_overlay_reset_otm(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ struct path_mode **saved_path_mode);
++
++/**is in overlay theater mode*/
++bool dal_ds_overlay_is_in_otm(
++ struct ds_overlay *ovl,
++ uint32_t display_index);
++
++void dal_ds_overlay_set_matrix(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ const struct overlay_color_matrix *matrix);
++
++void dal_ds_overlay_reset_matrix(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ enum overlay_csc_matrix_type type);
++
++const struct overlay_color_matrix *dal_ds_overlay_get_matrix(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ enum overlay_csc_matrix_type type);
++
++bool dal_ds_overlay_set_color_space(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ enum overlay_color_space space);
++
++bool dal_ds_overlay_get_display_pixel_encoding(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ enum display_pixel_encoding *pixel_encoding);
++
++bool dal_ds_overlay_set_display_pixel_encoding(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ enum display_pixel_encoding pixel_encoding);
++
++bool dal_ds_overlay_reset_display_pixel_encoding(
++ struct ds_overlay *ovl,
++ uint32_t display_index);
++
++/*After Set Overlay Theatre Mode (OTM) on a display path,
++ * saving the passed setting of Gpu scaling option for later restore*/
++enum ds_return dal_ds_overlay_save_gpu_scaling_before_otm(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ int32_t timing_sel_before_otm);
++
++/* After reset Overlay Theatre Mode (OTM) on a display path,
++ * returning the previous Gpu scaling option by SetOverlayTheatreMode*/
++enum ds_return dal_ds_overlay_get_gpu_scaling_before_otm(
++ struct ds_overlay *ovl,
++ uint32_t display_index,
++ int32_t *timing_sel_before_otm);
++
++uint32_t dal_ds_overlay_get_num_of_allowed(struct ds_overlay *ovl);
++
++#endif /* __DAL_OVERLAY_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/overlay_types.h b/drivers/gpu/drm/amd/dal/include/overlay_types.h
+new file mode 100644
+index 0000000..c001edf
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/overlay_types.h
+@@ -0,0 +1,164 @@
++/*
++ * 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_OVERLAY_TYPES_H__
++#define __DAL_OVERLAY_TYPES_H__
++
++enum overlay_color_space {
++ OVERLAY_COLOR_SPACE_UNINITIALIZED,
++ OVERLAY_COLOR_SPACE_RGB, /* the first*/
++ OVERLAY_COLOR_SPACE_BT601,
++ OVERLAY_COLOR_SPACE_BT709, /* the last*/
++ OVERLAY_COLOR_SPACE_INVALID,
++
++ /* flag the first and last*/
++ OVERLAY_COLOR_SPACE_BEGIN = OVERLAY_COLOR_SPACE_RGB,
++ OVERLAY_COLOR_SPACE_END = OVERLAY_COLOR_SPACE_BT709,
++};
++
++enum overlay_backend_bpp {
++ OVERLAY_BACKENDBPP_UNINITIALIZED,
++
++ OVERLAY_BACKEND_BPP_32_FULL_BANDWIDTH,/* the first*/
++ OVERLAY_BACKEND_BPP_16_FULL_BANDWIDTH,
++ OVERLAY_BACKEND_BPP_32_HALF_BANDWIDTH,/* the last*/
++
++ OVERLAY_BACKEND_BPP_INVALID,
++
++ /* flag the first and last*/
++ OVERLAY_BACKEND_BPP_BEGIN = OVERLAY_BACKEND_BPP_32_FULL_BANDWIDTH,
++ OVERLAY_BACKEND_BPP_END = OVERLAY_BACKEND_BPP_32_HALF_BANDWIDTH,
++};
++
++enum overlay_alloc_option {
++ OVERLAY_ALLOC_OPTION_UNINITIALIZED,
++
++ OVERLAY_ALLOC_OPTION_APPLY_OVERLAY_CSC, /* the first*/
++ OVERLAY_ALLOC_OPTION_APPLY_DESKTOP_CSC, /* the last*/
++
++ OVERLAY_ALLOC_OPTION_INVALID,
++
++ /* flag the first and last*/
++ OVERLAY_ALLOC_OPTION_BEGIN = OVERLAY_ALLOC_OPTION_APPLY_OVERLAY_CSC,
++ OVERLAY_ALLOC_OPTION_END = OVERLAY_ALLOC_OPTION_APPLY_DESKTOP_CSC,
++};
++
++enum overlay_format {
++ OVERLAY_FORMAT_UNINITIALIZED,
++ OVERLAY_FORMAT_YUY2,
++ OVERLAY_FORMAT_UYVY,
++ OVERLAY_FORMAT_RGB565,
++ OVERLAY_FORMAT_RGB555,
++ OVERLAY_FORMAT_RGB32,
++ OVERLAY_FORMAT_YUV444,
++ OVERLAY_FORMAT_RGB32_2101010,
++
++ OVERLAY_FORMAT_INVALID,
++
++ /* flag the first and last*/
++ OVERLAY_FORMAT_BEGIN = OVERLAY_FORMAT_YUY2,
++ OVERLAY_FORMAT_END = OVERLAY_FORMAT_RGB32_2101010,
++};
++
++enum display_pixel_encoding {
++ DISPLAY_PIXEL_ENCODING_UNDEFINED = 0,
++ DISPLAY_PIXEL_ENCODING_RGB,
++ DISPLAY_PIXEL_ENCODING_YCBCR422,
++ DISPLAY_PIXEL_ENCODING_YCBCR444
++};
++
++union overlay_data_status {
++ uint32_t u32all;
++ struct {
++ uint32_t COLOR_SPACE_SET:1;
++ uint32_t BACKEND_BPP:1;
++ uint32_t ALLOC_OPTION:1;
++ uint32_t SURFACE_FORMAT:1;
++ uint32_t PIXEL_ENCODING:1;
++ uint32_t reserved:27;
++
++ } bits;
++};
++
++struct overlay_data {
++ enum overlay_color_space color_space;
++ enum overlay_backend_bpp backend_bpp;
++ enum overlay_alloc_option alloc_option;
++ enum overlay_format surface_format;
++};
++
++enum overlay_csc_matrix_type {
++ OVERLAY_CSC_MATRIX_NOTDEFINED = 0,
++ OVERLAY_CSC_MATRIX_BT709,
++ OVERLAY_CSC_MATRIX_BT601,
++ OVERLAY_CSC_MATRIX_SMPTE240,
++ OVERLAY_CSC_MATRIX_SRGB,
++};
++
++#define DEFAULT_APP_MATRIX_DIVIDER 10000
++#define MAX_OVL_MATRIX_COUNTS 2
++#define OVL_BT709 0
++#define OVL_BT601 1
++
++#define OVL_MATRIX_ITEM 9
++#define OVL_MATRIX_OFFSET_ITEM 3
++
++struct overlay_color_matrix {
++ enum overlay_csc_matrix_type csc_matrix;
++/*3*3 Gamut Matrix (value is the real value * M_GAMUT_PRECISION_MULTIPLIER)*/
++ int32_t matrix_settings[OVL_MATRIX_ITEM];
++ int32_t offsets[OVL_MATRIX_OFFSET_ITEM];
++};
++
++enum setup_adjustment_ovl_value_type {
++ SETUP_ADJUSTMENT_MIN,
++ SETUP_ADJUSTMENT_MAX,
++ SETUP_ADJUSTMENT_DEF,
++ SETUP_ADJUSTMENT_CURRENT,
++ SETUP_ADJUSTMENT_BUNDLE_MIN,
++ SETUP_ADJUSTMENT_BUNDLE_MAX,
++ SETUP_ADJUSTMENT_BUNDLE_DEF,
++ SETUP_ADJUSTMENT_BUNDLE_CURRENT
++};
++
++struct overlay_parameter {
++ union {
++ uint32_t u32all;
++ struct {
++ uint32_t VALID_OVL_COLOR_SPACE:1;
++ uint32_t VALID_VALUE_TYPE:1;
++ uint32_t VALID_OVL_SURFACE_FORMAT:1;
++ uint32_t CONFIG_IS_CHANGED:1;
++ uint32_t reserved:28;
++
++ } bits;
++ };
++ /*currently colorSpace here packed, continue this list*/
++ enum overlay_color_space color_space;
++ enum setup_adjustment_ovl_value_type value_type;
++ enum overlay_format surface_format;
++};
++
++#endif /* OVERLAY_TYPES_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/include/path_mode_set_interface.h b/drivers/gpu/drm/amd/dal/include/path_mode_set_interface.h
+new file mode 100644
+index 0000000..a277010
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/path_mode_set_interface.h
+@@ -0,0 +1,107 @@
++/*
++ * 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_PATH_MODE_SET_INTERFACE_H__
++#define __DAL_PATH_MODE_SET_INTERFACE_H__
++
++/* Set of path modes */
++struct path_mode_set {
++ union control_flags {
++ struct {
++ uint32_t KEEP_DISPLAY_POWERED_OFF:1;
++ uint32_t UNBLANCK_SOURCE_AFTER_SETMODE:1;
++ uint32_t NODE_FAULT_UNDERSCAN:1;
++ } bits;
++
++ uint32_t all;
++ } control_flags;
++
++ struct path_mode path_mode_set[MAX_COFUNC_PATH];
++ uint32_t count;
++};
++
++/* Create path mode set */
++struct path_mode_set *dal_pms_create(void);
++
++/* Deallocate path mode set */
++void dal_pms_destroy(
++ struct path_mode_set **pms);
++
++/* Create a copy of given path mode set */
++struct path_mode_set *dal_pms_copy(
++ const struct path_mode_set *copy);
++
++/* Constructor for path mode set */
++bool dal_pms_construct(
++ struct path_mode_set *set);
++
++/* Add a path mode into the set */
++bool dal_pms_add_path_mode(
++ struct path_mode_set *set,
++ const struct path_mode *path_mode);
++
++/* Get number of path modes in the set */
++uint32_t dal_pms_get_path_mode_num(
++ const struct path_mode_set *set);
++
++/* Return the path mode at the index */
++const struct path_mode *dal_pms_get_path_mode_at_index(
++ const struct path_mode_set *set,
++ uint32_t index);
++
++/* Return the path mode for the given display index */
++const struct path_mode *dal_pms_get_path_mode_for_display_index(
++ const struct path_mode_set *set,
++ uint32_t index);
++
++/* Remove the path mode at index */
++bool dal_pms_remove_path_mode_at_index(
++ struct path_mode_set *set,
++ uint32_t index);
++
++/* Remove the given path mode if it is found in the set */
++bool dal_pms_remove_path_mode(
++ struct path_mode_set *set,
++ struct path_mode *mode);
++
++/* Add control flag to keep display powered off */
++void dal_pms_keep_display_powered_off(
++ struct path_mode_set *set,
++ bool keep);
++
++/* Return control flag if display needs to be kept powered off */
++bool dal_pms_is_display_power_off_required(
++ const struct path_mode_set *set);
++
++/* Add control flag to not use default underscan*/
++void dal_pms_fallback_remove_default_underscan(
++ struct path_mode_set *set,
++ bool lean);
++
++/* Return control flag if default underscan is not used */
++bool dal_pms_is_fallback_no_default_underscan_enabled(
++ struct path_mode_set *set);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/plane_types.h b/drivers/gpu/drm/amd/dal/include/plane_types.h
+new file mode 100644
+index 0000000..a2a8939
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/plane_types.h
+@@ -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
++ *
++ */
++
++#ifndef __DAL_PLANE_TYPES_H__
++#define __DAL_PLANE_TYPES_H__
++
++#include "scaler_types.h"
++
++enum display_flip_mode {
++ DISPLAY_FLIP_MODE_VERTICAL = 0,
++ DISPLAY_FLIP_MODE_HORIZONTAL
++};
++
++/*rect or view */
++struct rect_position {
++ uint32_t x;
++ uint32_t y;
++};
++
++union plane_config_change_flags {
++ struct {
++ uint32_t MIRROR_FLAGS:1;
++ uint32_t BLEND_FLAGS:1;
++ uint32_t COLORIMETRY:1;
++ uint32_t SCALING_RECTS:1;
++
++ uint32_t SCALING_QUALITY:1;
++ uint32_t VIDEO_SCAN_FORMAT:1;
++ uint32_t STEREO_FORMAT:1;
++ uint32_t PLANE_SIZE:1;
++
++ uint32_t TITLING_INFO:1;
++ uint32_t FORMAT:1;
++ uint32_t ROTATION:1;
++
++ uint32_t RESERVED:21;
++ } bits;
++ uint32_t value;
++};
++
++
++enum array_mode {
++ ARRAY_MODE_LINEAR_GENERAL = 0x00000000,
++ ARRAY_MODE_LINEAR_ALIGNED = 0x00000001,
++ ARRAY_MODE_1D_TILED_THIN1 = 0x00000002,
++ ARRAY_MODE_1D_TILED_THICK = 0x00000003,
++ ARRAY_MODE_2D_TILED_THIN1 = 0x00000004,
++ ARRAY_MODE_PRT_TILED_THIN1 = 0x00000005,
++ ARRAY_MODE_PRT_2D_TILED_THIN1 = 0x00000006,
++ ARRAY_MODE_2D_TILED_THICK = 0x00000007,
++ ARRAY_MODE_2D_TILED_X_THICK = 0x00000008,
++ ARRAY_MODE_PRT_TILED_THICK = 0x00000009,
++ ARRAY_MODE_PRT_2D_TILED_THICK = 0x0000000a,
++ ARRAY_MODE_PRT_3D_TILED_THIN1 = 0x0000000b,
++ ARRAY_MODE_3D_TILED_THIN1 = 0x0000000c,
++ ARRAY_MODE_3D_TILED_THICK = 0x0000000d,
++ ARRAY_MODE_3D_TILED_X_THICK = 0x0000000e,
++ ARRAY_MODE_PRT_3D_TILED_THICK = 0x0000000f
++};
++
++/* single enum for grph and video (both luma and chroma) */
++enum tile_split {
++ TILE_SPLIT_64B = 0x00000000,
++ TILE_SPLIT_128B = 0x00000001,
++ TILE_SPLIT_256B = 0x00000002,
++ TILE_SPLIT_512B = 0x00000003,
++ TILE_SPLIT_1KB = 0x00000004,
++ TILE_SPLIT_2KB = 0x00000005,
++ TILE_SPLIT_4KB = 0x00000006
++};
++
++/* single enum for grph and video (both luma and chroma)*/
++enum macro_tile_aspect {
++ MACRO_TILE_ASPECT_1 = 0x00000000,
++ MACRO_TILE_ASPECT_2 = 0x00000001,
++ MACRO_TILE_ASPECT_4 = 0x00000002,
++ MACRO_TILE_ASPECT_8 = 0x00000003
++};
++
++enum video_array_mode {
++ VIDEO_ARRAY_MODE_LINEAR_GENERAL = 0x00000000,
++ VIDEO_ARRAY_MODE_LINEAR_ALIGNED = 0x00000001,
++ VIDEO_ARRAY_MODE_1D_TILED_THIN1 = 0x00000002,
++ VIDEO_ARRAY_MODE_1D_TILED_THICK = 0x00000003,
++ VIDEO_ARRAY_MODE_2D_TILED_THIN1 = 0x00000004,
++ VIDEO_ARRAY_MODE_2D_TILED_THICK = 0x00000007,
++ VIDEO_ARRAY_MODE_3D_TILED_THIN1 = 0x0000000c,
++ VIDEO_ARRAY_MODE_3D_TILED_THICK = 0x0000000d
++};
++
++/* single enum for grph and video (both luma and chroma)*/
++enum micro_tile_mode {
++ MICRO_TILE_MODE_DISPLAY = 0x00000000,
++ MICRO_TILE_MODE_THIN = 0x00000001,
++ MICRO_TILE_MODE_DEPTH = 0x00000002,
++ MICRO_TILE_MODE_ROTATED = 0x00000003
++};
++
++/* KK: taken from addrlib*/
++enum addr_pipe_config {
++ ADDR_PIPE_CONFIG_INVALID = 0,
++ /* 2 pipes */
++ ADDR_PIPE_CONFIG_P2 = 1,
++ /* 4 pipes */
++ ADDR_PIPE_CONFIG_P4_8x16 = 5,
++ ADDR_PIPE_CONFIG_P4_16x16 = 6,
++ ADDR_PIPE_CONFIG_P4_16x32 = 7,
++ ADDR_PIPE_CONFIG_P4_32x32 = 8,
++ /* 8 pipes*/
++ ADDR_PIPE_CONFIG_P8_16x16_8x16 = 9,
++ ADDR_PIPE_CONFIG_P8_16x32_8x16 = 10,
++ ADDR_PIPE_CONFIG_P8_32x32_8x16 = 11,
++ ADDR_PIPE_CONFIG_P8_16x32_16x16 = 12,
++ ADDR_PIPE_CONFIG_P8_32x32_16x16 = 13,
++ ADDR_PIPE_CONFIG_P8_32x32_16x32 = 14,
++ ADDR_PIPE_CONFIG_P8_32x64_32x32 = 15,
++ /* 16 pipes */
++ ADDR_PIPE_CONFIG_P16_32x32_8x16 = 17,
++ ADDR_PIPE_CONFIG_P16_32x32_16x16 = 18,
++ ADDR_PIPE_CONFIG_MAX = 19
++};
++
++struct plane_surface_config {
++ uint32_t layer_index;
++ /*used in set operation*/
++ bool enabled;
++
++ union plane_size plane_size;
++ union plane_tiling_info tiling_info;
++ /* surface pixel format from display manager or fb*/
++ enum surface_pixel_format format;
++ /*pixel format for DAL internal hardware programming*/
++ enum pixel_format dal_pixel_format;
++ enum dc_rotation_angle rotation;
++};
++
++/* For Caps, maximum taps for each axis is returned*/
++/* For Set, the requested taps will be used*/
++struct plane_src_scaling_quality {
++ /* INVALID_TAP_VALUE indicates DAL
++ * decides considering aspect ratio
++ * & bandwidth
++ */
++ uint32_t h_taps;
++ /* INVALID_TAP_VALUE indicates DAL
++ * decides considering aspect ratio
++ * & bandwidth
++ */
++ uint32_t v_taps;
++ uint32_t h_taps_c;
++ uint32_t v_taps_c;
++};
++
++struct plane_mirror_flags {
++ union {
++ struct {
++ uint32_t vertical_mirror:1;
++ uint32_t horizontal_mirror:1;
++ uint32_t reserved:30;
++ } bits;
++ uint32_t value;
++ };
++};
++
++/* Note some combinations are mutually exclusive*/
++struct plane_blend_flags {
++ union {
++ struct {
++ uint32_t PER_PIXEL_ALPHA_BLEND:1;
++ uint32_t GLOBAL_ALPHA_BLEND:1;
++ uint32_t RESERVED:30;
++ } bits;
++ uint32_t value;
++ };
++};
++
++enum plane_vid_scan_fmt {
++ PLANE_VID_SCAN_FMT_PROGRESSIVE = 0,
++ PLANE_VID_SCAN_FMT_INTERLACED_TOP_FIRST = 1,
++ PLANE_VID_SCAN_FMT_INTERLACED_BOTTOM_FIRST = 2
++};
++
++
++struct plane_attributes {
++ /*mirror options */
++ struct plane_mirror_flags mirror_flags;
++ /*blending options*/
++ struct plane_blend_flags blend_flags;
++ /*color space */
++ struct plane_colorimetry colorimetry;
++
++ struct rect src_rect;
++ struct rect dst_rect;
++ struct rect clip_rect;
++ struct scaling_taps scaling_quality;
++ /*progressive, interlaced*/
++ enum plane_vid_scan_fmt video_scan_format;
++ enum plane_stereo_format stereo_format;
++};
++
++union address_flags {
++ struct {
++ /* always 1 for primary surface, used in get operation*/
++ uint32_t ENABLE:1;
++ /* set 1 if returned address is from cache*/
++ uint32_t ADDR_IS_PENDING:1;
++ /* currentFrameIsRightEye for stereo only*/
++ uint32_t CURRENT_FRAME_IS_RIGHT_EYE:1;
++ uint32_t RESERVED:29;
++ } bits;
++
++ uint32_t value;
++};
++
++struct address_info {
++ /* primary surface will be DAL_LAYER_INDEX_PRIMARY*/
++ int32_t layer_index;
++ /*the flags to describe the address info*/
++ union address_flags flags;
++ struct dc_plane_address address;
++};
++
++union plane_valid_mask {
++ struct {
++ /* set 1 if config is valid in DalPlane*/
++ uint32_t SURFACE_CONFIG_IS_VALID:1;
++ /* set 1 if plane_attributes is valid in plane*/
++ uint32_t PLANE_ATTRIBUTE_IS_VALID:1;
++ uint32_t RESERVED:30;
++ } bits;
++ uint32_t value;
++};
++
++union flip_valid_mask {
++ struct {
++ /* set 1 if flip_immediate is
++ * valid in plane_addr_flip_info
++ */
++ uint32_t FLIP_VALID:1;
++ /* set 1 if addressInfo is
++ * valid in plane_addr_flip_info
++ */
++ uint32_t ADDRESS_VALID:1;
++ uint32_t RESERVED:30;
++ } bits;
++ uint32_t value;
++};
++
++struct plane_addr_flip_info {
++ uint32_t display_index;
++ struct address_info address_info;
++ /* flip on vsync if false . When
++ * flip_immediate is true then
++ * update_duration is unused
++ */
++ bool flip_immediate;
++ /* 48 Hz support for single and
++ * multi plane cases ,set 0 when
++ * it is unused.
++ */
++ uint32_t update_duration;
++ union flip_valid_mask mask;
++};
++
++struct plane_config {
++ union plane_valid_mask mask;
++ uint32_t display_index;
++ struct plane_surface_config config;
++ struct plane_attributes attributes;
++ struct mp_scaling_data mp_scaling_data;
++ union plane_config_change_flags plane_change_flags;
++};
++
++struct plane_validate_config {
++ uint32_t display_index;
++ bool flip_immediate;
++ struct plane_surface_config config;
++ struct plane_attributes attributes;
++};
++
++struct view_port {
++ uint32_t display_index;
++ struct rect view_port_rect;
++};
++
++#endif
++
+diff --git a/drivers/gpu/drm/amd/dal/include/scaler_types.h b/drivers/gpu/drm/amd/dal/include/scaler_types.h
+new file mode 100644
+index 0000000..db52dbc
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/scaler_types.h
+@@ -0,0 +1,196 @@
++/*
++ * 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_SCALER_TYPES_H__
++#define __DAL_SCALER_TYPES_H__
++
++#include "signal_types.h"
++#include "fixed31_32.h"
++#include "dc_types.h"
++
++enum pixel_type {
++ PIXEL_TYPE_30BPP = 1,
++ PIXEL_TYPE_20BPP
++};
++
++/*overscan or window*/
++struct overscan_info {
++ uint32_t left;
++ uint32_t right;
++ uint32_t top;
++ uint32_t bottom;
++};
++
++struct mp_scaling_data {
++ struct rect viewport;
++ struct view dst_res;
++ struct overscan_info overscan;
++ struct scaling_taps taps;
++ struct scaling_ratios ratios;
++};
++
++struct scaler_validation_params {
++ uint32_t INTERLACED:1;
++ uint32_t CHROMA_SUB_SAMPLING:1;
++
++ uint32_t line_buffer_size;
++ uint32_t display_clock; /* in KHz */
++ uint32_t actual_pixel_clock; /* in KHz */
++ struct view source_view;
++ struct view dest_view;
++ enum signal_type signal_type;
++
++ struct scaling_taps taps_requested;
++ enum pixel_format pixel_format;
++ enum dc_rotation_angle rotation;
++};
++
++struct adjustment_factor {
++ int32_t adjust; /* Actual adjustment value * lDivider */
++ uint32_t divider;
++};
++
++struct sharpness_adjustment {
++ int32_t sharpness;
++ bool enable_sharpening;
++};
++
++enum scaling_options {
++ SCALING_BYPASS = 0,
++ SCALING_ENABLE
++};
++
++/* same as Hw register */
++enum filter_type {
++ FILTER_TYPE_V_LOW_PASS = 0x0,
++ FILTER_TYPE_V_HIGH_PASS = 0x1,
++ FILTER_TYPE_H_LUMA = 0x2,
++ FILTER_TYPE_H_CHROMA = 0x3
++};
++
++/* Validation Result enumeration */
++enum scaler_validation_code {
++ SCALER_VALIDATION_OK = 0,
++ SCALER_VALIDATION_INVALID_INPUT_PARAMETERS,
++ SCALER_VALIDATION_SCALING_RATIO_NOT_SUPPORTED,
++ SCALER_VALIDATION_SOURCE_VIEW_WIDTH_EXCEEDING_LIMIT,
++ SCALER_VALIDATION_DISPLAY_CLOCK_BELOW_PIXEL_CLOCK,
++ SCALER_VALIDATION_FAILURE_PREDEFINED_TAPS_NUMBER
++};
++
++
++#define FILTER_TYPE_MASK 0x0000000FL
++#define TWO_TAPS 2
++
++struct init_int_and_frac {
++ uint32_t integer;
++ uint32_t fraction;
++};
++
++struct scl_ratios_inits {
++ uint32_t bottom_enable;
++ uint32_t h_int_scale_ratio;
++ uint32_t v_int_scale_ratio;
++ struct init_int_and_frac h_init;
++ struct init_int_and_frac v_init;
++ struct init_int_and_frac v_init_bottom;
++};
++
++union scaler_flags {
++ uint32_t raw;
++ struct {
++ uint32_t INTERLACED:1;
++ uint32_t DOUBLE_SCAN_MODE:1;
++ /* this one is legacy flag only used in DCE80 */
++ uint32_t RGB_COLOR_SPACE:1;
++ uint32_t PIPE_LOCK_REQ:1;
++ /* 4 */
++ uint32_t WIDE_DISPLAY:1;
++ uint32_t OTHER_PIPE:1;
++ uint32_t SHOULD_PROGRAM_VIEWPORT:1;
++ uint32_t SHOULD_UNLOCK:1;
++ /* 8 */
++ uint32_t SHOULD_PROGRAM_ALPHA:1;
++ uint32_t SHOW_COLOURED_BORDER:1;
++
++ uint32_t RESERVED:22;
++ } bits;
++};
++
++struct scaler_data {
++ struct view src_res;
++ struct view dst_res;
++ struct overscan_info overscan;
++ struct scaling_taps taps;
++ struct adjustment_factor scale_ratio_hp_factor;
++ struct adjustment_factor scale_ratio_lp_factor;
++ enum pixel_type pixel_type; /*legacy*/
++ struct sharpness_adjustment sharp_gain;
++
++ union scaler_flags flags;
++ int32_t h_sharpness;
++ int32_t v_sharpness;
++
++ struct view src_res_wide_display;
++ struct view dst_res_wide_display;
++
++ /* it is here because of the HW bug in NI (UBTS #269539)
++ causes glitches in this VBI signal. It shouldn't change after
++ initialization, kind of a const */
++ const struct hw_crtc_timing *hw_crtc_timing;
++
++ struct rect viewport;
++
++ enum pixel_format dal_pixel_format;/*plane concept*/
++ /*stereoformat TODO*/
++ /*hwtotation TODO*/
++
++ const struct scaling_ratios *ratios;
++};
++
++enum bypass_type {
++ /* 00 - 00 - Manual Centering, Manual Replication */
++ BYPASS_TYPE_MANUAL = 0,
++ /* 01 - 01 - Auto-Centering, No Replication */
++ BYPASS_TYPE_AUTO_CENTER = 1,
++ /* 02 - 10 - Auto-Centering, Auto-Replication */
++ BYPASS_TYPE_AUTO_REPLICATION = 3
++};
++
++struct replication_factor {
++ uint32_t h_manual;
++ uint32_t v_manual;
++};
++
++enum ram_filter_type {
++ FILTER_TYPE_RGB_Y_VERTICAL = 0, /* 0 - RGB/Y Vertical filter */
++ FILTER_TYPE_CBCR_VERTICAL = 1, /* 1 - CbCr Vertical filter */
++ FILTER_TYPE_RGB_Y_HORIZONTAL = 2, /* 1 - RGB/Y Horizontal filter */
++ FILTER_TYPE_CBCR_HORIZONTAL = 3, /* 3 - CbCr Horizontal filter */
++ FILTER_TYPE_ALPHA_VERTICAL = 4, /* 4 - Alpha Vertical filter. */
++ FILTER_TYPE_ALPHA_HORIZONTAL = 5, /* 5 - Alpha Horizontal filter. */
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/set_mode_params_interface.h b/drivers/gpu/drm/amd/dal/include/set_mode_params_interface.h
+new file mode 100644
+index 0000000..e4f52c4
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/set_mode_params_interface.h
+@@ -0,0 +1,101 @@
++/*
++ * 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_SET_MODE_PARAMS_INTERFACE_H__
++#define __DAL_SET_MODE_PARAMS_INTERFACE_H__
++
++struct set_mode_params;
++
++struct set_mode_params_init_data {
++ struct hw_sequencer *hws;
++ struct dal_context *ctx;
++ struct topology_mgr *tm;
++};
++
++struct view_stereo_3d_support dal_set_mode_params_get_stereo_3d_support(
++ struct set_mode_params *smp,
++ uint32_t display_index,
++ enum dc_timing_3d_format);
++
++bool dal_set_mode_params_update_view_on_path(
++ struct set_mode_params *smp,
++ uint32_t display_index,
++ const struct view *vw);
++
++bool dal_set_mode_params_update_mode_timing_on_path(
++ struct set_mode_params *smp,
++ uint32_t display_index,
++ const struct dc_mode_timing *mode_timing,
++ enum view_3d_format format);
++
++bool dal_set_mode_params_update_scaling_on_path(
++ struct set_mode_params *smp,
++ uint32_t display_index,
++ enum scaling_transformation st);
++
++bool dal_set_mode_params_update_pixel_format_on_path(
++ struct set_mode_params *smp,
++ uint32_t display_index,
++ enum pixel_format pf);
++
++bool dal_set_mode_params_update_tiling_mode_on_path(
++ struct set_mode_params *smp,
++ uint32_t display_index,
++ enum tiling_mode tm);
++
++bool dal_set_mode_params_is_path_mode_set_supported(
++ struct set_mode_params *smp);
++
++bool dal_set_mode_params_is_path_mode_set_guaranteed(
++ struct set_mode_params *smp);
++
++bool dal_set_mode_params_report_single_selected_timing(
++ struct set_mode_params *smp,
++ uint32_t display_index);
++
++bool dal_set_mode_params_report_ce_mode_only(
++ struct set_mode_params *smp,
++ uint32_t display_index);
++
++struct set_mode_params *dal_set_mode_params_create(
++ struct set_mode_params_init_data *init_data);
++
++bool dal_set_mode_params_init_with_topology(
++ struct set_mode_params *smp,
++ const uint32_t display_indicies[],
++ uint32_t idx_num);
++
++bool dal_set_mode_params_is_multiple_pixel_encoding_supported(
++ struct set_mode_params *smp,
++ uint32_t display_index);
++
++enum dc_pixel_encoding dal_set_mode_params_get_default_pixel_format_preference(
++ struct set_mode_params *smp,
++ unsigned int display_index);
++
++void dal_set_mode_params_destroy(
++ struct set_mode_params **set_mode_params);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/set_mode_types.h b/drivers/gpu/drm/amd/dal/include/set_mode_types.h
+new file mode 100644
+index 0000000..3647815
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/set_mode_types.h
+@@ -0,0 +1,285 @@
++/*
++ * 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_SET_MODE_TYPES_H__
++#define __DAL_SET_MODE_TYPES_H__
++
++#include "adjustment_types.h"
++#include "hw_adjustment_types.h"
++#include "include/plane_types.h"
++#include "dc_types.h"
++
++/* Forward declaration */
++struct dc_mode_timing;
++struct display_path;
++
++/* State of stereo 3D for workstation */
++enum ws_stereo_state {
++ WS_STEREO_STATE_INACTIVE = 0,
++ WS_STEREO_STATE_ACTIVE,
++ WS_STEREO_STATE_ACTIVE_MASTER
++};
++
++/* GTC group number */
++enum gtc_group {
++ GTC_GROUP_DISABLED,
++ GTC_GROUP_1,
++ GTC_GROUP_2,
++ GTC_GROUP_3,
++ GTC_GROUP_4,
++ GTC_GROUP_5,
++ GTC_GROUP_6,
++ GTC_GROUP_MAX
++};
++
++/* Adjustment action*/
++enum adjustment_action {
++ ADJUSTMENT_ACTION_UNDEFINED = 0,
++ ADJUSTMENT_ACTION_VALIDATE,
++ ADJUSTMENT_ACTION_SET_ADJUSTMENT
++};
++
++/* Type of adjustment parameters*/
++enum adjustment_par_type {
++ ADJUSTMENT_PAR_TYPE_NONE = 0,
++ ADJUSTMENT_PAR_TYPE_TIMING,
++ ADJUSTMENT_PAR_TYPE_MODE
++};
++
++/* Method of validation */
++enum validation_method {
++ VALIDATION_METHOD_STATIC = 0,
++ VALIDATION_METHOD_DYNAMIC
++};
++
++/* Info frame packet status */
++enum info_frame_flag {
++ INFO_PACKET_PACKET_INVALID = 0,
++ INFO_PACKET_PACKET_VALID = 1,
++ INFO_PACKET_PACKET_RESET = 2,
++ INFO_PACKET_PACKET_UPDATE_SCAN_TYPE = 8
++};
++
++/* Info frame types */
++enum info_frame_type {
++ INFO_FRAME_GAMUT = 0x0A,
++ INFO_FRAME_VENDOR_INFO = 0x81,
++ INFO_FRAME_AVI = 0x82
++};
++
++/* Info frame versions */
++enum info_frame_version {
++ INFO_FRAME_VERSION_1 = 1,
++ INFO_FRAME_VERSION_2 = 2,
++ INFO_FRAME_VERSION_3 = 3
++};
++
++/* Info frame size */
++enum info_frame_size {
++ INFO_FRAME_SIZE_AVI = 13,
++ INFO_FRAME_SIZE_VENDOR = 25,
++ INFO_FRAME_SIZE_AUDIO = 10
++};
++
++/* Active format */
++enum active_format_info {
++ ACTIVE_FORMAT_NO_DATA = 0,
++ ACTIVE_FORMAT_VALID = 1
++};
++/* Bar info */
++enum bar_info {
++ BAR_INFO_NOT_VALID = 0,
++ BAR_INFO_VERTICAL_VALID = 1,
++ BAR_INFO_HORIZONTAL_VALID = 2,
++ BAR_INFO_BOTH_VALID = 3
++};
++
++/* Picture scaling */
++enum picture_scaling {
++ PICTURE_SCALING_UNIFORM = 0,
++ PICTURE_SCALING_HORIZONTAL = 1,
++ PICTURE_SCALING_VERTICAL = 2,
++ PICTURE_SCALING_BOTH = 3
++};
++
++/* Colorimetry */
++enum colorimetry {
++ COLORIMETRY_NO_DATA = 0,
++ COLORIMETRY_ITU601 = 1,
++ COLORIMETRY_ITU709 = 2,
++ COLORIMETRY_EXTENDED = 3
++};
++
++/* ColorimetryEx */
++enum colorimetry_ex {
++ COLORIMETRY_EX_XVYCC601 = 0,
++ COLORIMETRY_EX_XVYCC709 = 1,
++ COLORIMETRY_EX_SYCC601 = 2,
++ COLORIMETRY_EX_ADOBEYCC601 = 3,
++ COLORIMETRY_EX_ADOBERGB = 4,
++ COLORIMETRY_EX_RESERVED5 = 5,
++ COLORIMETRY_EX_RESERVED6 = 6,
++ COLORIMETRY_EX_RESERVED7 = 7
++};
++
++/* Active format aspect ratio */
++enum active_format_aspect_ratio {
++ ACTIVE_FORMAT_ASPECT_RATIO_SAME_AS_PICTURE = 8,
++ ACTIVE_FORMAT_ASPECT_RATIO_4_3 = 9,
++ ACTIVE_FORMAT_ASPECT_RATIO_16_9 = 0XA,
++ ACTIVE_FORMAT_ASPECT_RATIO_14_9 = 0XB
++};
++
++/* RGB quantization range */
++enum rgb_quantization_range {
++ RGB_QUANTIZATION_DEFAULT_RANGE = 0,
++ RGB_QUANTIZATION_LIMITED_RANGE = 1,
++ RGB_QUANTIZATION_FULL_RANGE = 2,
++ RGB_QUANTIZATION_RESERVED = 3
++};
++
++/* YYC quantization range */
++enum yyc_quantization_range {
++ YYC_QUANTIZATION_LIMITED_RANGE = 0,
++ YYC_QUANTIZATION_FULL_RANGE = 1,
++ YYC_QUANTIZATION_RESERVED2 = 2,
++ YYC_QUANTIZATION_RESERVED3 = 3
++};
++
++/* Rotation capability */
++struct rotation_capability {
++ bool ROTATION_ANGLE_0_CAP:1;
++ bool ROTATION_ANGLE_90_CAP:1;
++ bool ROTATION_ANGLE_180_CAP:1;
++ bool ROTATION_ANGLE_270_CAP:1;
++};
++
++/* Underscan position and size */
++struct ds_underscan_desc {
++ uint32_t x;
++ uint32_t y;
++ uint32_t width;
++ uint32_t height;
++};
++
++/* View, timing and other mode related information */
++struct path_mode {
++ struct view view;
++ struct rect_position view_position;
++ enum view_3d_format view_3d_format;
++ const struct dc_mode_timing *mode_timing;
++ enum scaling_transformation scaling;
++ enum pixel_format pixel_format;
++ uint32_t display_path_index;
++ enum tiling_mode tiling_mode;
++ enum dc_rotation_angle rotation_angle;
++ bool is_tiling_rotated;
++ struct rotation_capability rotation_capability;
++};
++
++struct hdmi_info_frame_header {
++ uint8_t info_frame_type;
++ uint8_t version;
++ uint8_t length;
++};
++
++#pragma pack(push)
++#pragma pack(1)
++struct info_packet_raw_data {
++ uint8_t hb0;
++ uint8_t hb1;
++ uint8_t hb2;
++ uint8_t sb[28]; /* sb0~sb27 */
++};
++
++union hdmi_info_packet {
++ struct avi_info_frame {
++ struct hdmi_info_frame_header header;
++
++ uint8_t CHECK_SUM:8;
++
++ uint8_t S0_S1:2;
++ uint8_t B0_B1:2;
++ uint8_t A0:1;
++ uint8_t Y0_Y1_Y2:3;
++
++ uint8_t R0_R3:4;
++ uint8_t M0_M1:2;
++ uint8_t C0_C1:2;
++
++ uint8_t SC0_SC1:2;
++ uint8_t Q0_Q1:2;
++ uint8_t EC0_EC2:3;
++ uint8_t ITC:1;
++
++ uint8_t VIC0_VIC7:8;
++
++ uint8_t PR0_PR3:4;
++ uint8_t CN0_CN1:2;
++ uint8_t YQ0_YQ1:2;
++
++ uint16_t bar_top;
++ uint16_t bar_bottom;
++ uint16_t bar_left;
++ uint16_t bar_right;
++
++ uint8_t reserved[14];
++ } bits;
++
++ struct info_packet_raw_data packet_raw_data;
++};
++
++struct info_packet {
++ enum info_frame_flag flags;
++ union hdmi_info_packet info_packet_hdmi;
++};
++
++struct info_frame {
++ struct info_packet avi_info_packet;
++ struct info_packet gamut_packet;
++ struct info_packet vendor_info_packet;
++ struct info_packet spd_info_packet;
++};
++
++
++/* Adjustment parameter */
++struct adjustment_parameters {
++ enum adjustment_par_type type;
++ struct {
++ enum adjustment_id ajd_id;
++ enum hw_adjustment_id adj_id_hw;
++ } timings;
++};
++
++/* Parameters for adjustments*/
++struct adjustment_params {
++ enum adjustment_action action;
++ struct adjustment_parameters params;
++ const struct display_path *affected_path;
++};
++
++#pragma pack(pop)
++
++#endif /* __DAL_SET_MODE_TYPES_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/signal_types.h b/drivers/gpu/drm/amd/dal/include/signal_types.h
+new file mode 100644
+index 0000000..e95e821
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/signal_types.h
+@@ -0,0 +1,58 @@
++/*
++ * Copyright 2012-15 Advanced Micro Devices, Inc.
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a
++ * copy of this software and associated documentation files (the "Software"),
++ * to deal in the Software without restriction, including without limitation
++ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
++ * and/or sell copies of the Software, and to permit persons to whom the
++ * Software is furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
++ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
++ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
++ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ * OTHER DEALINGS IN THE SOFTWARE.
++ *
++ * Authors: AMD
++ *
++ */
++
++#ifndef __DC_SIGNAL_TYPES_H__
++#define __DC_SIGNAL_TYPES_H__
++
++enum signal_type {
++ SIGNAL_TYPE_NONE = 0L, /* no signal */
++ SIGNAL_TYPE_DVI_SINGLE_LINK = (1 << 0),
++ SIGNAL_TYPE_DVI_DUAL_LINK = (1 << 1),
++ SIGNAL_TYPE_HDMI_TYPE_A = (1 << 2),
++ SIGNAL_TYPE_LVDS = (1 << 3),
++ SIGNAL_TYPE_RGB = (1 << 4),
++ SIGNAL_TYPE_DISPLAY_PORT = (1 << 5),
++ SIGNAL_TYPE_DISPLAY_PORT_MST = (1 << 6),
++ SIGNAL_TYPE_EDP = (1 << 7),
++ SIGNAL_TYPE_WIRELESS = (1 << 8), /* Wireless Display */
++
++ SIGNAL_TYPE_COUNT = 9,
++ SIGNAL_TYPE_ALL = (1 << SIGNAL_TYPE_COUNT) - 1
++};
++
++/* help functions for signal types manipulation */
++bool dc_is_hdmi_signal(enum signal_type signal);
++bool dc_is_dp_sst_signal(enum signal_type signal);
++bool dc_is_dp_signal(enum signal_type signal);
++bool dc_is_dp_external_signal(enum signal_type signal);
++bool dc_is_analog_signal(enum signal_type signal);
++bool dc_is_embedded_signal(enum signal_type signal);
++bool dc_is_dvi_signal(enum signal_type signal);
++bool dc_is_dvi_single_link_signal(enum signal_type signal);
++bool dc_is_dual_link_signal(enum signal_type signal);
++bool dc_is_audio_capable_signal(enum signal_type signal);
++bool dc_is_digital_encoder_compatible_signal(enum signal_type signal);
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/stream_encoder_types.h b/drivers/gpu/drm/amd/dal/include/stream_encoder_types.h
+new file mode 100644
+index 0000000..0d3e67c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/stream_encoder_types.h
+@@ -0,0 +1,16 @@
++/*
++ * stream_encoder_types.h
++ *
++ */
++#include "encoder_interface.h"
++
++#ifndef STREAM_ENCODER_TYPES_H_
++#define STREAM_ENCODER_TYPES_H_
++
++struct stream_encoder {
++ enum engine_id id;
++ struct adapter_service *adapter_service;
++ struct dc_context *ctx;
++};
++
++#endif /* STREAM_ENCODER_TYPES_H_ */
+diff --git a/drivers/gpu/drm/amd/dal/include/timing_generator_types.h b/drivers/gpu/drm/amd/dal/include/timing_generator_types.h
+new file mode 100644
+index 0000000..9c4d92d
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/timing_generator_types.h
+@@ -0,0 +1,150 @@
++/*
++ * 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_TIMING_GENERATOR_TYPES_H__
++#define __DAL_TIMING_GENERATOR_TYPES_H__
++
++#include "include/grph_csc_types.h"
++
++/**
++ * These parameters are required as input when doing blanking/Unblanking
++*/
++struct crtc_black_color {
++ uint32_t black_color_r_cr;
++ uint32_t black_color_g_y;
++ uint32_t black_color_b_cb;
++};
++
++/* Contains CRTC vertical/horizontal pixel counters */
++struct crtc_position {
++ uint32_t vertical_count;
++ uint32_t horizontal_count;
++ uint32_t nominal_vcount;
++};
++
++/*
++ * Parameters to enable/disable stereo 3D mode on CRTC
++ * - rightEyePolarity: if true, '0' means left eye image and '1' means right
++ * eye image.
++ * if false, '0' means right eye image and '1' means left eye image
++ * - framePacked: true when HDMI 1.4a FramePacking 3D format
++ * enabled/disabled
++ */
++struct crtc_stereo_parameters {
++ uint8_t PROGRAM_STEREO:1;
++ uint8_t PROGRAM_POLARITY:1;
++ uint8_t RIGHT_EYE_POLARITY:1;
++ uint8_t FRAME_PACKED:1;
++};
++
++struct crtc_stereo_status {
++ uint8_t ENABLED:1;
++ uint8_t CURRENT_FRAME_IS_RIGHT_EYE:1;
++ uint8_t CURRENT_FRAME_IS_ODD_FIELD:1;
++ uint8_t FRAME_PACKED:1;
++ uint8_t PENDING_RESET:1;
++};
++
++enum dcp_gsl_purpose {
++ DCP_GSL_PURPOSE_SURFACE_FLIP = 0,
++ DCP_GSL_PURPOSE_STEREO3D_PHASE,
++ DCP_GSL_PURPOSE_UNDEFINED
++};
++
++struct dcp_gsl_params {
++ enum sync_source gsl_group;
++ enum dcp_gsl_purpose gsl_purpose;
++ bool timing_server;
++ bool overlay_present;
++ bool gsl_paused;
++};
++
++struct vbi_end_signal_setup {
++ uint32_t minimum_interval_in_us; /* microseconds */
++ uint32_t pixel_clock; /* in KHz */
++ bool scaler_enabled;
++ bool interlace;
++ uint32_t src_height;
++ uint32_t overscan_top;
++ uint32_t overscan_bottom;
++ uint32_t v_total;
++ uint32_t v_addressable;
++ uint32_t h_total;
++};
++
++#define LEFT_EYE_3D_PRIMARY_SURFACE 1
++#define RIGHT_EYE_3D_PRIMARY_SURFACE 0
++
++enum test_pattern_dyn_range {
++ TEST_PATTERN_DYN_RANGE_VESA = 0,
++ TEST_PATTERN_DYN_RANGE_CEA
++};
++
++enum test_pattern_mode {
++ TEST_PATTERN_MODE_COLORSQUARES_RGB = 0,
++ TEST_PATTERN_MODE_COLORSQUARES_YCBCR601,
++ TEST_PATTERN_MODE_COLORSQUARES_YCBCR709,
++ TEST_PATTERN_MODE_VERTICALBARS,
++ TEST_PATTERN_MODE_HORIZONTALBARS,
++ TEST_PATTERN_MODE_SINGLERAMP_RGB,
++ TEST_PATTERN_MODE_DUALRAMP_RGB
++};
++
++enum test_pattern_color_format {
++ TEST_PATTERN_COLOR_FORMAT_BPC_6 = 0,
++ TEST_PATTERN_COLOR_FORMAT_BPC_8,
++ TEST_PATTERN_COLOR_FORMAT_BPC_10,
++ TEST_PATTERN_COLOR_FORMAT_BPC_12
++};
++
++enum controller_dp_test_pattern {
++ CONTROLLER_DP_TEST_PATTERN_D102 = 0,
++ CONTROLLER_DP_TEST_PATTERN_SYMBOLERROR,
++ CONTROLLER_DP_TEST_PATTERN_PRBS7,
++ CONTROLLER_DP_TEST_PATTERN_COLORSQUARES,
++ CONTROLLER_DP_TEST_PATTERN_VERTICALBARS,
++ CONTROLLER_DP_TEST_PATTERN_HORIZONTALBARS,
++ CONTROLLER_DP_TEST_PATTERN_COLORRAMP,
++ CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
++ CONTROLLER_DP_TEST_PATTERN_RESERVED_8,
++ CONTROLLER_DP_TEST_PATTERN_RESERVED_9,
++ CONTROLLER_DP_TEST_PATTERN_RESERVED_A,
++ CONTROLLER_DP_TEST_PATTERN_COLORSQUARES_CEA
++};
++
++struct timing_generator {
++ uint32_t *regs;
++ struct bios_parser *bp;
++ enum controller_id controller_id;
++ struct dc_context *ctx;
++ uint32_t max_h_total;
++ uint32_t max_v_total;
++
++ uint32_t min_h_blank;
++ uint32_t min_h_front_porch;
++ uint32_t min_h_back_porch;
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/timing_list_query_interface.h b/drivers/gpu/drm/amd/dal/include/timing_list_query_interface.h
+new file mode 100644
+index 0000000..16e3521
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/timing_list_query_interface.h
+@@ -0,0 +1,69 @@
++/*
++ * 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_TIMING_LIST_QUERY_INTERFACE_H__
++#define __DAL_TIMING_LIST_QUERY_INTERFACE_H__
++
++/* External dependencies */
++#include "include/dcs_interface.h"
++
++/* Forward declarations */
++struct dal;
++struct dal_timing_list_query;
++
++enum timing_support_level {
++ TIMING_SUPPORT_LEVEL_UNDEFINED,
++ /* assumed to be guaranteed supported by display,
++ * usually one timing is marked as native */
++ TIMING_SUPPORT_LEVEL_NATIVE,
++ /* user wants DAL to drive this timing as if Display supports it */
++ TIMING_SUPPORT_LEVEL_GUARANTEED,
++ /* user wants DAL to drive this timing even if display
++ * may not support it */
++ TIMING_SUPPORT_LEVEL_NOT_GUARANTEED
++};
++
++struct timing_list_query_init_data {
++ struct dal *dal; /* an instance of DAL */
++ struct timing_service *timing_srv;
++ struct dcs *dcs;
++ uint32_t display_index;
++};
++
++struct dal_timing_list_query *dal_timing_list_query_create(
++ struct timing_list_query_init_data *init_data);
++
++void dal_timing_list_query_destroy(struct dal_timing_list_query **tlsq);
++
++/* Get count of mode timings in the list. */
++uint32_t dal_timing_list_query_get_mode_timing_count(
++ const struct dal_timing_list_query *tlsq);
++
++const struct dc_mode_timing *dal_timing_list_query_get_mode_timing_at_index(
++ const struct dal_timing_list_query *tlsq,
++ uint32_t index);
++
++
++#endif /* __DAL_TIMING_LIST_QUERY_INTERFACE_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/vector.h b/drivers/gpu/drm/amd/dal/include/vector.h
+new file mode 100644
+index 0000000..8233b7c
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/vector.h
+@@ -0,0 +1,150 @@
++/*
++ * 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_VECTOR_H__
++#define __DAL_VECTOR_H__
++
++struct vector {
++ uint8_t *container;
++ uint32_t struct_size;
++ uint32_t count;
++ uint32_t capacity;
++ struct dc_context *ctx;
++};
++
++bool dal_vector_construct(
++ struct vector *vector,
++ struct dc_context *ctx,
++ uint32_t capacity,
++ uint32_t struct_size);
++
++struct vector *dal_vector_create(
++ struct dc_context *ctx,
++ uint32_t capacity,
++ uint32_t struct_size);
++
++/* 'initial_value' is optional. If initial_value not supplied,
++ * each "structure" in the vector will contain zeros by default. */
++struct vector *dal_vector_presized_create(
++ struct dc_context *ctx,
++ uint32_t size,
++ void *initial_value,
++ uint32_t struct_size);
++
++void dal_vector_destruct(
++ struct vector *vector);
++
++void dal_vector_destroy(
++ struct vector **vector);
++
++uint32_t dal_vector_get_count(
++ const struct vector *vector);
++
++/* dal_vector_insert_at
++ * reallocate container if necessary
++ * then shell items at right and insert
++ * return if the container modified
++ * do not check that index belongs to container
++ * since the function is private and index is going to be calculated
++ * either with by function or as get_count+1 */
++bool dal_vector_insert_at(
++ struct vector *vector,
++ const void *what,
++ uint32_t position);
++
++bool dal_vector_append(
++ struct vector *vector,
++ const void *item);
++
++/* operator[] */
++void *dal_vector_at_index(
++ const struct vector *vector,
++ uint32_t index);
++
++void dal_vector_set_at_index(
++ const struct vector *vector,
++ const void *what,
++ uint32_t index);
++
++/* create a clone (copy) of a vector */
++struct vector *dal_vector_clone(
++ const struct vector *vector_other);
++
++/* dal_vector_remove_at_index
++ * Shifts elements on the right from remove position to the left,
++ * removing an element at position by overwrite means*/
++bool dal_vector_remove_at_index(
++ struct vector *vector,
++ uint32_t index);
++
++uint32_t dal_vector_capacity(const struct vector *vector);
++
++bool dal_vector_reserve(struct vector *vector, uint32_t capacity);
++
++void dal_vector_clear(struct vector *vector);
++
++/***************************************************************************
++ * Macro definitions of TYPE-SAFE versions of vector set/get functions.
++ ***************************************************************************/
++
++#define DAL_VECTOR_INSERT_AT(vector_type, type_t) \
++ static bool vector_type##_vector_insert_at( \
++ struct vector *vector, \
++ type_t what, \
++ uint32_t position) \
++{ \
++ return dal_vector_insert_at(vector, what, position); \
++}
++
++#define DAL_VECTOR_APPEND(vector_type, type_t) \
++ static bool vector_type##_vector_append( \
++ struct vector *vector, \
++ type_t item) \
++{ \
++ return dal_vector_append(vector, item); \
++}
++
++/* Note: "type_t" is the ONLY token accepted by "checkpatch.pl" and by
++ * "checkcommit" as *return type*.
++ * For uniformity reasons "type_t" is used for all type-safe macro
++ * definitions here. */
++#define DAL_VECTOR_AT_INDEX(vector_type, type_t) \
++ static type_t vector_type##_vector_at_index( \
++ const struct vector *vector, \
++ uint32_t index) \
++{ \
++ return dal_vector_at_index(vector, index); \
++}
++
++#define DAL_VECTOR_SET_AT_INDEX(vector_type, type_t) \
++ static void vector_type##_vector_set_at_index( \
++ const struct vector *vector, \
++ type_t what, \
++ uint32_t index) \
++{ \
++ dal_vector_set_at_index(vector, what, index); \
++}
++
++#endif /* __DAL_VECTOR_H__ */
+diff --git a/drivers/gpu/drm/amd/dal/include/video_csc_types.h b/drivers/gpu/drm/amd/dal/include/video_csc_types.h
+new file mode 100644
+index 0000000..c229f5a
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/video_csc_types.h
+@@ -0,0 +1,135 @@
++/*
++ * 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_VIDEO_CSC_TYPES_H__
++#define __DAL_VIDEO_CSC_TYPES_H__
++
++#include "video_gamma_types.h"
++
++enum ovl_alpha_blending_mode {
++ OVL_ALPHA_PER_PIXEL_GRPH_ALPHA_MODE = 0,
++ OVL_ALPHA_PER_PIXEL_OVL_ALPHA_MODE
++};
++
++enum ovl_color_space {
++ OVL_COLOR_SPACE_UNKNOWN = 0,
++ OVL_COLOR_SPACE_RGB,
++ OVL_COLOR_SPACE_YUV601,
++ OVL_COLOR_SPACE_YUV709
++};
++
++enum ovl_surface_format {
++ OVL_SURFACE_FORMAT_UNKNOWN = 0,
++ OVL_SURFACE_FORMAT_YUY2,
++ OVL_SURFACE_FORMAT_UYVY,
++ OVL_SURFACE_FORMAT_RGB565,
++ OVL_SURFACE_FORMAT_RGB555,
++ OVL_SURFACE_FORMAT_RGB32,
++ OVL_SURFACE_FORMAT_YUV444,
++ OVL_SURFACE_FORMAT_RGB32_2101010
++};
++
++struct ovl_color_adjust_option {
++ uint32_t ALLOW_OVL_RGB_ADJUST:1;
++ uint32_t ALLOW_OVL_TEMPERATURE:1;
++ uint32_t FULL_RANGE:1; /* 0 for limited range it'is default for YUV */
++ uint32_t OVL_MATRIX:1;
++ uint32_t RESERVED:28;
++};
++
++struct overlay_adjust_item {
++ int32_t adjust; /* InInteger */
++ int32_t adjust_divider;
++};
++
++enum overlay_csc_adjust_type {
++ OVERLAY_CSC_ADJUST_TYPE_BYPASS = 0,
++ OVERLAY_CSC_ADJUST_TYPE_HW, /* without adjustments */
++ OVERLAY_CSC_ADJUST_TYPE_SW /* use adjustments */
++};
++
++enum overlay_gamut_adjust_type {
++ OVERLAY_GAMUT_ADJUST_TYPE_BYPASS = 0,
++ OVERLAY_GAMUT_ADJUST_TYPE_SW /* use adjustments */
++};
++
++#define TEMPERATURE_MATRIX_SIZE 9
++#define MAXTRIX_SIZE TEMPERATURE_MAXTRIX_SIZE
++#define MAXTRIX_SIZE_WITH_OFFSET 12
++
++/* overlay adjustment input */
++union ovl_csc_flag {
++ uint32_t u_all;
++ struct {
++ uint32_t CONFIG_IS_CHANGED:1;
++ uint32_t RESERVED:31;
++ } bits;
++};
++
++struct ovl_csc_adjustment {
++ enum ovl_color_space ovl_cs;
++ struct ovl_color_adjust_option ovl_option;
++ enum dc_color_depth display_color_depth;
++ uint32_t lb_color_depth;
++ enum pixel_format desktop_surface_pixel_format;
++ enum ovl_surface_format ovl_sf;
++ /* API adjustment */
++ struct overlay_adjust_item overlay_brightness;
++ struct overlay_adjust_item overlay_gamma;
++ struct overlay_adjust_item overlay_contrast;
++ struct overlay_adjust_item overlay_saturation;
++ struct overlay_adjust_item overlay_hue; /* unit in degree from API. */
++ int32_t f_temperature[TEMPERATURE_MATRIX_SIZE];
++ uint32_t temperature_divider;
++ /* OEM/Application matrix related. */
++ int32_t matrix[MAXTRIX_SIZE_WITH_OFFSET];
++ uint32_t matrix_divider;
++
++ /* DCE50 parameters */
++ struct regamma_lut regamma;
++ enum overlay_gamma_adjust adjust_gamma_type;
++ enum overlay_csc_adjust_type adjust_csc_type;
++ enum overlay_gamut_adjust_type adjust_gamut_type;
++ union ovl_csc_flag flag;
++
++};
++
++enum ovl_csc_adjust_item {
++ OVERLAY_BRIGHTNESS = 0,
++ OVERLAY_GAMMA,
++ OVERLAY_CONTRAST,
++ OVERLAY_SATURATION,
++ OVERLAY_HUE,
++ OVERLAY_ALPHA,
++ OVERLAY_ALPHA_PER_PIX,
++ OVERLAY_COLOR_TEMPERATURE
++};
++
++struct input_csc_matrix {
++ enum color_space color_space;
++ uint16_t regval[12];
++};
++
++#endif
+diff --git a/drivers/gpu/drm/amd/dal/include/video_gamma_types.h b/drivers/gpu/drm/amd/dal/include/video_gamma_types.h
+new file mode 100644
+index 0000000..dc294b6
+--- /dev/null
++++ b/drivers/gpu/drm/amd/dal/include/video_gamma_types.h
+@@ -0,0 +1,56 @@
++/*
++ * 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_VIDEO_GAMMA_TYPES_H__
++#define __DAL_VIDEO_GAMMA_TYPES_H__
++
++#include "set_mode_types.h"
++
++enum overlay_gamma_adjust {
++ OVERLAY_GAMMA_ADJUST_BYPASS,
++ OVERLAY_GAMMA_ADJUST_HW, /* without adjustments */
++ OVERLAY_GAMMA_ADJUST_SW /* use adjustments */
++
++};
++
++union video_gamma_flag {
++ struct {
++ uint32_t CONFIG_IS_CHANGED:1;
++ uint32_t RESERVED:31;
++ } bits;
++ uint32_t u_all;
++};
++
++struct overlay_gamma_parameters {
++ union video_gamma_flag flag;
++ int32_t ovl_gamma_cont;
++ enum overlay_gamma_adjust adjust_type;
++ enum pixel_format desktop_surface;
++ struct regamma_lut regamma;
++
++ /* here we grow with parameters if necessary */
++};
++
++#endif
+--
+2.7.4
+