Merge tag 'drm-for-v4.15-amd-dc' of git://people.freedesktop.org/~airlied/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Nov 2017 22:34:42 +0000 (14:34 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 17 Nov 2017 22:34:42 +0000 (14:34 -0800)
Pull amdgpu DC display code for Vega from Dave Airlie:
 "This is the pull request for the AMD DC (display code) layer which is
  a requirement to program the display engines on the new Vega and Raven
  based GPUs. It also contains support for all amdgpu supported GPUs
  (CIK, VI, Polaris), which has to be enabled. It is also a kms atomic
  modesetting compatible driver (unlike the current in-tree display
  code).

  I've kept it separate from drm-next because it may have some things
  that cause you to reject it.

  Background story:

  AMD have an internal team creating a shared OS codebase for display at
  hw bring up time using information from their hardware teams. This
  process doesn't lead to the most Linux friendly/looking code but we
  have worked together on cleaning a lot of it up and dealing with
  sparse/smatch/checkpatch, and having their team internally adhere to
  Linux coding standards.

  This tree is a complete history rebased since they started opening it,
  we decided not to squash it down as the history may have some value.
  Some of the commits therefore might not reach kernel standards, and we
  are steadily training people in AMD to better write commit msgs.

  There is a major bunch of generated bandwidth calculation and
  verification code that comes from their hardware team. On Vega and
  before this is float calculations, on Raven (DCN10) this is double
  based. They do the required things to do FP in the kernel, and I could
  understand this might raise some issues. Rewriting the bandwidth would
  be a major undertaken in reverification, it's non-trivial to work out
  if a display can handle the complete set of mode information thrown at
  it.

  Future story:

  There is a TODO list with this, and it address most of the remaining
  things that would be nice to refine/remove. The DCN10 code is still
  under development internally and they push out a lot of patches quite
  regularly and are supporting this code base with their display team. I
  think we've reached the point where keeping it out of tree is going to
  motivate distributions to start carrying the code, so I'd prefer we
  get it in tree. I think this code is slightly better than STAGING
  quality but not massively so, I'd really like to see that float/double
  magic gone and fixed point used, but AMD don't seem to think the
  accuracy and revalidation of the code is worth the effort"

* tag 'drm-for-v4.15-amd-dc' of git://people.freedesktop.org/~airlied/linux: (1110 commits)
  drm/amd/display: fix MST link training fail division by 0
  drm/amd/display: Fix formatting for null pointer dereference fix
  drm/amd/display: Remove dangling planes on dc commit state
  drm/amd/display: add flip_immediate to commit update for stream
  drm/amd/display: Miss register MST encoder cbs
  drm/amd/display: Fix warnings on S3 resume
  drm/amd/display: use num_timing_generator instead of pipe_count
  drm/amd/display: use configurable FBC option in dm
  drm/amd/display: fix AZ clock not enabled before program AZ endpoint
  amdgpu/dm: Don't use DRM_ERROR in amdgpu_dm_atomic_check
  amd/display: Fix potential null dereference in dce_calcs.c
  amdgpu/dm: Remove unused forward declaration
  drm/amdgpu: Remove unused dc_stream from amdgpu_crtc
  amdgpu/dc: Fix double unlock in amdgpu_dm_commit_planes
  amdgpu/dc: Fix missing null checks in amdgpu_dm.c
  amdgpu/dc: Fix potential null dereferences in amdgpu_dm.c
  amdgpu/dc: fix more indentation warnings
  amdgpu/dc: handle allocation failures in dc_commit_planes_to_stream.
  amdgpu/dc: fix indentation warning from smatch.
  amdgpu/dc: fix non-ansi function decls.
  ...

368 files changed:
Documentation/gpu/todo.rst
drivers/gpu/drm/amd/amdgpu/Kconfig
drivers/gpu/drm/amd/amdgpu/Makefile
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_cgs.c
drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.c
drivers/gpu/drm/amd/amdgpu/amdgpu_display.h [new file with mode: 0644]
drivers/gpu/drm/amd/amdgpu/amdgpu_dpm.h
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c
drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c
drivers/gpu/drm/amd/amdgpu/amdgpu_mode.h
drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c
drivers/gpu/drm/amd/amdgpu/cik.c
drivers/gpu/drm/amd/amdgpu/soc15.c
drivers/gpu/drm/amd/amdgpu/vi.c
drivers/gpu/drm/amd/display/Kconfig [new file with mode: 0644]
drivers/gpu/drm/amd/display/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/TODO [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/conversion.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/conversion.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/fixpt31_32.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/fixpt32_32.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/grph_object_id.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/log_helpers.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/logger.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/logger.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/basics/vector.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser2.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser_helper.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser_interface.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/bios_parser_types_internal2.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/command_table.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/command_table.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/command_table2.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/command_table2.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/command_table_helper.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/command_table_helper.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/dce110/command_table_helper_dce110.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper2_dce112.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/dce112/command_table_helper_dce112.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/bios/dce80/command_table_helper_dce80.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/bw_fixed.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/custom_float.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_debug.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_link.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_resource.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_sink.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_stream.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/core/dc_surface.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dc_bios_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dc_ddc_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dc_dp_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dc_helper.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dc_hw_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dc_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_abm.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_abm.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_audio.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_audio.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_clocks.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_clocks.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_hwseq.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_ipp.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_ipp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_mem_input.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_opp.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_opp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_scl_filters.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_transform.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce/dce_transform.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce100/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce100/dce100_hw_sequencer.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_compressor.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_mem_input_v.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_csc_v.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_regamma_v.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_v.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_opp_v.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_timing_generator_v.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce110/dce110_transform_v.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce112/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce112/dce112_compressor.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce112/dce112_hw_sequencer.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce120/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce120/dce120_hw_sequencer.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce120/dce120_resource.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce120/dce120_timing_generator.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/dce80_compressor.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/dce80_compressor.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/dce80_hw_sequencer.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/dce80_resource.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dce80/dce80_timing_generator.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_cm_common.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_cm.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_dpp_dscl.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_ipp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_opp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dm_helpers.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dm_pp_smu.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dm_services.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dm_services_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/dc_features.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_mode_enums.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_mode_lib.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_calc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_calc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/display_rq_dlg_helpers.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/dml_common_defs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/dml_inline_defs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/dml/soc_bounding_box.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_factory_dce110.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_translate_dce110.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce110/hw_translate_dce110.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_factory_dce120.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce120/hw_translate_dce120.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_factory_dce80.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dce80/hw_translate_dce80.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_factory_dcn10.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/dcn10/hw_translate_dcn10.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/ddc_regs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_factory_diag.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_translate_diag.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/diagnostics/hw_translate_diag.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/gpio_base.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/gpio_regs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/gpio_service.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hpd_regs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_ddc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_factory.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_gpio.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_gpio.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_hpd.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/gpio/hw_translate.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/aux_engine.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce100/i2caux_dce100.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce110/aux_engine_dce110.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_hw_engine_dce110.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2c_sw_engine_dce110.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce110/i2caux_dce110.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce112/i2caux_dce112.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce120/i2caux_dce120.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_hw_engine_dce80.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2c_sw_engine_dce80.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dce80/i2caux_dce80.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/dcn10/i2caux_dcn10.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/diagnostics/i2caux_diag.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/engine.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/engine_base.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2c_engine.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2c_generic_hw_engine.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2c_hw_engine.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2c_sw_engine.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2caux.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/i2caux/i2caux.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/bw_fixed.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/clock_source.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/compressor.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/core_status.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/core_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/custom_float.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/dc_link_ddc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/dce_calcs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/abm.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/audio.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/display_clock.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/dmcu.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/dpp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/gpio.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/ipp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/mem_input.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/opp.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw/transform.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/link_hwss.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/reg_helper.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/inc/resource.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/dce110/irq_service_dce110.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/dce120/irq_service_dce120.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/dce80/irq_service_dce80.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/dcn10/irq_service_dcn10.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/irq_service.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq/irq_service.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/irq_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/os_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/virtual/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/dc/virtual/virtual_stream_encoder.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/audio_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/bios_parser_interface.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/bios_parser_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/dal_asic_id.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/dal_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/ddc_service_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/dpcd_defs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/fixed31_32.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/fixed32_32.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/gpio_interface.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/gpio_service_interface.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/gpio_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/grph_object_defs.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/grph_object_id.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/i2caux_interface.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/irq_service_interface.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/link_service_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/logger_interface.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/logger_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/set_mode_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/signal_types.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/include/vector.h [new file with mode: 0644]
drivers/gpu/drm/amd/display/modules/freesync/Makefile [new file with mode: 0644]
drivers/gpu/drm/amd/display/modules/freesync/freesync.c [new file with mode: 0644]
drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h [new file with mode: 0644]
drivers/gpu/drm/amd/include/asic_reg/raven1/DCN/dcn_1_0_offset.h
drivers/gpu/drm/amd/include/asic_reg/raven1/DCN/dcn_1_0_sh_mask.h
drivers/gpu/drm/amd/include/asic_reg/vega10/DC/dce_12_0_offset.h
drivers/gpu/drm/amd/include/asic_reg/vega10/DC/dce_12_0_sh_mask.h
include/drm/drm_dp_helper.h

index 96f8ec7dbe4edb054664a9b8048530928182017b..36625aa66c27672c00219e1283d4ecb034913e40 100644 (file)
@@ -409,5 +409,15 @@ those drivers as simple as possible, so lots of room for refactoring:
 
 Contact: Noralf Trønnes, Daniel Vetter
 
+AMD DC Display Driver
+---------------------
+
+AMD DC is the display driver for AMD devices starting with Vega. There has been
+a bunch of progress cleaning it up but there's still plenty of work to be done.
+
+See drivers/gpu/drm/amd/display/TODO for tasks.
+
+Contact: Harry Wentland, Alex Deucher
+
 Outside DRM
 ===========
index 26682454a4463dd36b3c1ffdbd66bdb666c04488..e8af1f5e8a7981bdac82c4262c3c8c979cf13799 100644 (file)
@@ -41,3 +41,4 @@ config DRM_AMDGPU_GART_DEBUGFS
          pages. Uses more memory for housekeeping, enable only for debugging.
 
 source "drivers/gpu/drm/amd/acp/Kconfig"
+source "drivers/gpu/drm/amd/display/Kconfig"
index 7fc42e0777705fd6597fb7631aca09f60d9dcf35..78d609123420455a1d8811eaeb6e91ebaa26e626 100644 (file)
@@ -4,13 +4,19 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 FULL_AMD_PATH=$(src)/..
+DISPLAY_FOLDER_NAME=display
+FULL_AMD_DISPLAY_PATH = $(FULL_AMD_PATH)/$(DISPLAY_FOLDER_NAME)
 
 ccflags-y := -I$(FULL_AMD_PATH)/include/asic_reg \
        -I$(FULL_AMD_PATH)/include \
        -I$(FULL_AMD_PATH)/amdgpu \
        -I$(FULL_AMD_PATH)/scheduler \
        -I$(FULL_AMD_PATH)/powerplay/inc \
-       -I$(FULL_AMD_PATH)/acp/include
+       -I$(FULL_AMD_PATH)/acp/include \
+       -I$(FULL_AMD_DISPLAY_PATH) \
+       -I$(FULL_AMD_DISPLAY_PATH)/include \
+       -I$(FULL_AMD_DISPLAY_PATH)/dc \
+       -I$(FULL_AMD_DISPLAY_PATH)/amdgpu_dm
 
 amdgpu-y := amdgpu_drv.o
 
@@ -133,4 +139,13 @@ include $(FULL_AMD_PATH)/powerplay/Makefile
 
 amdgpu-y += $(AMD_POWERPLAY_FILES)
 
+ifneq ($(CONFIG_DRM_AMD_DC),)
+
+RELATIVE_AMD_DISPLAY_PATH = ../$(DISPLAY_FOLDER_NAME)
+include $(FULL_AMD_DISPLAY_PATH)/Makefile
+
+amdgpu-y += $(AMD_DISPLAY_FILES)
+
+endif
+
 obj-$(CONFIG_DRM_AMDGPU)+= amdgpu.o
index cbcb6a153abae61810f1223e4080a2f18af60706..5afaf6016b4a654f552c5a7439bfac8e3425ddc6 100644 (file)
@@ -66,6 +66,7 @@
 #include "amdgpu_vce.h"
 #include "amdgpu_vcn.h"
 #include "amdgpu_mn.h"
+#include "amdgpu_dm.h"
 
 #include "gpu_scheduler.h"
 #include "amdgpu_virt.h"
@@ -101,6 +102,8 @@ extern int amdgpu_vm_fragment_size;
 extern int amdgpu_vm_fault_stop;
 extern int amdgpu_vm_debug;
 extern int amdgpu_vm_update_mode;
+extern int amdgpu_dc;
+extern int amdgpu_dc_log;
 extern int amdgpu_sched_jobs;
 extern int amdgpu_sched_hw_submission;
 extern int amdgpu_no_evict;
@@ -1535,6 +1538,7 @@ struct amdgpu_device {
        /* display */
        bool                            enable_virtual_display;
        struct amdgpu_mode_info         mode_info;
+       /* For pre-DCE11. DCE11 and later are in "struct amdgpu_device->dm" */
        struct work_struct              hotplug_work;
        struct amdgpu_irq_src           crtc_irq;
        struct amdgpu_irq_src           pageflip_irq;
@@ -1590,6 +1594,9 @@ struct amdgpu_device {
        /* GDS */
        struct amdgpu_gds               gds;
 
+       /* display related functionality */
+       struct amdgpu_display_manager dm;
+
        struct amdgpu_ip_block          ip_blocks[AMDGPU_MAX_IP_NUM];
        int                             num_ip_blocks;
        struct mutex    mn_lock;
@@ -1653,6 +1660,9 @@ void amdgpu_mm_wdoorbell(struct amdgpu_device *adev, u32 index, u32 v);
 u64 amdgpu_mm_rdoorbell64(struct amdgpu_device *adev, u32 index);
 void amdgpu_mm_wdoorbell64(struct amdgpu_device *adev, u32 index, u64 v);
 
+bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type);
+bool amdgpu_device_has_dc_support(struct amdgpu_device *adev);
+
 /*
  * Registers read & write functions.
  */
@@ -1911,5 +1921,11 @@ int amdgpu_cs_find_mapping(struct amdgpu_cs_parser *parser,
                           uint64_t addr, struct amdgpu_bo **bo,
                           struct amdgpu_bo_va_mapping **mapping);
 
+#if defined(CONFIG_DRM_AMD_DC)
+int amdgpu_dm_display_resume(struct amdgpu_device *adev );
+#else
+static inline int amdgpu_dm_display_resume(struct amdgpu_device *adev) { return 0; }
+#endif
+
 #include "amdgpu_object.h"
 #endif
index a7afe553e0a165361e5be1a2cdee46c28ed1e92f..f2b72c7c6857e66a5a4b14d216973c5c1ea8aa1a 100644 (file)
@@ -911,10 +911,6 @@ static int amdgpu_cgs_get_active_displays_info(struct cgs_device *cgs_device,
                                          struct cgs_display_info *info)
 {
        CGS_FUNC_ADEV;
-       struct amdgpu_crtc *amdgpu_crtc;
-       struct drm_device *ddev = adev->ddev;
-       struct drm_crtc *crtc;
-       uint32_t line_time_us, vblank_lines;
        struct cgs_mode_info *mode_info;
 
        if (info == NULL)
@@ -928,30 +924,43 @@ static int amdgpu_cgs_get_active_displays_info(struct cgs_device *cgs_device,
                mode_info->ref_clock = adev->clock.spll.reference_freq;
        }
 
-       if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
-               list_for_each_entry(crtc,
-                               &ddev->mode_config.crtc_list, head) {
-                       amdgpu_crtc = to_amdgpu_crtc(crtc);
-                       if (crtc->enabled) {
-                               info->active_display_mask |= (1 << amdgpu_crtc->crtc_id);
-                               info->display_count++;
-                       }
-                       if (mode_info != NULL &&
-                               crtc->enabled && amdgpu_crtc->enabled &&
-                               amdgpu_crtc->hw_mode.clock) {
-                               line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
-                                                       amdgpu_crtc->hw_mode.clock;
-                               vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
-                                                       amdgpu_crtc->hw_mode.crtc_vdisplay +
-                                                       (amdgpu_crtc->v_border * 2);
-                               mode_info->vblank_time_us = vblank_lines * line_time_us;
-                               mode_info->refresh_rate = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
-                               mode_info->ref_clock = adev->clock.spll.reference_freq;
-                               mode_info = NULL;
+       if (!amdgpu_device_has_dc_support(adev)) {
+               struct amdgpu_crtc *amdgpu_crtc;
+               struct drm_device *ddev = adev->ddev;
+               struct drm_crtc *crtc;
+               uint32_t line_time_us, vblank_lines;
+
+               if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) {
+                       list_for_each_entry(crtc,
+                                       &ddev->mode_config.crtc_list, head) {
+                               amdgpu_crtc = to_amdgpu_crtc(crtc);
+                               if (crtc->enabled) {
+                                       info->active_display_mask |= (1 << amdgpu_crtc->crtc_id);
+                                       info->display_count++;
+                               }
+                               if (mode_info != NULL &&
+                                       crtc->enabled && amdgpu_crtc->enabled &&
+                                       amdgpu_crtc->hw_mode.clock) {
+                                       line_time_us = (amdgpu_crtc->hw_mode.crtc_htotal * 1000) /
+                                                               amdgpu_crtc->hw_mode.clock;
+                                       vblank_lines = amdgpu_crtc->hw_mode.crtc_vblank_end -
+                                                               amdgpu_crtc->hw_mode.crtc_vdisplay +
+                                                               (amdgpu_crtc->v_border * 2);
+                                       mode_info->vblank_time_us = vblank_lines * line_time_us;
+                                       mode_info->refresh_rate = drm_mode_vrefresh(&amdgpu_crtc->hw_mode);
+                                       mode_info->ref_clock = adev->clock.spll.reference_freq;
+                                       mode_info = NULL;
+                               }
                        }
                }
+       } else {
+               info->display_count = adev->pm.pm_display_cfg.num_display;
+               if (mode_info != NULL) {
+                       mode_info->vblank_time_us = adev->pm.pm_display_cfg.min_vblank_time;
+                       mode_info->refresh_rate = adev->pm.pm_display_cfg.vrefresh;
+                       mode_info->ref_clock = adev->clock.spll.reference_freq;
+               }
        }
-
        return 0;
 }
 
index efcacb827de73cab22755eb6c13ec05b76cd6bd8..2d792cdc094cd60e86542c0ed5380c3590198fc2 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/debugfs.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
+#include <drm/drm_atomic_helper.h>
 #include <drm/amdgpu_drm.h>
 #include <linux/vgaarb.h>
 #include <linux/vga_switcheroo.h>
@@ -2046,6 +2047,52 @@ static void amdgpu_device_detect_sriov_bios(struct amdgpu_device *adev)
        }
 }
 
+bool amdgpu_device_asic_has_dc_support(enum amd_asic_type asic_type)
+{
+       switch (asic_type) {
+#if defined(CONFIG_DRM_AMD_DC)
+       case CHIP_BONAIRE:
+       case CHIP_HAWAII:
+       case CHIP_KAVERI:
+       case CHIP_CARRIZO:
+       case CHIP_STONEY:
+       case CHIP_POLARIS11:
+       case CHIP_POLARIS10:
+       case CHIP_POLARIS12:
+       case CHIP_TONGA:
+       case CHIP_FIJI:
+#if defined(CONFIG_DRM_AMD_DC_PRE_VEGA)
+               return amdgpu_dc != 0;
+#endif
+       case CHIP_KABINI:
+       case CHIP_MULLINS:
+               return amdgpu_dc > 0;
+       case CHIP_VEGA10:
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+       case CHIP_RAVEN:
+#endif
+               return amdgpu_dc != 0;
+#endif
+       default:
+               return false;
+       }
+}
+
+/**
+ * amdgpu_device_has_dc_support - check if dc is supported
+ *
+ * @adev: amdgpu_device_pointer
+ *
+ * Returns true for supported, false for not supported
+ */
+bool amdgpu_device_has_dc_support(struct amdgpu_device *adev)
+{
+       if (amdgpu_sriov_vf(adev))
+               return false;
+
+       return amdgpu_device_asic_has_dc_support(adev->asic_type);
+}
+
 /**
  * amdgpu_device_init - initialize the driver
  *
@@ -2100,7 +2147,6 @@ int amdgpu_device_init(struct amdgpu_device *adev,
        adev->audio_endpt_rreg = &amdgpu_block_invalid_rreg;
        adev->audio_endpt_wreg = &amdgpu_block_invalid_wreg;
 
-
        DRM_INFO("initializing kernel modesetting (%s 0x%04X:0x%04X 0x%04X:0x%04X 0x%02X).\n",
                 amdgpu_asic_name[adev->asic_type], pdev->vendor, pdev->device,
                 pdev->subsystem_vendor, pdev->subsystem_device, pdev->revision);
@@ -2242,7 +2288,8 @@ int amdgpu_device_init(struct amdgpu_device *adev,
                        goto failed;
                }
                /* init i2c buses */
-               amdgpu_atombios_i2c_init(adev);
+               if (!amdgpu_device_has_dc_support(adev))
+                       amdgpu_atombios_i2c_init(adev);
        }
 
        /* Fence driver */
@@ -2378,7 +2425,8 @@ void amdgpu_device_fini(struct amdgpu_device *adev)
        adev->accel_working = false;
        cancel_delayed_work_sync(&adev->late_init_work);
        /* free i2c buses */
-       amdgpu_i2c_fini(adev);
+       if (!amdgpu_device_has_dc_support(adev))
+               amdgpu_i2c_fini(adev);
        amdgpu_atombios_fini(adev);
        kfree(adev->bios);
        adev->bios = NULL;
@@ -2429,12 +2477,14 @@ int amdgpu_device_suspend(struct drm_device *dev, bool suspend, bool fbcon)
 
        drm_kms_helper_poll_disable(dev);
 
-       /* turn off display hw */
-       drm_modeset_lock_all(dev);
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+       if (!amdgpu_device_has_dc_support(adev)) {
+               /* turn off display hw */
+               drm_modeset_lock_all(dev);
+               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_OFF);
+               }
+               drm_modeset_unlock_all(dev);
        }
-       drm_modeset_unlock_all(dev);
 
        amdgpu_amdkfd_suspend(adev);
 
@@ -2577,13 +2627,25 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
 
        /* blat the mode back in */
        if (fbcon) {
-               drm_helper_resume_force_mode(dev);
-               /* turn on display hw */
-               drm_modeset_lock_all(dev);
-               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+               if (!amdgpu_device_has_dc_support(adev)) {
+                       /* pre DCE11 */
+                       drm_helper_resume_force_mode(dev);
+
+                       /* turn on display hw */
+                       drm_modeset_lock_all(dev);
+                       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+                       }
+                       drm_modeset_unlock_all(dev);
+               } else {
+                       /*
+                        * There is no equivalent atomic helper to turn on
+                        * display, so we defined our own function for this,
+                        * once suspend resume is supported by the atomic
+                        * framework this will be reworked
+                        */
+                       amdgpu_dm_display_resume(adev);
                }
-               drm_modeset_unlock_all(dev);
        }
 
        drm_kms_helper_poll_enable(dev);
@@ -2600,7 +2662,10 @@ int amdgpu_device_resume(struct drm_device *dev, bool resume, bool fbcon)
 #ifdef CONFIG_PM
        dev->dev->power.disable_depth++;
 #endif
-       drm_helper_hpd_irq_event(dev);
+       if (!amdgpu_device_has_dc_support(adev))
+               drm_helper_hpd_irq_event(dev);
+       else
+               drm_kms_helper_hotplug_event(dev);
 #ifdef CONFIG_PM
        dev->dev->power.disable_depth--;
 #endif
@@ -2900,6 +2965,7 @@ give_up_reset:
  */
 int amdgpu_gpu_reset(struct amdgpu_device *adev)
 {
+       struct drm_atomic_state *state = NULL;
        int i, r;
        int resched;
        bool need_full_reset, vram_lost = false;
@@ -2913,6 +2979,9 @@ int amdgpu_gpu_reset(struct amdgpu_device *adev)
 
        /* block TTM */
        resched = ttm_bo_lock_delayed_workqueue(&adev->mman.bdev);
+       /* store modesetting */
+       if (amdgpu_device_has_dc_support(adev))
+               state = drm_atomic_helper_suspend(adev->ddev);
 
        /* block scheduler */
        for (i = 0; i < AMDGPU_MAX_RINGS; ++i) {
@@ -3029,7 +3098,11 @@ out:
                }
        }
 
-       drm_helper_resume_force_mode(adev->ddev);
+       if (amdgpu_device_has_dc_support(adev)) {
+               r = drm_atomic_helper_resume(adev->ddev, state);
+               amdgpu_dm_display_resume(adev);
+       } else
+               drm_helper_resume_force_mode(adev->ddev);
 
        ttm_bo_unlock_delayed_workqueue(&adev->mman.bdev, resched);
        if (r) {
index 6ad243293a78b163f0c0269ad2eba78623a60811..138beb550a5897dcaefeadedc9d3bb238ed4f2c1 100644 (file)
@@ -518,7 +518,7 @@ amdgpu_framebuffer_init(struct drm_device *dev,
        return 0;
 }
 
-static struct drm_framebuffer *
+struct drm_framebuffer *
 amdgpu_user_framebuffer_create(struct drm_device *dev,
                               struct drm_file *file_priv,
                               const struct drm_mode_fb_cmd2 *mode_cmd)
@@ -556,7 +556,7 @@ amdgpu_user_framebuffer_create(struct drm_device *dev,
        return &amdgpu_fb->base;
 }
 
-static void amdgpu_output_poll_changed(struct drm_device *dev)
+void amdgpu_output_poll_changed(struct drm_device *dev)
 {
        struct amdgpu_device *adev = dev->dev_private;
        amdgpu_fb_output_poll_changed(adev);
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_display.h
new file mode 100644 (file)
index 0000000..3cc0ef0
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#ifndef __AMDGPU_DISPLAY_H__
+#define __AMDGPU_DISPLAY_H__
+
+struct drm_framebuffer *
+amdgpu_user_framebuffer_create(struct drm_device *dev,
+                                                      struct drm_file *file_priv,
+                                                          const struct drm_mode_fb_cmd2 *mode_cmd);
+
+void amdgpu_output_poll_changed(struct drm_device *dev);
+
+#endif
index 7279fb5c3abc4472a08d4495aaba105abeba40ed..56caaeee6fea3a6f376338e5a09042b79c67bf9d 100644 (file)
@@ -433,7 +433,7 @@ struct amdgpu_pm {
        uint32_t                fw_version;
        uint32_t                pcie_gen_mask;
        uint32_t                pcie_mlw_mask;
-       struct amd_pp_display_configuration pm_display_cfg;/* set by DAL */
+       struct amd_pp_display_configuration pm_display_cfg;/* set by dc */
 };
 
 #define R600_SSTU_DFLT                               0
index dd2f060d62a86306500ed9cb3dc55915d4e7afda..ec96bb1f9eafbc374cdad09c85f96da8e8d1bbad 100644 (file)
@@ -106,6 +106,8 @@ int amdgpu_vm_debug = 0;
 int amdgpu_vram_page_split = 512;
 int amdgpu_vm_update_mode = -1;
 int amdgpu_exp_hw_support = 0;
+int amdgpu_dc = -1;
+int amdgpu_dc_log = 0;
 int amdgpu_sched_jobs = 32;
 int amdgpu_sched_hw_submission = 2;
 int amdgpu_no_evict = 0;
@@ -211,6 +213,12 @@ module_param_named(vram_page_split, amdgpu_vram_page_split, int, 0444);
 MODULE_PARM_DESC(exp_hw_support, "experimental hw support (1 = enable, 0 = disable (default))");
 module_param_named(exp_hw_support, amdgpu_exp_hw_support, int, 0444);
 
+MODULE_PARM_DESC(dc, "Display Core driver (1 = enable, 0 = disable, -1 = auto (default))");
+module_param_named(dc, amdgpu_dc, int, 0444);
+
+MODULE_PARM_DESC(dc, "Display Core Log Level (0 = minimal (default), 1 = chatty");
+module_param_named(dc_log, amdgpu_dc_log, int, 0444);
+
 MODULE_PARM_DESC(sched_jobs, "the max number of jobs supported in the sw queue (default 32)");
 module_param_named(sched_jobs, amdgpu_sched_jobs, int, 0444);
 
@@ -518,15 +526,15 @@ static const struct pci_device_id pciidlist[] = {
        {0x1002, 0x6997, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
        {0x1002, 0x699F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_POLARIS12},
        /* Vega 10 */
-       {0x1002, 0x6860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6861, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6862, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6863, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6864, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6867, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x6868, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x686c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
-       {0x1002, 0x687f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10|AMD_EXP_HW_SUPPORT},
+       {0x1002, 0x6860, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
+       {0x1002, 0x6861, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
+       {0x1002, 0x6862, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
+       {0x1002, 0x6863, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
+       {0x1002, 0x6864, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
+       {0x1002, 0x6867, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
+       {0x1002, 0x6868, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
+       {0x1002, 0x686c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
+       {0x1002, 0x687f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_VEGA10},
        /* Raven */
        {0x1002, 0x15dd, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RAVEN|AMD_IS_APU|AMD_EXP_HW_SUPPORT},
 
index 562930b17a6d7fdf3157b2f2f9013d7f074a105f..90fa8e8bc6fb3db21d57fe390cf0e2d0f38ec5e8 100644 (file)
    this contains a helper + a amdgpu fb
    the helper contains a pointer to amdgpu framebuffer baseclass.
 */
-struct amdgpu_fbdev {
-       struct drm_fb_helper helper;
-       struct amdgpu_framebuffer rfb;
-       struct amdgpu_device *adev;
-};
 
 static int
 amdgpufb_open(struct fb_info *info, int user)
@@ -353,7 +348,8 @@ int amdgpu_fbdev_init(struct amdgpu_device *adev)
        drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
 
        /* disable all the possible outputs/crtcs before entering KMS mode */
-       drm_helper_disable_unused_functions(adev->ddev);
+       if (!amdgpu_device_has_dc_support(adev))
+               drm_helper_disable_unused_functions(adev->ddev);
 
        drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
        return 0;
index 538e5f27d1205809ec293dee0aae8da5b5711e8b..47c5ce9807db28f8f9e6906ca53338cbee24742a 100644 (file)
 
 #include <linux/pm_runtime.h>
 
+#ifdef CONFIG_DRM_AMD_DC
+#include "amdgpu_dm_irq.h"
+#endif
+
 #define AMDGPU_WAIT_IDLE_TIMEOUT 200
 
 /*
@@ -221,15 +225,6 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
 
        spin_lock_init(&adev->irq.lock);
 
-       if (!adev->enable_virtual_display)
-               /* Disable vblank irqs aggressively for power-saving */
-               adev->ddev->vblank_disable_immediate = true;
-
-       r = drm_vblank_init(adev->ddev, adev->mode_info.num_crtc);
-       if (r) {
-               return r;
-       }
-
        /* enable msi */
        adev->irq.msi_enabled = false;
 
@@ -241,7 +236,21 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
                }
        }
 
-       INIT_WORK(&adev->hotplug_work, amdgpu_hotplug_work_func);
+       if (!amdgpu_device_has_dc_support(adev)) {
+               if (!adev->enable_virtual_display)
+                       /* Disable vblank irqs aggressively for power-saving */
+                       /* XXX: can this be enabled for DC? */
+                       adev->ddev->vblank_disable_immediate = true;
+
+               r = drm_vblank_init(adev->ddev, adev->mode_info.num_crtc);
+               if (r)
+                       return r;
+
+               /* pre DCE11 */
+               INIT_WORK(&adev->hotplug_work,
+                               amdgpu_hotplug_work_func);
+       }
+
        INIT_WORK(&adev->reset_work, amdgpu_irq_reset_work_func);
 
        adev->irq.installed = true;
index 6f0b26dae3b0009ee127929186ef43d140b87bcb..720139e182a3d8be1cb2015630e3519f96785d8a 100644 (file)
@@ -1030,7 +1030,7 @@ const struct drm_ioctl_desc amdgpu_ioctls_kms[] = {
        DRM_IOCTL_DEF_DRV(AMDGPU_GEM_METADATA, amdgpu_gem_metadata_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(AMDGPU_GEM_VA, amdgpu_gem_va_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(AMDGPU_GEM_OP, amdgpu_gem_op_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
-       DRM_IOCTL_DEF_DRV(AMDGPU_GEM_USERPTR, amdgpu_gem_userptr_ioctl, DRM_AUTH|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(AMDGPU_GEM_USERPTR, amdgpu_gem_userptr_ioctl, DRM_AUTH|DRM_RENDER_ALLOW)
 };
 const int amdgpu_max_kms_ioctl = ARRAY_SIZE(amdgpu_ioctls_kms);
 
index 2af2678ddaf6254948d529f647f87bb1ef74a959..ffde1e9666e8c00ee603f98cb4d81453974c7ff9 100644 (file)
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_plane_helper.h>
+#include <drm/drm_fb_helper.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/hrtimer.h>
 #include "amdgpu_irq.h"
 
+#include <drm/drm_dp_mst_helper.h>
+#include "modules/inc/mod_freesync.h"
+
 struct amdgpu_bo;
 struct amdgpu_device;
 struct amdgpu_encoder;
@@ -53,9 +57,13 @@ struct amdgpu_hpd;
 #define to_amdgpu_connector(x) container_of(x, struct amdgpu_connector, base)
 #define to_amdgpu_encoder(x) container_of(x, struct amdgpu_encoder, base)
 #define to_amdgpu_framebuffer(x) container_of(x, struct amdgpu_framebuffer, base)
+#define to_amdgpu_plane(x)     container_of(x, struct amdgpu_plane, base)
+
+#define to_dm_plane_state(x)   container_of(x, struct dm_plane_state, base);
 
 #define AMDGPU_MAX_HPD_PINS 6
 #define AMDGPU_MAX_CRTCS 6
+#define AMDGPU_MAX_PLANES 6
 #define AMDGPU_MAX_AFMT_BLOCKS 9
 
 enum amdgpu_rmx_type {
@@ -292,6 +300,30 @@ struct amdgpu_display_funcs {
                              uint16_t connector_object_id,
                              struct amdgpu_hpd *hpd,
                              struct amdgpu_router *router);
+       /* it is used to enter or exit into free sync mode */
+       int (*notify_freesync)(struct drm_device *dev, void *data,
+                              struct drm_file *filp);
+       /* it is used to allow enablement of freesync mode */
+       int (*set_freesync_property)(struct drm_connector *connector,
+                                    struct drm_property *property,
+                                    uint64_t val);
+
+
+};
+
+struct amdgpu_framebuffer {
+       struct drm_framebuffer base;
+       struct drm_gem_object *obj;
+
+       /* caching for later use */
+       uint64_t address;
+};
+
+struct amdgpu_fbdev {
+       struct drm_fb_helper helper;
+       struct amdgpu_framebuffer rfb;
+       struct list_head fbdev_list;
+       struct amdgpu_device *adev;
 };
 
 struct amdgpu_mode_info {
@@ -299,6 +331,7 @@ struct amdgpu_mode_info {
        struct card_info *atom_card_info;
        bool mode_config_initialized;
        struct amdgpu_crtc *crtcs[AMDGPU_MAX_CRTCS];
+       struct amdgpu_plane *planes[AMDGPU_MAX_PLANES];
        struct amdgpu_afmt *afmt[AMDGPU_MAX_AFMT_BLOCKS];
        /* DVI-I properties */
        struct drm_property *coherent_mode_property;
@@ -328,6 +361,7 @@ struct amdgpu_mode_info {
        int                     num_dig; /* number of dig blocks */
        int                     disp_priority;
        const struct amdgpu_display_funcs *funcs;
+       const enum drm_plane_type *plane_type;
 };
 
 #define AMDGPU_MAX_BL_LEVEL 0xFF
@@ -400,6 +434,14 @@ struct amdgpu_crtc {
        /* for virtual dce */
        struct hrtimer vblank_timer;
        enum amdgpu_interrupt_state vsync_timer_enabled;
+
+       int otg_inst;
+       struct drm_pending_vblank_event *event;
+};
+
+struct amdgpu_plane {
+       struct drm_plane base;
+       enum drm_plane_type plane_type;
 };
 
 struct amdgpu_encoder_atom_dig {
@@ -489,6 +531,19 @@ enum amdgpu_connector_dither {
        AMDGPU_FMT_DITHER_ENABLE = 1,
 };
 
+struct amdgpu_dm_dp_aux {
+       struct drm_dp_aux aux;
+       struct ddc_service *ddc_service;
+};
+
+struct amdgpu_i2c_adapter {
+       struct i2c_adapter base;
+
+       struct ddc_service *ddc_service;
+};
+
+#define TO_DM_AUX(x) container_of((x), struct amdgpu_dm_dp_aux, aux)
+
 struct amdgpu_connector {
        struct drm_connector base;
        uint32_t connector_id;
@@ -500,6 +555,14 @@ struct amdgpu_connector {
        /* we need to mind the EDID between detect
           and get modes due to analog/digital/tvencoder */
        struct edid *edid;
+       /* number of modes generated from EDID at 'dc_sink' */
+       int num_modes;
+       /* The 'old' sink - before an HPD.
+        * The 'current' sink is in dc_link->sink. */
+       struct dc_sink *dc_sink;
+       struct dc_link *dc_link;
+       struct dc_sink *dc_em_sink;
+       const struct dc_stream *stream;
        void *con_priv;
        bool dac_load_detect;
        bool detected_by_load; /* if the connection status was determined by load */
@@ -510,11 +573,39 @@ struct amdgpu_connector {
        enum amdgpu_connector_audio audio;
        enum amdgpu_connector_dither dither;
        unsigned pixelclock_for_modeset;
+
+       struct drm_dp_mst_topology_mgr mst_mgr;
+       struct amdgpu_dm_dp_aux dm_dp_aux;
+       struct drm_dp_mst_port *port;
+       struct amdgpu_connector *mst_port;
+       struct amdgpu_encoder *mst_encoder;
+       struct semaphore mst_sem;
+
+       /* TODO see if we can merge with ddc_bus or make a dm_connector */
+       struct amdgpu_i2c_adapter *i2c;
+
+       /* Monitor range limits */
+       int min_vfreq ;
+       int max_vfreq ;
+       int pixel_clock_mhz;
+
+       /*freesync caps*/
+       struct mod_freesync_caps caps;
+
+       struct mutex hpd_lock;
+
 };
 
-struct amdgpu_framebuffer {
-       struct drm_framebuffer base;
-       struct drm_gem_object *obj;
+/* TODO: start to use this struct and remove same field from base one */
+struct amdgpu_mst_connector {
+       struct amdgpu_connector base;
+
+       struct drm_dp_mst_topology_mgr mst_mgr;
+       struct amdgpu_dm_dp_aux dm_dp_aux;
+       struct drm_dp_mst_port *port;
+       struct amdgpu_connector *mst_port;
+       bool is_mst_connector;
+       struct amdgpu_encoder *mst_encoder;
 };
 
 #define ENCODER_MODE_IS_DP(em) (((em) == ATOM_ENCODER_MODE_DP) || \
index a59e04f3eeba787ec29452e10a66e886038f8905..d6df5728df7fca04648daa9677bc03d8dafd830f 100644 (file)
@@ -1466,7 +1466,7 @@ void amdgpu_pm_compute_clocks(struct amdgpu_device *adev)
                        list_for_each_entry(crtc,
                                            &ddev->mode_config.crtc_list, head) {
                                amdgpu_crtc = to_amdgpu_crtc(crtc);
-                               if (crtc->enabled) {
+                               if (amdgpu_crtc->enabled) {
                                        adev->pm.dpm.new_active_crtcs |= (1 << amdgpu_crtc->crtc_id);
                                        adev->pm.dpm.new_active_crtc_count++;
                                }
index 567c4a5cf90cc2ce927c151c2665d4d2ab5a8395..793b1470284d67b13c68954481520f7ab3ef635e 100644 (file)
@@ -65,6 +65,7 @@
 #include "oss/oss_2_0_d.h"
 #include "oss/oss_2_0_sh_mask.h"
 
+#include "amdgpu_dm.h"
 #include "amdgpu_amdkfd.h"
 #include "amdgpu_powerplay.h"
 #include "dce_virtual.h"
@@ -1900,6 +1901,10 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display)
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v8_2_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v7_2_ip_block);
@@ -1914,6 +1919,10 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display)
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v8_5_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v7_3_ip_block);
@@ -1928,6 +1937,10 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display)
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v8_1_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v7_1_ip_block);
@@ -1943,6 +1956,10 @@ int cik_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display)
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v8_3_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v7_2_ip_block);
index 3ca9d114f630e67e3e7f23b1318e550b49c6f2e4..4e67fe1e79553d610c79819b525ecb881c13d059 100644 (file)
@@ -532,6 +532,12 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
                        amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display || amdgpu_sriov_vf(adev))
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#else
+#      warning "Enable CONFIG_DRM_AMD_DC for display support on SOC15."
+#endif
                amdgpu_ip_block_add(adev, &gfx_v9_0_ip_block);
                amdgpu_ip_block_add(adev, &sdma_v4_0_ip_block);
                amdgpu_ip_block_add(adev, &uvd_v7_0_ip_block);
@@ -545,6 +551,12 @@ int soc15_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display || amdgpu_sriov_vf(adev))
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#else
+#      warning "Enable CONFIG_DRM_AMD_DC for display support on SOC15."
+#endif
                amdgpu_ip_block_add(adev, &gfx_v9_0_ip_block);
                amdgpu_ip_block_add(adev, &sdma_v4_0_ip_block);
                amdgpu_ip_block_add(adev, &vcn_v1_0_ip_block);
index f3cfef48aa996aab7760a39a8327d503951b1c5b..3a4c2fa7e36dbcf258f9a54c851828951e203f62 100644 (file)
@@ -77,6 +77,7 @@
 #endif
 #include "dce_virtual.h"
 #include "mxgpu_vi.h"
+#include "amdgpu_dm.h"
 
 /*
  * Indirect registers accessor
@@ -1502,6 +1503,10 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display || amdgpu_sriov_vf(adev))
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v10_1_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v8_0_ip_block);
@@ -1518,6 +1523,10 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display || amdgpu_sriov_vf(adev))
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v10_0_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v8_0_ip_block);
@@ -1536,6 +1545,10 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display)
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v11_2_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v8_0_ip_block);
@@ -1550,6 +1563,10 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display)
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v11_0_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v8_0_ip_block);
@@ -1567,6 +1584,10 @@ int vi_set_ip_blocks(struct amdgpu_device *adev)
                amdgpu_ip_block_add(adev, &amdgpu_pp_ip_block);
                if (adev->enable_virtual_display)
                        amdgpu_ip_block_add(adev, &dce_virtual_ip_block);
+#if defined(CONFIG_DRM_AMD_DC)
+               else if (amdgpu_device_has_dc_support(adev))
+                       amdgpu_ip_block_add(adev, &dm_ip_block);
+#endif
                else
                        amdgpu_ip_block_add(adev, &dce_v11_0_ip_block);
                amdgpu_ip_block_add(adev, &gfx_v8_1_ip_block);
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
new file mode 100644 (file)
index 0000000..ec3285f
--- /dev/null
@@ -0,0 +1,45 @@
+menu "Display Engine Configuration"
+       depends on DRM && DRM_AMDGPU
+
+config DRM_AMD_DC
+       bool "AMD DC - Enable new display engine"
+       default y
+       help
+         Choose this option if you want to use the new display engine
+         support for AMDGPU. This adds required support for Vega and
+         Raven ASICs.
+
+config DRM_AMD_DC_PRE_VEGA
+       bool "DC support for Polaris and older ASICs"
+       default n
+       help
+         Choose this option to enable the new DC support for older asics
+         by default. This includes Polaris, Carrizo, Tonga, Bonaire,
+         and Hawaii.
+
+config DRM_AMD_DC_FBC
+       bool "AMD FBC - Enable Frame Buffer Compression"
+       depends on DRM_AMD_DC
+       help
+         Choose this option if you want to use frame buffer compression
+         support.
+         This is a power optimisation feature, check its availability
+         on your hardware before enabling this option.
+
+
+config DRM_AMD_DC_DCN1_0
+       bool "DCN 1.0 Raven family"
+       depends on DRM_AMD_DC && X86
+       help
+         Choose this option if you want to have
+         RV family for display engine
+
+config DEBUG_KERNEL_DC
+       bool "Enable kgdb break in DC"
+       depends on DRM_AMD_DC
+       help
+         Choose this option
+         if you want to hit
+         kdgb_break in assert.
+
+endmenu
diff --git a/drivers/gpu/drm/amd/display/Makefile b/drivers/gpu/drm/amd/display/Makefile
new file mode 100644 (file)
index 0000000..8ba37dd
--- /dev/null
@@ -0,0 +1,22 @@
+#
+# 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_DISPLAY_PATH)
+
+subdir-ccflags-y += -I$(AMDDALPATH)/ -I$(AMDDALPATH)/include
+
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc/inc/hw
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/inc
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/modules/freesync
+
+#TODO: remove when Timing Sync feature is complete
+subdir-ccflags-y += -DBUILD_FEATURE_TIMING_SYNC=0
+
+DAL_LIBS = amdgpu_dm dc        modules/freesync
+
+AMD_DAL = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/,$(DAL_LIBS)))
+
+include $(AMD_DAL)
diff --git a/drivers/gpu/drm/amd/display/TODO b/drivers/gpu/drm/amd/display/TODO
new file mode 100644 (file)
index 0000000..4646467
--- /dev/null
@@ -0,0 +1,107 @@
+===============================================================================
+TODOs
+===============================================================================
+
+1. Base this on drm-next - WIP
+
+
+2. Cleanup commit history
+
+
+3. WIP - Drop page flip helper and use DRM's version
+
+
+4. DONE - Flatten all DC objects
+    * dc_stream/core_stream/stream should just be dc_stream
+    * Same for other DC objects
+
+    "Is there any major reason to keep all those abstractions?
+
+    Could you collapse everything into struct dc_stream?
+
+    I haven't looked recently but I didn't get the impression there was a
+    lot of design around what was public/protected, more whatever needed
+    to be used by someone else was in public."
+    ~ Dave Airlie
+
+
+5. DONE - Rename DC objects to align more with DRM
+    * dc_surface -> dc_plane_state
+    * dc_stream -> dc_stream_state
+
+
+6. DONE - Per-plane and per-stream validation
+
+
+7. WIP - Per-plane and per-stream commit
+
+
+8. WIP - Split pipe_ctx into plane and stream resource structs
+
+
+9. Attach plane and stream reources to state object instead of validate_context
+
+
+10. Remove dc_edid_caps and drm_helpers_parse_edid_caps
+    * Use drm_display_info instead
+    * Remove DC's edid quirks and rely on DRM's quirks (add quirks if needed)
+
+    "Making sure you use the sink-specific helper libraries and kernel
+    subsystems, since there's really no good reason to have 2nd
+    implementation of those in the kernel. Looks likes that's done for mst
+    and edid parsing. There's still a bit a midlayer feeling to the edid
+    parsing side (e.g. dc_edid_caps and dm_helpers_parse_edid_caps, I
+    think it'd be much better if you convert that over to reading stuff
+    from drm_display_info and if needed, push stuff into the core). Also,
+    I can't come up with a good reason why DC needs all this (except to
+    reimplement half of our edid quirk table, which really isn't a good
+    idea). Might be good if you put this onto the list of things to fix
+    long-term, but imo not a blocker. Definitely make sure new stuff
+    doesn't slip in (i.e. if you start adding edid quirks to DC instead of
+    the drm core, refactoring to use the core edid stuff was pointless)."
+    ~ Daniel Vetter
+
+
+11. Remove dc/i2caux. This folder can be somewhat misleading. It's basically an
+overy complicated HW programming function for sendind and receiving i2c/aux
+commands. We can greatly simplify that and move it into dc/dceXYZ like other
+HW blocks.
+
+12. drm_modeset_lock in MST should no longer be needed in recent kernels
+    * Adopt appropriate locking scheme
+
+13. get_modes and best_encoder callbacks look a bit funny. Can probably rip out
+a few indirections, and consider removing entirely and using the
+drm_atomic_helper_best_encoder default behaviour.
+
+14. core/dc_debug.c, consider switching to the atomic state debug helpers and
+moving all your driver state printing into the various atomic_print_state
+callbacks. There's also plans to expose this stuff in a standard way across all
+drivers, to make debugging userspace compositors easier across different hw.
+
+15. Move DP/HDMI dual mode adaptors to drm_dp_dual_mode_helper.c. See
+dal_ddc_service_i2c_query_dp_dual_mode_adaptor.
+
+16. Move to core SCDC helpers (I think those are new since initial DC review).
+
+17. There's still a pretty massive layer cake around dp aux and DPCD handling,
+with like 3 levels of abstraction and using your own structures instead of the
+stuff in drm_dp_helper.h. drm_dp_helper.h isn't really great and already has 2
+incompatible styles, just means more reasons not to add a third (or well third
+one gets to do the cleanup refactor).
+
+18. There's a pile of sink handling code, both for DP and HDMI where I didn't
+immediately recognize the standard. I think long term it'd be best for the drm
+subsystem if we try to move as much of that into helpers/core as possible, and
+share it with drivers. But that's a very long term goal, and by far not just an
+issue with DC - other drivers, especially around DP sink handling, are equally
+guilty.
+
+19. The DC logger is still a rather sore thing, but I know that the DRM_DEBUG
+stuff just isn't up to the challenges either. We need to figure out something
+that integrates better with DRM and linux debug printing, while not being
+useless with filtering output. dynamic debug printing might be an option.
+
+20. Use kernel i2c device to program HDMI retimer. Some boards have an HDMI
+retimer that we need to program to pass PHY compliance. Currently that's
+bypassing the i2c device and goes directly to HW. This should be changed.
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile
new file mode 100644 (file)
index 0000000..4699e47
--- /dev/null
@@ -0,0 +1,17 @@
+#
+# Makefile for the 'dm' sub-component of DAL.
+# It provides the control and status of dm blocks.
+
+
+
+AMDGPUDM = amdgpu_dm.o amdgpu_dm_irq.o amdgpu_dm_mst_types.o
+
+ifneq ($(CONFIG_DRM_AMD_DC),)
+AMDGPUDM += amdgpu_dm_services.o amdgpu_dm_helpers.o
+endif
+
+subdir-ccflags-y += -I$(FULL_AMD_DISPLAY_PATH)/dc
+
+AMDGPU_DM = $(addprefix $(AMDDALPATH)/amdgpu_dm/,$(AMDGPUDM))
+
+AMD_DISPLAY_FILES += $(AMDGPU_DM)
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
new file mode 100644 (file)
index 0000000..889ed24
--- /dev/null
@@ -0,0 +1,4925 @@
+/*
+ * 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 "dm_services_types.h"
+#include "dc.h"
+#include "dc/inc/core_types.h"
+
+#include "vid.h"
+#include "amdgpu.h"
+#include "amdgpu_display.h"
+#include "atom.h"
+#include "amdgpu_dm.h"
+#include "amdgpu_pm.h"
+
+#include "amd_shared.h"
+#include "amdgpu_dm_irq.h"
+#include "dm_helpers.h"
+#include "dm_services_types.h"
+#include "amdgpu_dm_mst_types.h"
+
+#include "ivsrcid/ivsrcid_vislands30.h"
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/version.h>
+#include <linux/types.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_dp_mst_helper.h>
+#include <drm/drm_fb_helper.h>
+#include <drm/drm_edid.h>
+
+#include "modules/inc/mod_freesync.h"
+
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+#include "ivsrcid/irqsrcs_dcn_1_0.h"
+
+#include "raven1/DCN/dcn_1_0_offset.h"
+#include "raven1/DCN/dcn_1_0_sh_mask.h"
+#include "vega10/soc15ip.h"
+
+#include "soc15_common.h"
+#endif
+
+#include "modules/inc/mod_freesync.h"
+
+#include "i2caux_interface.h"
+
+/* basic init/fini API */
+static int amdgpu_dm_init(struct amdgpu_device *adev);
+static void amdgpu_dm_fini(struct amdgpu_device *adev);
+
+/* initializes drm_device display related structures, based on the information
+ * provided by DAL. The drm strcutures are: drm_crtc, drm_connector,
+ * drm_encoder, drm_mode_config
+ *
+ * Returns 0 on success
+ */
+static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev);
+/* removes and deallocates the drm structures, created by the above function */
+static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm);
+
+static void
+amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector);
+
+static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
+                               struct amdgpu_plane *aplane,
+                               unsigned long possible_crtcs);
+static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
+                              struct drm_plane *plane,
+                              uint32_t link_index);
+static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
+                                   struct amdgpu_dm_connector *amdgpu_dm_connector,
+                                   uint32_t link_index,
+                                   struct amdgpu_encoder *amdgpu_encoder);
+static int amdgpu_dm_encoder_init(struct drm_device *dev,
+                                 struct amdgpu_encoder *aencoder,
+                                 uint32_t link_index);
+
+static int amdgpu_dm_connector_get_modes(struct drm_connector *connector);
+
+static int amdgpu_dm_atomic_commit(struct drm_device *dev,
+                                  struct drm_atomic_state *state,
+                                  bool nonblock);
+
+static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state);
+
+static int amdgpu_dm_atomic_check(struct drm_device *dev,
+                                 struct drm_atomic_state *state);
+
+
+
+
+static const enum drm_plane_type dm_plane_type_default[AMDGPU_MAX_PLANES] = {
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_PRIMARY,
+};
+
+static const enum drm_plane_type dm_plane_type_carizzo[AMDGPU_MAX_PLANES] = {
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_OVERLAY,/* YUV Capable Underlay */
+};
+
+static const enum drm_plane_type dm_plane_type_stoney[AMDGPU_MAX_PLANES] = {
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_OVERLAY, /* YUV Capable Underlay */
+};
+
+/*
+ * dm_vblank_get_counter
+ *
+ * @brief
+ * Get counter for number of vertical blanks
+ *
+ * @param
+ * struct amdgpu_device *adev - [in] desired amdgpu device
+ * int disp_idx - [in] which CRTC to get the counter from
+ *
+ * @return
+ * Counter for vertical blanks
+ */
+static u32 dm_vblank_get_counter(struct amdgpu_device *adev, int crtc)
+{
+       if (crtc >= adev->mode_info.num_crtc)
+               return 0;
+       else {
+               struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc];
+               struct dm_crtc_state *acrtc_state = to_dm_crtc_state(
+                               acrtc->base.state);
+
+
+               if (acrtc_state->stream == NULL) {
+                       DRM_ERROR("dc_stream_state is NULL for crtc '%d'!\n",
+                                 crtc);
+                       return 0;
+               }
+
+               return dc_stream_get_vblank_counter(acrtc_state->stream);
+       }
+}
+
+static int dm_crtc_get_scanoutpos(struct amdgpu_device *adev, int crtc,
+                                 u32 *vbl, u32 *position)
+{
+       uint32_t v_blank_start, v_blank_end, h_position, v_position;
+
+       if ((crtc < 0) || (crtc >= adev->mode_info.num_crtc))
+               return -EINVAL;
+       else {
+               struct amdgpu_crtc *acrtc = adev->mode_info.crtcs[crtc];
+               struct dm_crtc_state *acrtc_state = to_dm_crtc_state(
+                                               acrtc->base.state);
+
+               if (acrtc_state->stream ==  NULL) {
+                       DRM_ERROR("dc_stream_state is NULL for crtc '%d'!\n",
+                                 crtc);
+                       return 0;
+               }
+
+               /*
+                * TODO rework base driver to use values directly.
+                * for now parse it back into reg-format
+                */
+               dc_stream_get_scanoutpos(acrtc_state->stream,
+                                        &v_blank_start,
+                                        &v_blank_end,
+                                        &h_position,
+                                        &v_position);
+
+               *position = v_position | (h_position << 16);
+               *vbl = v_blank_start | (v_blank_end << 16);
+       }
+
+       return 0;
+}
+
+static bool dm_is_idle(void *handle)
+{
+       /* XXX todo */
+       return true;
+}
+
+static int dm_wait_for_idle(void *handle)
+{
+       /* XXX todo */
+       return 0;
+}
+
+static bool dm_check_soft_reset(void *handle)
+{
+       return false;
+}
+
+static int dm_soft_reset(void *handle)
+{
+       /* XXX todo */
+       return 0;
+}
+
+static struct amdgpu_crtc *
+get_crtc_by_otg_inst(struct amdgpu_device *adev,
+                    int otg_inst)
+{
+       struct drm_device *dev = adev->ddev;
+       struct drm_crtc *crtc;
+       struct amdgpu_crtc *amdgpu_crtc;
+
+       /*
+        * following if is check inherited from both functions where this one is
+        * used now. Need to be checked why it could happen.
+        */
+       if (otg_inst == -1) {
+               WARN_ON(1);
+               return adev->mode_info.crtcs[0];
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               amdgpu_crtc = to_amdgpu_crtc(crtc);
+
+               if (amdgpu_crtc->otg_inst == otg_inst)
+                       return amdgpu_crtc;
+       }
+
+       return NULL;
+}
+
+static void dm_pflip_high_irq(void *interrupt_params)
+{
+       struct amdgpu_crtc *amdgpu_crtc;
+       struct common_irq_params *irq_params = interrupt_params;
+       struct amdgpu_device *adev = irq_params->adev;
+       unsigned long flags;
+
+       amdgpu_crtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_PFLIP);
+
+       /* IRQ could occur when in initial stage */
+       /*TODO work and BO cleanup */
+       if (amdgpu_crtc == NULL) {
+               DRM_DEBUG_DRIVER("CRTC is null, returning.\n");
+               return;
+       }
+
+       spin_lock_irqsave(&adev->ddev->event_lock, flags);
+
+       if (amdgpu_crtc->pflip_status != AMDGPU_FLIP_SUBMITTED){
+               DRM_DEBUG_DRIVER("amdgpu_crtc->pflip_status = %d !=AMDGPU_FLIP_SUBMITTED(%d) on crtc:%d[%p] \n",
+                                                amdgpu_crtc->pflip_status,
+                                                AMDGPU_FLIP_SUBMITTED,
+                                                amdgpu_crtc->crtc_id,
+                                                amdgpu_crtc);
+               spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+               return;
+       }
+
+
+       /* wakeup usersapce */
+       if (amdgpu_crtc->event) {
+               /* Update to correct count/ts if racing with vblank irq */
+               drm_crtc_accurate_vblank_count(&amdgpu_crtc->base);
+
+               drm_crtc_send_vblank_event(&amdgpu_crtc->base, amdgpu_crtc->event);
+
+               /* page flip completed. clean up */
+               amdgpu_crtc->event = NULL;
+
+       } else
+               WARN_ON(1);
+
+       amdgpu_crtc->pflip_status = AMDGPU_FLIP_NONE;
+       spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+
+       DRM_DEBUG_DRIVER("%s - crtc :%d[%p], pflip_stat:AMDGPU_FLIP_NONE\n",
+                                       __func__, amdgpu_crtc->crtc_id, amdgpu_crtc);
+
+       drm_crtc_vblank_put(&amdgpu_crtc->base);
+}
+
+static void dm_crtc_high_irq(void *interrupt_params)
+{
+       struct common_irq_params *irq_params = interrupt_params;
+       struct amdgpu_device *adev = irq_params->adev;
+       uint8_t crtc_index = 0;
+       struct amdgpu_crtc *acrtc;
+
+       acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
+
+       if (acrtc)
+               crtc_index = acrtc->crtc_id;
+
+       drm_handle_vblank(adev->ddev, crtc_index);
+}
+
+static int dm_set_clockgating_state(void *handle,
+                 enum amd_clockgating_state state)
+{
+       return 0;
+}
+
+static int dm_set_powergating_state(void *handle,
+                 enum amd_powergating_state state)
+{
+       return 0;
+}
+
+/* Prototypes of private functions */
+static int dm_early_init(void* handle);
+
+static void hotplug_notify_work_func(struct work_struct *work)
+{
+       struct amdgpu_display_manager *dm = container_of(work, struct amdgpu_display_manager, mst_hotplug_work);
+       struct drm_device *dev = dm->ddev;
+
+       drm_kms_helper_hotplug_event(dev);
+}
+
+#if defined(CONFIG_DRM_AMD_DC_FBC)
+#include "dal_asic_id.h"
+/* Allocate memory for FBC compressed data  */
+/* TODO: Dynamic allocation */
+#define AMDGPU_FBC_SIZE    (3840 * 2160 * 4)
+
+static void amdgpu_dm_initialize_fbc(struct amdgpu_device *adev)
+{
+       int r;
+       struct dm_comressor_info *compressor = &adev->dm.compressor;
+
+       if (!compressor->bo_ptr) {
+               r = amdgpu_bo_create_kernel(adev, AMDGPU_FBC_SIZE, PAGE_SIZE,
+                               AMDGPU_GEM_DOMAIN_VRAM, &compressor->bo_ptr,
+                               &compressor->gpu_addr, &compressor->cpu_addr);
+
+               if (r)
+                       DRM_ERROR("DM: Failed to initialize fbc\n");
+       }
+
+}
+#endif
+
+
+/* Init display KMS
+ *
+ * Returns 0 on success
+ */
+static int amdgpu_dm_init(struct amdgpu_device *adev)
+{
+       struct dc_init_data init_data;
+       adev->dm.ddev = adev->ddev;
+       adev->dm.adev = adev;
+
+       /* Zero all the fields */
+       memset(&init_data, 0, sizeof(init_data));
+
+       /* initialize DAL's lock (for SYNC context use) */
+       spin_lock_init(&adev->dm.dal_lock);
+
+       /* initialize DAL's mutex */
+       mutex_init(&adev->dm.dal_mutex);
+
+       if(amdgpu_dm_irq_init(adev)) {
+               DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
+               goto error;
+       }
+
+       init_data.asic_id.chip_family = adev->family;
+
+       init_data.asic_id.pci_revision_id = adev->rev_id;
+       init_data.asic_id.hw_internal_rev = adev->external_rev_id;
+
+       init_data.asic_id.vram_width = adev->mc.vram_width;
+       /* TODO: initialize init_data.asic_id.vram_type here!!!! */
+       init_data.asic_id.atombios_base_address =
+               adev->mode_info.atom_context->bios;
+
+       init_data.driver = adev;
+
+       adev->dm.cgs_device = amdgpu_cgs_create_device(adev);
+
+       if (!adev->dm.cgs_device) {
+               DRM_ERROR("amdgpu: failed to create cgs device.\n");
+               goto error;
+       }
+
+       init_data.cgs_device = adev->dm.cgs_device;
+
+       adev->dm.dal = NULL;
+
+       init_data.dce_environment = DCE_ENV_PRODUCTION_DRV;
+
+       if (amdgpu_dc_log)
+               init_data.log_mask = DC_DEFAULT_LOG_MASK;
+       else
+               init_data.log_mask = DC_MIN_LOG_MASK;
+
+#if defined(CONFIG_DRM_AMD_DC_FBC)
+       if (adev->family == FAMILY_CZ)
+               amdgpu_dm_initialize_fbc(adev);
+       init_data.fbc_gpu_addr = adev->dm.compressor.gpu_addr;
+#endif
+       /* Display Core create. */
+       adev->dm.dc = dc_create(&init_data);
+
+       if (adev->dm.dc) {
+               DRM_INFO("Display Core initialized!\n");
+       } else {
+               DRM_INFO("Display Core failed to initialize!\n");
+               goto error;
+       }
+
+       INIT_WORK(&adev->dm.mst_hotplug_work, hotplug_notify_work_func);
+
+       adev->dm.freesync_module = mod_freesync_create(adev->dm.dc);
+       if (!adev->dm.freesync_module) {
+               DRM_ERROR(
+               "amdgpu: failed to initialize freesync_module.\n");
+       } else
+               DRM_DEBUG_DRIVER("amdgpu: freesync_module init done %p.\n",
+                               adev->dm.freesync_module);
+
+       if (amdgpu_dm_initialize_drm_device(adev)) {
+               DRM_ERROR(
+               "amdgpu: failed to initialize sw for display support.\n");
+               goto error;
+       }
+
+       /* Update the actual used number of crtc */
+       adev->mode_info.num_crtc = adev->dm.display_indexes_num;
+
+       /* TODO: Add_display_info? */
+
+       /* TODO use dynamic cursor width */
+       adev->ddev->mode_config.cursor_width = adev->dm.dc->caps.max_cursor_size;
+       adev->ddev->mode_config.cursor_height = adev->dm.dc->caps.max_cursor_size;
+
+       if (drm_vblank_init(adev->ddev, adev->dm.display_indexes_num)) {
+               DRM_ERROR(
+               "amdgpu: failed to initialize sw for display support.\n");
+               goto error;
+       }
+
+       DRM_DEBUG_DRIVER("KMS initialized.\n");
+
+       return 0;
+error:
+       amdgpu_dm_fini(adev);
+
+       return -1;
+}
+
+static void amdgpu_dm_fini(struct amdgpu_device *adev)
+{
+       amdgpu_dm_destroy_drm_device(&adev->dm);
+       /*
+        * TODO: pageflip, vlank interrupt
+        *
+        * amdgpu_dm_irq_fini(adev);
+        */
+
+       if (adev->dm.cgs_device) {
+               amdgpu_cgs_destroy_device(adev->dm.cgs_device);
+               adev->dm.cgs_device = NULL;
+       }
+       if (adev->dm.freesync_module) {
+               mod_freesync_destroy(adev->dm.freesync_module);
+               adev->dm.freesync_module = NULL;
+       }
+       /* DC Destroy TODO: Replace destroy DAL */
+       if (adev->dm.dc)
+               dc_destroy(&adev->dm.dc);
+       return;
+}
+
+static int dm_sw_init(void *handle)
+{
+       return 0;
+}
+
+static int dm_sw_fini(void *handle)
+{
+       return 0;
+}
+
+static int detect_mst_link_for_all_connectors(struct drm_device *dev)
+{
+       struct amdgpu_dm_connector *aconnector;
+       struct drm_connector *connector;
+       int ret = 0;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               aconnector = to_amdgpu_dm_connector(connector);
+               if (aconnector->dc_link->type == dc_connection_mst_branch) {
+                       DRM_DEBUG_DRIVER("DM_MST: starting TM on aconnector: %p [id: %d]\n",
+                                       aconnector, aconnector->base.base.id);
+
+                       ret = drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true);
+                       if (ret < 0) {
+                               DRM_ERROR("DM_MST: Failed to start MST\n");
+                               ((struct dc_link *)aconnector->dc_link)->type = dc_connection_single;
+                               return ret;
+                               }
+                       }
+       }
+
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+       return ret;
+}
+
+static int dm_late_init(void *handle)
+{
+       struct drm_device *dev = ((struct amdgpu_device *)handle)->ddev;
+
+       return detect_mst_link_for_all_connectors(dev);
+}
+
+static void s3_handle_mst(struct drm_device *dev, bool suspend)
+{
+       struct amdgpu_dm_connector *aconnector;
+       struct drm_connector *connector;
+
+       drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                  aconnector = to_amdgpu_dm_connector(connector);
+                  if (aconnector->dc_link->type == dc_connection_mst_branch &&
+                                  !aconnector->mst_port) {
+
+                          if (suspend)
+                                  drm_dp_mst_topology_mgr_suspend(&aconnector->mst_mgr);
+                          else
+                                  drm_dp_mst_topology_mgr_resume(&aconnector->mst_mgr);
+                  }
+       }
+
+       drm_modeset_unlock(&dev->mode_config.connection_mutex);
+}
+
+static int dm_hw_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+       /* Create DAL display manager */
+       amdgpu_dm_init(adev);
+       amdgpu_dm_hpd_init(adev);
+
+       return 0;
+}
+
+static int dm_hw_fini(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       amdgpu_dm_hpd_fini(adev);
+
+       amdgpu_dm_irq_fini(adev);
+       amdgpu_dm_fini(adev);
+       return 0;
+}
+
+static int dm_suspend(void *handle)
+{
+       struct amdgpu_device *adev = handle;
+       struct amdgpu_display_manager *dm = &adev->dm;
+       int ret = 0;
+
+       s3_handle_mst(adev->ddev, true);
+
+       amdgpu_dm_irq_suspend(adev);
+
+       WARN_ON(adev->dm.cached_state);
+       adev->dm.cached_state = drm_atomic_helper_suspend(adev->ddev);
+
+       dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D3);
+
+       return ret;
+}
+
+static struct amdgpu_dm_connector *
+amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
+                                            struct drm_crtc *crtc)
+{
+       uint32_t i;
+       struct drm_connector_state *new_con_state;
+       struct drm_connector *connector;
+       struct drm_crtc *crtc_from_state;
+
+       for_each_new_connector_in_state(state, connector, new_con_state, i) {
+               crtc_from_state = new_con_state->crtc;
+
+               if (crtc_from_state == crtc)
+                       return to_amdgpu_dm_connector(connector);
+       }
+
+       return NULL;
+}
+
+static int dm_resume(void *handle)
+{
+       struct amdgpu_device *adev = handle;
+       struct amdgpu_display_manager *dm = &adev->dm;
+
+       /* power on hardware */
+       dc_set_power_state(dm->dc, DC_ACPI_CM_POWER_STATE_D0);
+
+       return 0;
+}
+
+int amdgpu_dm_display_resume(struct amdgpu_device *adev)
+{
+       struct drm_device *ddev = adev->ddev;
+       struct amdgpu_display_manager *dm = &adev->dm;
+       struct amdgpu_dm_connector *aconnector;
+       struct drm_connector *connector;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *new_crtc_state;
+       struct dm_crtc_state *dm_new_crtc_state;
+       struct drm_plane *plane;
+       struct drm_plane_state *new_plane_state;
+       struct dm_plane_state *dm_new_plane_state;
+
+       int ret = 0;
+       int i;
+
+       /* program HPD filter */
+       dc_resume(dm->dc);
+
+       /* On resume we need to  rewrite the MSTM control bits to enamble MST*/
+       s3_handle_mst(ddev, false);
+
+       /*
+        * early enable HPD Rx IRQ, should be done before set mode as short
+        * pulse interrupts are used for MST
+        */
+       amdgpu_dm_irq_resume_early(adev);
+
+       /* Do detection*/
+       list_for_each_entry(connector,
+                       &ddev->mode_config.connector_list, head) {
+               aconnector = to_amdgpu_dm_connector(connector);
+
+               /*
+                * this is the case when traversing through already created
+                * MST connectors, should be skipped
+                */
+               if (aconnector->mst_port)
+                       continue;
+
+               mutex_lock(&aconnector->hpd_lock);
+               dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD);
+               aconnector->dc_sink = NULL;
+               amdgpu_dm_update_connector_after_detect(aconnector);
+               mutex_unlock(&aconnector->hpd_lock);
+       }
+
+       /* Force mode set in atomic comit */
+       for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i)
+               new_crtc_state->active_changed = true;
+
+       /*
+        * atomic_check is expected to create the dc states. We need to release
+        * them here, since they were duplicated as part of the suspend
+        * procedure.
+        */
+       for_each_new_crtc_in_state(adev->dm.cached_state, crtc, new_crtc_state, i) {
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+               if (dm_new_crtc_state->stream) {
+                       WARN_ON(kref_read(&dm_new_crtc_state->stream->refcount) > 1);
+                       dc_stream_release(dm_new_crtc_state->stream);
+                       dm_new_crtc_state->stream = NULL;
+               }
+       }
+
+       for_each_new_plane_in_state(adev->dm.cached_state, plane, new_plane_state, i) {
+               dm_new_plane_state = to_dm_plane_state(new_plane_state);
+               if (dm_new_plane_state->dc_state) {
+                       WARN_ON(kref_read(&dm_new_plane_state->dc_state->refcount) > 1);
+                       dc_plane_state_release(dm_new_plane_state->dc_state);
+                       dm_new_plane_state->dc_state = NULL;
+               }
+       }
+
+       ret = drm_atomic_helper_resume(ddev, adev->dm.cached_state);
+
+       drm_atomic_state_put(adev->dm.cached_state);
+       adev->dm.cached_state = NULL;
+
+       amdgpu_dm_irq_resume_late(adev);
+
+       return ret;
+}
+
+static const struct amd_ip_funcs amdgpu_dm_funcs = {
+       .name = "dm",
+       .early_init = dm_early_init,
+       .late_init = dm_late_init,
+       .sw_init = dm_sw_init,
+       .sw_fini = dm_sw_fini,
+       .hw_init = dm_hw_init,
+       .hw_fini = dm_hw_fini,
+       .suspend = dm_suspend,
+       .resume = dm_resume,
+       .is_idle = dm_is_idle,
+       .wait_for_idle = dm_wait_for_idle,
+       .check_soft_reset = dm_check_soft_reset,
+       .soft_reset = dm_soft_reset,
+       .set_clockgating_state = dm_set_clockgating_state,
+       .set_powergating_state = dm_set_powergating_state,
+};
+
+const struct amdgpu_ip_block_version dm_ip_block =
+{
+       .type = AMD_IP_BLOCK_TYPE_DCE,
+       .major = 1,
+       .minor = 0,
+       .rev = 0,
+       .funcs = &amdgpu_dm_funcs,
+};
+
+
+static struct drm_atomic_state *
+dm_atomic_state_alloc(struct drm_device *dev)
+{
+       struct dm_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
+
+       if (!state)
+               return NULL;
+
+       if (drm_atomic_state_init(dev, &state->base) < 0)
+               goto fail;
+
+       return &state->base;
+
+fail:
+       kfree(state);
+       return NULL;
+}
+
+static void
+dm_atomic_state_clear(struct drm_atomic_state *state)
+{
+       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
+
+       if (dm_state->context) {
+               dc_release_state(dm_state->context);
+               dm_state->context = NULL;
+       }
+
+       drm_atomic_state_default_clear(state);
+}
+
+static void
+dm_atomic_state_alloc_free(struct drm_atomic_state *state)
+{
+       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
+       drm_atomic_state_default_release(state);
+       kfree(dm_state);
+}
+
+static const struct drm_mode_config_funcs amdgpu_dm_mode_funcs = {
+       .fb_create = amdgpu_user_framebuffer_create,
+       .output_poll_changed = amdgpu_output_poll_changed,
+       .atomic_check = amdgpu_dm_atomic_check,
+       .atomic_commit = amdgpu_dm_atomic_commit,
+       .atomic_state_alloc = dm_atomic_state_alloc,
+       .atomic_state_clear = dm_atomic_state_clear,
+       .atomic_state_free = dm_atomic_state_alloc_free
+};
+
+static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
+       .atomic_commit_tail = amdgpu_dm_atomic_commit_tail
+};
+
+static void
+amdgpu_dm_update_connector_after_detect(struct amdgpu_dm_connector *aconnector)
+{
+       struct drm_connector *connector = &aconnector->base;
+       struct drm_device *dev = connector->dev;
+       struct dc_sink *sink;
+
+       /* MST handled by drm_mst framework */
+       if (aconnector->mst_mgr.mst_state == true)
+               return;
+
+
+       sink = aconnector->dc_link->local_sink;
+
+       /* Edid mgmt connector gets first update only in mode_valid hook and then
+        * the connector sink is set to either fake or physical sink depends on link status.
+        * don't do it here if u are during boot
+        */
+       if (aconnector->base.force != DRM_FORCE_UNSPECIFIED
+                       && aconnector->dc_em_sink) {
+
+               /* For S3 resume with headless use eml_sink to fake stream
+                * because on resume connecotr->sink is set ti NULL
+                */
+               mutex_lock(&dev->mode_config.mutex);
+
+               if (sink) {
+                       if (aconnector->dc_sink) {
+                               amdgpu_dm_remove_sink_from_freesync_module(
+                                                               connector);
+                               /* retain and release bellow are used for
+                                * bump up refcount for sink because the link don't point
+                                * to it anymore after disconnect so on next crtc to connector
+                                * reshuffle by UMD we will get into unwanted dc_sink release
+                                */
+                               if (aconnector->dc_sink != aconnector->dc_em_sink)
+                                       dc_sink_release(aconnector->dc_sink);
+                       }
+                       aconnector->dc_sink = sink;
+                       amdgpu_dm_add_sink_to_freesync_module(
+                                               connector, aconnector->edid);
+               } else {
+                       amdgpu_dm_remove_sink_from_freesync_module(connector);
+                       if (!aconnector->dc_sink)
+                               aconnector->dc_sink = aconnector->dc_em_sink;
+                       else if (aconnector->dc_sink != aconnector->dc_em_sink)
+                               dc_sink_retain(aconnector->dc_sink);
+               }
+
+               mutex_unlock(&dev->mode_config.mutex);
+               return;
+       }
+
+       /*
+        * TODO: temporary guard to look for proper fix
+        * if this sink is MST sink, we should not do anything
+        */
+       if (sink && sink->sink_signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
+               return;
+
+       if (aconnector->dc_sink == sink) {
+               /* We got a DP short pulse (Link Loss, DP CTS, etc...).
+                * Do nothing!! */
+               DRM_DEBUG_DRIVER("DCHPD: connector_id=%d: dc_sink didn't change.\n",
+                               aconnector->connector_id);
+               return;
+       }
+
+       DRM_DEBUG_DRIVER("DCHPD: connector_id=%d: Old sink=%p New sink=%p\n",
+               aconnector->connector_id, aconnector->dc_sink, sink);
+
+       mutex_lock(&dev->mode_config.mutex);
+
+       /* 1. Update status of the drm connector
+        * 2. Send an event and let userspace tell us what to do */
+       if (sink) {
+               /* TODO: check if we still need the S3 mode update workaround.
+                * If yes, put it here. */
+               if (aconnector->dc_sink)
+                       amdgpu_dm_remove_sink_from_freesync_module(
+                                                       connector);
+
+               aconnector->dc_sink = sink;
+               if (sink->dc_edid.length == 0) {
+                       aconnector->edid = NULL;
+               } else {
+                       aconnector->edid =
+                               (struct edid *) sink->dc_edid.raw_edid;
+
+
+                       drm_mode_connector_update_edid_property(connector,
+                                       aconnector->edid);
+               }
+               amdgpu_dm_add_sink_to_freesync_module(connector, aconnector->edid);
+
+       } else {
+               amdgpu_dm_remove_sink_from_freesync_module(connector);
+               drm_mode_connector_update_edid_property(connector, NULL);
+               aconnector->num_modes = 0;
+               aconnector->dc_sink = NULL;
+       }
+
+       mutex_unlock(&dev->mode_config.mutex);
+}
+
+static void handle_hpd_irq(void *param)
+{
+       struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
+       struct drm_connector *connector = &aconnector->base;
+       struct drm_device *dev = connector->dev;
+
+       /* In case of failure or MST no need to update connector status or notify the OS
+        * since (for MST case) MST does this in it's own context.
+        */
+       mutex_lock(&aconnector->hpd_lock);
+
+       if (aconnector->fake_enable)
+               aconnector->fake_enable = false;
+
+       if (dc_link_detect(aconnector->dc_link, DETECT_REASON_HPD)) {
+               amdgpu_dm_update_connector_after_detect(aconnector);
+
+
+               drm_modeset_lock_all(dev);
+               dm_restore_drm_connector_state(dev, connector);
+               drm_modeset_unlock_all(dev);
+
+               if (aconnector->base.force == DRM_FORCE_UNSPECIFIED)
+                       drm_kms_helper_hotplug_event(dev);
+       }
+       mutex_unlock(&aconnector->hpd_lock);
+
+}
+
+static void dm_handle_hpd_rx_irq(struct amdgpu_dm_connector *aconnector)
+{
+       uint8_t esi[DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI] = { 0 };
+       uint8_t dret;
+       bool new_irq_handled = false;
+       int dpcd_addr;
+       int dpcd_bytes_to_read;
+
+       const int max_process_count = 30;
+       int process_count = 0;
+
+       const struct dc_link_status *link_status = dc_link_get_status(aconnector->dc_link);
+
+       if (link_status->dpcd_caps->dpcd_rev.raw < 0x12) {
+               dpcd_bytes_to_read = DP_LANE0_1_STATUS - DP_SINK_COUNT;
+               /* DPCD 0x200 - 0x201 for downstream IRQ */
+               dpcd_addr = DP_SINK_COUNT;
+       } else {
+               dpcd_bytes_to_read = DP_PSR_ERROR_STATUS - DP_SINK_COUNT_ESI;
+               /* DPCD 0x2002 - 0x2005 for downstream IRQ */
+               dpcd_addr = DP_SINK_COUNT_ESI;
+       }
+
+       dret = drm_dp_dpcd_read(
+               &aconnector->dm_dp_aux.aux,
+               dpcd_addr,
+               esi,
+               dpcd_bytes_to_read);
+
+       while (dret == dpcd_bytes_to_read &&
+               process_count < max_process_count) {
+               uint8_t retry;
+               dret = 0;
+
+               process_count++;
+
+               DRM_DEBUG_DRIVER("ESI %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+               /* handle HPD short pulse irq */
+               if (aconnector->mst_mgr.mst_state)
+                       drm_dp_mst_hpd_irq(
+                               &aconnector->mst_mgr,
+                               esi,
+                               &new_irq_handled);
+
+               if (new_irq_handled) {
+                       /* ACK at DPCD to notify down stream */
+                       const int ack_dpcd_bytes_to_write =
+                               dpcd_bytes_to_read - 1;
+
+                       for (retry = 0; retry < 3; retry++) {
+                               uint8_t wret;
+
+                               wret = drm_dp_dpcd_write(
+                                       &aconnector->dm_dp_aux.aux,
+                                       dpcd_addr + 1,
+                                       &esi[1],
+                                       ack_dpcd_bytes_to_write);
+                               if (wret == ack_dpcd_bytes_to_write)
+                                       break;
+                       }
+
+                       /* check if there is new irq to be handle */
+                       dret = drm_dp_dpcd_read(
+                               &aconnector->dm_dp_aux.aux,
+                               dpcd_addr,
+                               esi,
+                               dpcd_bytes_to_read);
+
+                       new_irq_handled = false;
+               } else {
+                       break;
+               }
+       }
+
+       if (process_count == max_process_count)
+               DRM_DEBUG_DRIVER("Loop exceeded max iterations\n");
+}
+
+static void handle_hpd_rx_irq(void *param)
+{
+       struct amdgpu_dm_connector *aconnector = (struct amdgpu_dm_connector *)param;
+       struct drm_connector *connector = &aconnector->base;
+       struct drm_device *dev = connector->dev;
+       struct dc_link *dc_link = aconnector->dc_link;
+       bool is_mst_root_connector = aconnector->mst_mgr.mst_state;
+
+       /* TODO:Temporary add mutex to protect hpd interrupt not have a gpio
+        * conflict, after implement i2c helper, this mutex should be
+        * retired.
+        */
+       if (dc_link->type != dc_connection_mst_branch)
+               mutex_lock(&aconnector->hpd_lock);
+
+       if (dc_link_handle_hpd_rx_irq(dc_link, NULL) &&
+                       !is_mst_root_connector) {
+               /* Downstream Port status changed. */
+               if (dc_link_detect(dc_link, DETECT_REASON_HPDRX)) {
+                       amdgpu_dm_update_connector_after_detect(aconnector);
+
+
+                       drm_modeset_lock_all(dev);
+                       dm_restore_drm_connector_state(dev, connector);
+                       drm_modeset_unlock_all(dev);
+
+                       drm_kms_helper_hotplug_event(dev);
+               }
+       }
+       if ((dc_link->cur_link_settings.lane_count != LANE_COUNT_UNKNOWN) ||
+           (dc_link->type == dc_connection_mst_branch))
+               dm_handle_hpd_rx_irq(aconnector);
+
+       if (dc_link->type != dc_connection_mst_branch)
+               mutex_unlock(&aconnector->hpd_lock);
+}
+
+static void register_hpd_handlers(struct amdgpu_device *adev)
+{
+       struct drm_device *dev = adev->ddev;
+       struct drm_connector *connector;
+       struct amdgpu_dm_connector *aconnector;
+       const struct dc_link *dc_link;
+       struct dc_interrupt_params int_params = {0};
+
+       int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
+       int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
+
+       list_for_each_entry(connector,
+                       &dev->mode_config.connector_list, head) {
+
+               aconnector = to_amdgpu_dm_connector(connector);
+               dc_link = aconnector->dc_link;
+
+               if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd) {
+                       int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
+                       int_params.irq_source = dc_link->irq_source_hpd;
+
+                       amdgpu_dm_irq_register_interrupt(adev, &int_params,
+                                       handle_hpd_irq,
+                                       (void *) aconnector);
+               }
+
+               if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd_rx) {
+
+                       /* Also register for DP short pulse (hpd_rx). */
+                       int_params.int_context = INTERRUPT_LOW_IRQ_CONTEXT;
+                       int_params.irq_source = dc_link->irq_source_hpd_rx;
+
+                       amdgpu_dm_irq_register_interrupt(adev, &int_params,
+                                       handle_hpd_rx_irq,
+                                       (void *) aconnector);
+               }
+       }
+}
+
+/* Register IRQ sources and initialize IRQ callbacks */
+static int dce110_register_irq_handlers(struct amdgpu_device *adev)
+{
+       struct dc *dc = adev->dm.dc;
+       struct common_irq_params *c_irq_params;
+       struct dc_interrupt_params int_params = {0};
+       int r;
+       int i;
+       unsigned client_id = AMDGPU_IH_CLIENTID_LEGACY;
+
+       if (adev->asic_type == CHIP_VEGA10 ||
+           adev->asic_type == CHIP_RAVEN)
+               client_id = AMDGPU_IH_CLIENTID_DCE;
+
+       int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
+       int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
+
+       /* Actions of amdgpu_irq_add_id():
+        * 1. Register a set() function with base driver.
+        *    Base driver will call set() function to enable/disable an
+        *    interrupt in DC hardware.
+        * 2. Register amdgpu_dm_irq_handler().
+        *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
+        *    coming from DC hardware.
+        *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
+        *    for acknowledging and handling. */
+
+       /* Use VBLANK interrupt */
+       for (i = VISLANDS30_IV_SRCID_D1_VERTICAL_INTERRUPT0; i <= VISLANDS30_IV_SRCID_D6_VERTICAL_INTERRUPT0; i++) {
+               r = amdgpu_irq_add_id(adev, client_id, i, &adev->crtc_irq);
+               if (r) {
+                       DRM_ERROR("Failed to add crtc irq id!\n");
+                       return r;
+               }
+
+               int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+               int_params.irq_source =
+                       dc_interrupt_to_irq_source(dc, i, 0);
+
+               c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
+
+               c_irq_params->adev = adev;
+               c_irq_params->irq_src = int_params.irq_source;
+
+               amdgpu_dm_irq_register_interrupt(adev, &int_params,
+                               dm_crtc_high_irq, c_irq_params);
+       }
+
+       /* Use GRPH_PFLIP interrupt */
+       for (i = VISLANDS30_IV_SRCID_D1_GRPH_PFLIP;
+                       i <= VISLANDS30_IV_SRCID_D6_GRPH_PFLIP; i += 2) {
+               r = amdgpu_irq_add_id(adev, client_id, i, &adev->pageflip_irq);
+               if (r) {
+                       DRM_ERROR("Failed to add page flip irq id!\n");
+                       return r;
+               }
+
+               int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+               int_params.irq_source =
+                       dc_interrupt_to_irq_source(dc, i, 0);
+
+               c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST];
+
+               c_irq_params->adev = adev;
+               c_irq_params->irq_src = int_params.irq_source;
+
+               amdgpu_dm_irq_register_interrupt(adev, &int_params,
+                               dm_pflip_high_irq, c_irq_params);
+
+       }
+
+       /* HPD */
+       r = amdgpu_irq_add_id(adev, client_id,
+                       VISLANDS30_IV_SRCID_HOTPLUG_DETECT_A, &adev->hpd_irq);
+       if (r) {
+               DRM_ERROR("Failed to add hpd irq id!\n");
+               return r;
+       }
+
+       register_hpd_handlers(adev);
+
+       return 0;
+}
+
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+/* Register IRQ sources and initialize IRQ callbacks */
+static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
+{
+       struct dc *dc = adev->dm.dc;
+       struct common_irq_params *c_irq_params;
+       struct dc_interrupt_params int_params = {0};
+       int r;
+       int i;
+
+       int_params.requested_polarity = INTERRUPT_POLARITY_DEFAULT;
+       int_params.current_polarity = INTERRUPT_POLARITY_DEFAULT;
+
+       /* Actions of amdgpu_irq_add_id():
+        * 1. Register a set() function with base driver.
+        *    Base driver will call set() function to enable/disable an
+        *    interrupt in DC hardware.
+        * 2. Register amdgpu_dm_irq_handler().
+        *    Base driver will call amdgpu_dm_irq_handler() for ALL interrupts
+        *    coming from DC hardware.
+        *    amdgpu_dm_irq_handler() will re-direct the interrupt to DC
+        *    for acknowledging and handling.
+        * */
+
+       /* Use VSTARTUP interrupt */
+       for (i = DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP;
+                       i <= DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP + adev->mode_info.num_crtc - 1;
+                       i++) {
+               r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, i, &adev->crtc_irq);
+
+               if (r) {
+                       DRM_ERROR("Failed to add crtc irq id!\n");
+                       return r;
+               }
+
+               int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+               int_params.irq_source =
+                       dc_interrupt_to_irq_source(dc, i, 0);
+
+               c_irq_params = &adev->dm.vblank_params[int_params.irq_source - DC_IRQ_SOURCE_VBLANK1];
+
+               c_irq_params->adev = adev;
+               c_irq_params->irq_src = int_params.irq_source;
+
+               amdgpu_dm_irq_register_interrupt(adev, &int_params,
+                               dm_crtc_high_irq, c_irq_params);
+       }
+
+       /* Use GRPH_PFLIP interrupt */
+       for (i = DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT;
+                       i <= DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT + adev->mode_info.num_crtc - 1;
+                       i++) {
+               r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, i, &adev->pageflip_irq);
+               if (r) {
+                       DRM_ERROR("Failed to add page flip irq id!\n");
+                       return r;
+               }
+
+               int_params.int_context = INTERRUPT_HIGH_IRQ_CONTEXT;
+               int_params.irq_source =
+                       dc_interrupt_to_irq_source(dc, i, 0);
+
+               c_irq_params = &adev->dm.pflip_params[int_params.irq_source - DC_IRQ_SOURCE_PFLIP_FIRST];
+
+               c_irq_params->adev = adev;
+               c_irq_params->irq_src = int_params.irq_source;
+
+               amdgpu_dm_irq_register_interrupt(adev, &int_params,
+                               dm_pflip_high_irq, c_irq_params);
+
+       }
+
+       /* HPD */
+       r = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_DCE, DCN_1_0__SRCID__DC_HPD1_INT,
+                       &adev->hpd_irq);
+       if (r) {
+               DRM_ERROR("Failed to add hpd irq id!\n");
+               return r;
+       }
+
+       register_hpd_handlers(adev);
+
+       return 0;
+}
+#endif
+
+static int amdgpu_dm_mode_config_init(struct amdgpu_device *adev)
+{
+       int r;
+
+       adev->mode_info.mode_config_initialized = true;
+
+       adev->ddev->mode_config.funcs = (void *)&amdgpu_dm_mode_funcs;
+       adev->ddev->mode_config.helper_private = &amdgpu_dm_mode_config_helperfuncs;
+
+       adev->ddev->mode_config.max_width = 16384;
+       adev->ddev->mode_config.max_height = 16384;
+
+       adev->ddev->mode_config.preferred_depth = 24;
+       adev->ddev->mode_config.prefer_shadow = 1;
+       /* indicate support of immediate flip */
+       adev->ddev->mode_config.async_page_flip = true;
+
+       adev->ddev->mode_config.fb_base = adev->mc.aper_base;
+
+       r = amdgpu_modeset_create_props(adev);
+       if (r)
+               return r;
+
+       return 0;
+}
+
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
+       defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+
+static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
+{
+       struct amdgpu_display_manager *dm = bl_get_data(bd);
+
+       if (dc_link_set_backlight_level(dm->backlight_link,
+                       bd->props.brightness, 0, 0))
+               return 0;
+       else
+               return 1;
+}
+
+static int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd)
+{
+       return bd->props.brightness;
+}
+
+static const struct backlight_ops amdgpu_dm_backlight_ops = {
+       .get_brightness = amdgpu_dm_backlight_get_brightness,
+       .update_status  = amdgpu_dm_backlight_update_status,
+};
+
+static void
+amdgpu_dm_register_backlight_device(struct amdgpu_display_manager *dm)
+{
+       char bl_name[16];
+       struct backlight_properties props = { 0 };
+
+       props.max_brightness = AMDGPU_MAX_BL_LEVEL;
+       props.type = BACKLIGHT_RAW;
+
+       snprintf(bl_name, sizeof(bl_name), "amdgpu_bl%d",
+                       dm->adev->ddev->primary->index);
+
+       dm->backlight_dev = backlight_device_register(bl_name,
+                       dm->adev->ddev->dev,
+                       dm,
+                       &amdgpu_dm_backlight_ops,
+                       &props);
+
+       if (IS_ERR(dm->backlight_dev))
+               DRM_ERROR("DM: Backlight registration failed!\n");
+       else
+               DRM_DEBUG_DRIVER("DM: Registered Backlight device: %s\n", bl_name);
+}
+
+#endif
+
+/* In this architecture, the association
+ * connector -> encoder -> crtc
+ * id not really requried. The crtc and connector will hold the
+ * display_index as an abstraction to use with DAL component
+ *
+ * Returns 0 on success
+ */
+static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
+{
+       struct amdgpu_display_manager *dm = &adev->dm;
+       uint32_t i;
+       struct amdgpu_dm_connector *aconnector = NULL;
+       struct amdgpu_encoder *aencoder = NULL;
+       struct amdgpu_mode_info *mode_info = &adev->mode_info;
+       uint32_t link_cnt;
+       unsigned long possible_crtcs;
+
+       link_cnt = dm->dc->caps.max_links;
+       if (amdgpu_dm_mode_config_init(dm->adev)) {
+               DRM_ERROR("DM: Failed to initialize mode config\n");
+               return -1;
+       }
+
+       for (i = 0; i < dm->dc->caps.max_planes; i++) {
+               struct amdgpu_plane *plane;
+
+               plane = kzalloc(sizeof(struct amdgpu_plane), GFP_KERNEL);
+               mode_info->planes[i] = plane;
+
+               if (!plane) {
+                       DRM_ERROR("KMS: Failed to allocate plane\n");
+                       goto fail;
+               }
+               plane->base.type = mode_info->plane_type[i];
+
+               /*
+                * HACK: IGT tests expect that each plane can only have one
+                * one possible CRTC. For now, set one CRTC for each
+                * plane that is not an underlay, but still allow multiple
+                * CRTCs for underlay planes.
+                */
+               possible_crtcs = 1 << i;
+               if (i >= dm->dc->caps.max_streams)
+                       possible_crtcs = 0xff;
+
+               if (amdgpu_dm_plane_init(dm, mode_info->planes[i], possible_crtcs)) {
+                       DRM_ERROR("KMS: Failed to initialize plane\n");
+                       goto fail;
+               }
+       }
+
+       for (i = 0; i < dm->dc->caps.max_streams; i++)
+               if (amdgpu_dm_crtc_init(dm, &mode_info->planes[i]->base, i)) {
+                       DRM_ERROR("KMS: Failed to initialize crtc\n");
+                       goto fail;
+               }
+
+       dm->display_indexes_num = dm->dc->caps.max_streams;
+
+       /* loops over all connectors on the board */
+       for (i = 0; i < link_cnt; i++) {
+
+               if (i > AMDGPU_DM_MAX_DISPLAY_INDEX) {
+                       DRM_ERROR(
+                               "KMS: Cannot support more than %d display indexes\n",
+                                       AMDGPU_DM_MAX_DISPLAY_INDEX);
+                       continue;
+               }
+
+               aconnector = kzalloc(sizeof(*aconnector), GFP_KERNEL);
+               if (!aconnector)
+                       goto fail;
+
+               aencoder = kzalloc(sizeof(*aencoder), GFP_KERNEL);
+               if (!aencoder)
+                       goto fail;
+
+               if (amdgpu_dm_encoder_init(dm->ddev, aencoder, i)) {
+                       DRM_ERROR("KMS: Failed to initialize encoder\n");
+                       goto fail;
+               }
+
+               if (amdgpu_dm_connector_init(dm, aconnector, i, aencoder)) {
+                       DRM_ERROR("KMS: Failed to initialize connector\n");
+                       goto fail;
+               }
+
+               if (dc_link_detect(dc_get_link_at_index(dm->dc, i),
+                               DETECT_REASON_BOOT))
+                       amdgpu_dm_update_connector_after_detect(aconnector);
+       }
+
+       /* Software is initialized. Now we can register interrupt handlers. */
+       switch (adev->asic_type) {
+       case CHIP_BONAIRE:
+       case CHIP_HAWAII:
+       case CHIP_KAVERI:
+       case CHIP_KABINI:
+       case CHIP_MULLINS:
+       case CHIP_TONGA:
+       case CHIP_FIJI:
+       case CHIP_CARRIZO:
+       case CHIP_STONEY:
+       case CHIP_POLARIS11:
+       case CHIP_POLARIS10:
+       case CHIP_POLARIS12:
+       case CHIP_VEGA10:
+               if (dce110_register_irq_handlers(dm->adev)) {
+                       DRM_ERROR("DM: Failed to initialize IRQ\n");
+                       goto fail;
+               }
+               break;
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+       case CHIP_RAVEN:
+               if (dcn10_register_irq_handlers(dm->adev)) {
+                       DRM_ERROR("DM: Failed to initialize IRQ\n");
+                       goto fail;
+               }
+               /*
+                * Temporary disable until pplib/smu interaction is implemented
+                */
+               dm->dc->debug.disable_stutter = true;
+               break;
+#endif
+       default:
+               DRM_ERROR("Usupported ASIC type: 0x%X\n", adev->asic_type);
+               goto fail;
+       }
+
+       return 0;
+fail:
+       kfree(aencoder);
+       kfree(aconnector);
+       for (i = 0; i < dm->dc->caps.max_planes; i++)
+               kfree(mode_info->planes[i]);
+       return -1;
+}
+
+static void amdgpu_dm_destroy_drm_device(struct amdgpu_display_manager *dm)
+{
+       drm_mode_config_cleanup(dm->ddev);
+       return;
+}
+
+/******************************************************************************
+ * amdgpu_display_funcs functions
+ *****************************************************************************/
+
+/**
+ * dm_bandwidth_update - program display watermarks
+ *
+ * @adev: amdgpu_device pointer
+ *
+ * Calculate and program the display watermarks and line buffer allocation.
+ */
+static void dm_bandwidth_update(struct amdgpu_device *adev)
+{
+       /* TODO: implement later */
+}
+
+static void dm_set_backlight_level(struct amdgpu_encoder *amdgpu_encoder,
+                                    u8 level)
+{
+       /* TODO: translate amdgpu_encoder to display_index and call DAL */
+}
+
+static u8 dm_get_backlight_level(struct amdgpu_encoder *amdgpu_encoder)
+{
+       /* TODO: translate amdgpu_encoder to display_index and call DAL */
+       return 0;
+}
+
+static int amdgpu_notify_freesync(struct drm_device *dev, void *data,
+                               struct drm_file *filp)
+{
+       struct mod_freesync_params freesync_params;
+       uint8_t num_streams;
+       uint8_t i;
+
+       struct amdgpu_device *adev = dev->dev_private;
+       int r = 0;
+
+       /* Get freesync enable flag from DRM */
+
+       num_streams = dc_get_current_stream_count(adev->dm.dc);
+
+       for (i = 0; i < num_streams; i++) {
+               struct dc_stream_state *stream;
+               stream = dc_get_stream_at_index(adev->dm.dc, i);
+
+               mod_freesync_update_state(adev->dm.freesync_module,
+                                         &stream, 1, &freesync_params);
+       }
+
+       return r;
+}
+
+static const struct amdgpu_display_funcs dm_display_funcs = {
+       .bandwidth_update = dm_bandwidth_update, /* called unconditionally */
+       .vblank_get_counter = dm_vblank_get_counter,/* called unconditionally */
+       .vblank_wait = NULL,
+       .backlight_set_level =
+               dm_set_backlight_level,/* called unconditionally */
+       .backlight_get_level =
+               dm_get_backlight_level,/* called unconditionally */
+       .hpd_sense = NULL,/* called unconditionally */
+       .hpd_set_polarity = NULL, /* called unconditionally */
+       .hpd_get_gpio_reg = NULL, /* VBIOS parsing. DAL does it. */
+       .page_flip_get_scanoutpos =
+               dm_crtc_get_scanoutpos,/* called unconditionally */
+       .add_encoder = NULL, /* VBIOS parsing. DAL does it. */
+       .add_connector = NULL, /* VBIOS parsing. DAL does it. */
+       .notify_freesync = amdgpu_notify_freesync,
+
+};
+
+#if defined(CONFIG_DEBUG_KERNEL_DC)
+
+static ssize_t s3_debug_store(struct device *device,
+                             struct device_attribute *attr,
+                             const char *buf,
+                             size_t count)
+{
+       int ret;
+       int s3_state;
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+       struct amdgpu_device *adev = drm_dev->dev_private;
+
+       ret = kstrtoint(buf, 0, &s3_state);
+
+       if (ret == 0) {
+               if (s3_state) {
+                       dm_resume(adev);
+                       amdgpu_dm_display_resume(adev);
+                       drm_kms_helper_hotplug_event(adev->ddev);
+               } else
+                       dm_suspend(adev);
+       }
+
+       return ret == 0 ? count : 0;
+}
+
+DEVICE_ATTR_WO(s3_debug);
+
+#endif
+
+static int dm_early_init(void *handle)
+{
+       struct amdgpu_device *adev = (struct amdgpu_device *)handle;
+
+       adev->ddev->driver->driver_features |= DRIVER_ATOMIC;
+       amdgpu_dm_set_irq_funcs(adev);
+
+       switch (adev->asic_type) {
+       case CHIP_BONAIRE:
+       case CHIP_HAWAII:
+               adev->mode_info.num_crtc = 6;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 6;
+               adev->mode_info.plane_type = dm_plane_type_default;
+               break;
+       case CHIP_KAVERI:
+               adev->mode_info.num_crtc = 4;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 7;
+               adev->mode_info.plane_type = dm_plane_type_default;
+               break;
+       case CHIP_KABINI:
+       case CHIP_MULLINS:
+               adev->mode_info.num_crtc = 2;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 6;
+               adev->mode_info.plane_type = dm_plane_type_default;
+               break;
+       case CHIP_FIJI:
+       case CHIP_TONGA:
+               adev->mode_info.num_crtc = 6;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 7;
+               adev->mode_info.plane_type = dm_plane_type_default;
+               break;
+       case CHIP_CARRIZO:
+               adev->mode_info.num_crtc = 3;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 9;
+               adev->mode_info.plane_type = dm_plane_type_carizzo;
+               break;
+       case CHIP_STONEY:
+               adev->mode_info.num_crtc = 2;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 9;
+               adev->mode_info.plane_type = dm_plane_type_stoney;
+               break;
+       case CHIP_POLARIS11:
+       case CHIP_POLARIS12:
+               adev->mode_info.num_crtc = 5;
+               adev->mode_info.num_hpd = 5;
+               adev->mode_info.num_dig = 5;
+               adev->mode_info.plane_type = dm_plane_type_default;
+               break;
+       case CHIP_POLARIS10:
+               adev->mode_info.num_crtc = 6;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 6;
+               adev->mode_info.plane_type = dm_plane_type_default;
+               break;
+       case CHIP_VEGA10:
+               adev->mode_info.num_crtc = 6;
+               adev->mode_info.num_hpd = 6;
+               adev->mode_info.num_dig = 6;
+               adev->mode_info.plane_type = dm_plane_type_default;
+               break;
+#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
+       case CHIP_RAVEN:
+               adev->mode_info.num_crtc = 4;
+               adev->mode_info.num_hpd = 4;
+               adev->mode_info.num_dig = 4;
+               adev->mode_info.plane_type = dm_plane_type_default;
+               break;
+#endif
+       default:
+               DRM_ERROR("Usupported ASIC type: 0x%X\n", adev->asic_type);
+               return -EINVAL;
+       }
+
+       if (adev->mode_info.funcs == NULL)
+               adev->mode_info.funcs = &dm_display_funcs;
+
+       /* Note: Do NOT change adev->audio_endpt_rreg and
+        * adev->audio_endpt_wreg because they are initialised in
+        * amdgpu_device_init() */
+#if defined(CONFIG_DEBUG_KERNEL_DC)
+       device_create_file(
+               adev->ddev->dev,
+               &dev_attr_s3_debug);
+#endif
+
+       return 0;
+}
+
+struct dm_connector_state {
+       struct drm_connector_state base;
+
+       enum amdgpu_rmx_type scaling;
+       uint8_t underscan_vborder;
+       uint8_t underscan_hborder;
+       bool underscan_enable;
+};
+
+#define to_dm_connector_state(x)\
+       container_of((x), struct dm_connector_state, base)
+
+static bool modeset_required(struct drm_crtc_state *crtc_state,
+                            struct dc_stream_state *new_stream,
+                            struct dc_stream_state *old_stream)
+{
+       if (!drm_atomic_crtc_needs_modeset(crtc_state))
+               return false;
+
+       if (!crtc_state->enable)
+               return false;
+
+       return crtc_state->active;
+}
+
+static bool modereset_required(struct drm_crtc_state *crtc_state)
+{
+       if (!drm_atomic_crtc_needs_modeset(crtc_state))
+               return false;
+
+       return !crtc_state->enable || !crtc_state->active;
+}
+
+static void amdgpu_dm_encoder_destroy(struct drm_encoder *encoder)
+{
+       drm_encoder_cleanup(encoder);
+       kfree(encoder);
+}
+
+static const struct drm_encoder_funcs amdgpu_dm_encoder_funcs = {
+       .destroy = amdgpu_dm_encoder_destroy,
+};
+
+static bool fill_rects_from_plane_state(const struct drm_plane_state *state,
+                                       struct dc_plane_state *plane_state)
+{
+       plane_state->src_rect.x = state->src_x >> 16;
+       plane_state->src_rect.y = state->src_y >> 16;
+       /*we ignore for now mantissa and do not to deal with floating pixels :(*/
+       plane_state->src_rect.width = state->src_w >> 16;
+
+       if (plane_state->src_rect.width == 0)
+               return false;
+
+       plane_state->src_rect.height = state->src_h >> 16;
+       if (plane_state->src_rect.height == 0)
+               return false;
+
+       plane_state->dst_rect.x = state->crtc_x;
+       plane_state->dst_rect.y = state->crtc_y;
+
+       if (state->crtc_w == 0)
+               return false;
+
+       plane_state->dst_rect.width = state->crtc_w;
+
+       if (state->crtc_h == 0)
+               return false;
+
+       plane_state->dst_rect.height = state->crtc_h;
+
+       plane_state->clip_rect = plane_state->dst_rect;
+
+       switch (state->rotation & DRM_MODE_ROTATE_MASK) {
+       case DRM_MODE_ROTATE_0:
+               plane_state->rotation = ROTATION_ANGLE_0;
+               break;
+       case DRM_MODE_ROTATE_90:
+               plane_state->rotation = ROTATION_ANGLE_90;
+               break;
+       case DRM_MODE_ROTATE_180:
+               plane_state->rotation = ROTATION_ANGLE_180;
+               break;
+       case DRM_MODE_ROTATE_270:
+               plane_state->rotation = ROTATION_ANGLE_270;
+               break;
+       default:
+               plane_state->rotation = ROTATION_ANGLE_0;
+               break;
+       }
+
+       return true;
+}
+static int get_fb_info(const struct amdgpu_framebuffer *amdgpu_fb,
+                      uint64_t *tiling_flags,
+                      uint64_t *fb_location)
+{
+       struct amdgpu_bo *rbo = gem_to_amdgpu_bo(amdgpu_fb->obj);
+       int r = amdgpu_bo_reserve(rbo, false);
+
+       if (unlikely(r)) {
+               // Don't show error msg. when return -ERESTARTSYS
+               if (r != -ERESTARTSYS)
+                       DRM_ERROR("Unable to reserve buffer: %d\n", r);
+               return r;
+       }
+
+       if (fb_location)
+               *fb_location = amdgpu_bo_gpu_offset(rbo);
+
+       if (tiling_flags)
+               amdgpu_bo_get_tiling_flags(rbo, tiling_flags);
+
+       amdgpu_bo_unreserve(rbo);
+
+       return r;
+}
+
+static int fill_plane_attributes_from_fb(struct amdgpu_device *adev,
+                                        struct dc_plane_state *plane_state,
+                                        const struct amdgpu_framebuffer *amdgpu_fb,
+                                        bool addReq)
+{
+       uint64_t tiling_flags;
+       uint64_t fb_location = 0;
+       uint64_t chroma_addr = 0;
+       unsigned int awidth;
+       const struct drm_framebuffer *fb = &amdgpu_fb->base;
+       int ret = 0;
+       struct drm_format_name_buf format_name;
+
+       ret = get_fb_info(
+               amdgpu_fb,
+               &tiling_flags,
+               addReq == true ? &fb_location:NULL);
+
+       if (ret)
+               return ret;
+
+       switch (fb->format->format) {
+       case DRM_FORMAT_C8:
+               plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS;
+               break;
+       case DRM_FORMAT_RGB565:
+               plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_RGB565;
+               break;
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_ARGB8888:
+               plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB8888;
+               break;
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_ARGB2101010:
+               plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010;
+               break;
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_ABGR2101010:
+               plane_state->format = SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010;
+               break;
+       case DRM_FORMAT_NV21:
+               plane_state->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr;
+               break;
+       case DRM_FORMAT_NV12:
+               plane_state->format = SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb;
+               break;
+       default:
+               DRM_ERROR("Unsupported screen format %s\n",
+                         drm_get_format_name(fb->format->format, &format_name));
+               return -EINVAL;
+       }
+
+       if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
+               plane_state->address.type = PLN_ADDR_TYPE_GRAPHICS;
+               plane_state->address.grph.addr.low_part = lower_32_bits(fb_location);
+               plane_state->address.grph.addr.high_part = upper_32_bits(fb_location);
+               plane_state->plane_size.grph.surface_size.x = 0;
+               plane_state->plane_size.grph.surface_size.y = 0;
+               plane_state->plane_size.grph.surface_size.width = fb->width;
+               plane_state->plane_size.grph.surface_size.height = fb->height;
+               plane_state->plane_size.grph.surface_pitch =
+                               fb->pitches[0] / fb->format->cpp[0];
+               /* TODO: unhardcode */
+               plane_state->color_space = COLOR_SPACE_SRGB;
+
+       } else {
+               awidth = ALIGN(fb->width, 64);
+               plane_state->address.type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
+               plane_state->address.video_progressive.luma_addr.low_part
+                                               = lower_32_bits(fb_location);
+               plane_state->address.video_progressive.luma_addr.high_part
+                                               = upper_32_bits(fb_location);
+               chroma_addr = fb_location + (u64)(awidth * fb->height);
+               plane_state->address.video_progressive.chroma_addr.low_part
+                                               = lower_32_bits(chroma_addr);
+               plane_state->address.video_progressive.chroma_addr.high_part
+                                               = upper_32_bits(chroma_addr);
+               plane_state->plane_size.video.luma_size.x = 0;
+               plane_state->plane_size.video.luma_size.y = 0;
+               plane_state->plane_size.video.luma_size.width = awidth;
+               plane_state->plane_size.video.luma_size.height = fb->height;
+               /* TODO: unhardcode */
+               plane_state->plane_size.video.luma_pitch = awidth;
+
+               plane_state->plane_size.video.chroma_size.x = 0;
+               plane_state->plane_size.video.chroma_size.y = 0;
+               plane_state->plane_size.video.chroma_size.width = awidth;
+               plane_state->plane_size.video.chroma_size.height = fb->height;
+               plane_state->plane_size.video.chroma_pitch = awidth / 2;
+
+               /* TODO: unhardcode */
+               plane_state->color_space = COLOR_SPACE_YCBCR709;
+       }
+
+       memset(&plane_state->tiling_info, 0, sizeof(plane_state->tiling_info));
+
+       /* Fill GFX8 params */
+       if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE) == DC_ARRAY_2D_TILED_THIN1) {
+               unsigned int bankw, bankh, mtaspect, tile_split, num_banks;
+
+               bankw = AMDGPU_TILING_GET(tiling_flags, BANK_WIDTH);
+               bankh = AMDGPU_TILING_GET(tiling_flags, BANK_HEIGHT);
+               mtaspect = AMDGPU_TILING_GET(tiling_flags, MACRO_TILE_ASPECT);
+               tile_split = AMDGPU_TILING_GET(tiling_flags, TILE_SPLIT);
+               num_banks = AMDGPU_TILING_GET(tiling_flags, NUM_BANKS);
+
+               /* XXX fix me for VI */
+               plane_state->tiling_info.gfx8.num_banks = num_banks;
+               plane_state->tiling_info.gfx8.array_mode =
+                               DC_ARRAY_2D_TILED_THIN1;
+               plane_state->tiling_info.gfx8.tile_split = tile_split;
+               plane_state->tiling_info.gfx8.bank_width = bankw;
+               plane_state->tiling_info.gfx8.bank_height = bankh;
+               plane_state->tiling_info.gfx8.tile_aspect = mtaspect;
+               plane_state->tiling_info.gfx8.tile_mode =
+                               DC_ADDR_SURF_MICRO_TILING_DISPLAY;
+       } else if (AMDGPU_TILING_GET(tiling_flags, ARRAY_MODE)
+                       == DC_ARRAY_1D_TILED_THIN1) {
+               plane_state->tiling_info.gfx8.array_mode = DC_ARRAY_1D_TILED_THIN1;
+       }
+
+       plane_state->tiling_info.gfx8.pipe_config =
+                       AMDGPU_TILING_GET(tiling_flags, PIPE_CONFIG);
+
+       if (adev->asic_type == CHIP_VEGA10 ||
+           adev->asic_type == CHIP_RAVEN) {
+               /* Fill GFX9 params */
+               plane_state->tiling_info.gfx9.num_pipes =
+                       adev->gfx.config.gb_addr_config_fields.num_pipes;
+               plane_state->tiling_info.gfx9.num_banks =
+                       adev->gfx.config.gb_addr_config_fields.num_banks;
+               plane_state->tiling_info.gfx9.pipe_interleave =
+                       adev->gfx.config.gb_addr_config_fields.pipe_interleave_size;
+               plane_state->tiling_info.gfx9.num_shader_engines =
+                       adev->gfx.config.gb_addr_config_fields.num_se;
+               plane_state->tiling_info.gfx9.max_compressed_frags =
+                       adev->gfx.config.gb_addr_config_fields.max_compress_frags;
+               plane_state->tiling_info.gfx9.num_rb_per_se =
+                       adev->gfx.config.gb_addr_config_fields.num_rb_per_se;
+               plane_state->tiling_info.gfx9.swizzle =
+                       AMDGPU_TILING_GET(tiling_flags, SWIZZLE_MODE);
+               plane_state->tiling_info.gfx9.shaderEnable = 1;
+       }
+
+       plane_state->visible = true;
+       plane_state->scaling_quality.h_taps_c = 0;
+       plane_state->scaling_quality.v_taps_c = 0;
+
+       /* is this needed? is plane_state zeroed at allocation? */
+       plane_state->scaling_quality.h_taps = 0;
+       plane_state->scaling_quality.v_taps = 0;
+       plane_state->stereo_format = PLANE_STEREO_FORMAT_NONE;
+
+       return ret;
+
+}
+
+static void fill_gamma_from_crtc_state(const struct drm_crtc_state *crtc_state,
+                                      struct dc_plane_state *plane_state)
+{
+       int i;
+       struct dc_gamma *gamma;
+       struct drm_color_lut *lut =
+                       (struct drm_color_lut *) crtc_state->gamma_lut->data;
+
+       gamma = dc_create_gamma();
+
+       if (gamma == NULL) {
+               WARN_ON(1);
+               return;
+       }
+
+       gamma->type = GAMMA_RGB_256;
+       gamma->num_entries = GAMMA_RGB_256_ENTRIES;
+       for (i = 0; i < GAMMA_RGB_256_ENTRIES; i++) {
+               gamma->entries.red[i] = dal_fixed31_32_from_int(lut[i].red);
+               gamma->entries.green[i] = dal_fixed31_32_from_int(lut[i].green);
+               gamma->entries.blue[i] = dal_fixed31_32_from_int(lut[i].blue);
+       }
+
+       plane_state->gamma_correction = gamma;
+}
+
+static int fill_plane_attributes(struct amdgpu_device *adev,
+                                struct dc_plane_state *dc_plane_state,
+                                struct drm_plane_state *plane_state,
+                                struct drm_crtc_state *crtc_state,
+                                bool addrReq)
+{
+       const struct amdgpu_framebuffer *amdgpu_fb =
+               to_amdgpu_framebuffer(plane_state->fb);
+       const struct drm_crtc *crtc = plane_state->crtc;
+       struct dc_transfer_func *input_tf;
+       int ret = 0;
+
+       if (!fill_rects_from_plane_state(plane_state, dc_plane_state))
+               return -EINVAL;
+
+       ret = fill_plane_attributes_from_fb(
+               crtc->dev->dev_private,
+               dc_plane_state,
+               amdgpu_fb,
+               addrReq);
+
+       if (ret)
+               return ret;
+
+       input_tf = dc_create_transfer_func();
+
+       if (input_tf == NULL)
+               return -ENOMEM;
+
+       input_tf->type = TF_TYPE_PREDEFINED;
+       input_tf->tf = TRANSFER_FUNCTION_SRGB;
+
+       dc_plane_state->in_transfer_func = input_tf;
+
+       /* In case of gamma set, update gamma value */
+       if (crtc_state->gamma_lut)
+               fill_gamma_from_crtc_state(crtc_state, dc_plane_state);
+
+       return ret;
+}
+
+/*****************************************************************************/
+
+static void update_stream_scaling_settings(const struct drm_display_mode *mode,
+                                          const struct dm_connector_state *dm_state,
+                                          struct dc_stream_state *stream)
+{
+       enum amdgpu_rmx_type rmx_type;
+
+       struct rect src = { 0 }; /* viewport in composition space*/
+       struct rect dst = { 0 }; /* stream addressable area */
+
+       /* no mode. nothing to be done */
+       if (!mode)
+               return;
+
+       /* Full screen scaling by default */
+       src.width = mode->hdisplay;
+       src.height = mode->vdisplay;
+       dst.width = stream->timing.h_addressable;
+       dst.height = stream->timing.v_addressable;
+
+       rmx_type = dm_state->scaling;
+       if (rmx_type == RMX_ASPECT || rmx_type == RMX_OFF) {
+               if (src.width * dst.height <
+                               src.height * dst.width) {
+                       /* height needs less upscaling/more downscaling */
+                       dst.width = src.width *
+                                       dst.height / src.height;
+               } else {
+                       /* width needs less upscaling/more downscaling */
+                       dst.height = src.height *
+                                       dst.width / src.width;
+               }
+       } else if (rmx_type == RMX_CENTER) {
+               dst = src;
+       }
+
+       dst.x = (stream->timing.h_addressable - dst.width) / 2;
+       dst.y = (stream->timing.v_addressable - dst.height) / 2;
+
+       if (dm_state->underscan_enable) {
+               dst.x += dm_state->underscan_hborder / 2;
+               dst.y += dm_state->underscan_vborder / 2;
+               dst.width -= dm_state->underscan_hborder;
+               dst.height -= dm_state->underscan_vborder;
+       }
+
+       stream->src = src;
+       stream->dst = dst;
+
+       DRM_DEBUG_DRIVER("Destination Rectangle x:%d  y:%d  width:%d  height:%d\n",
+                       dst.x, dst.y, dst.width, dst.height);
+
+}
+
+static enum dc_color_depth
+convert_color_depth_from_display_info(const struct drm_connector *connector)
+{
+       uint32_t bpc = connector->display_info.bpc;
+
+       /* Limited color depth to 8bit
+        * TODO: Still need to handle deep color
+        */
+       if (bpc > 8)
+               bpc = 8;
+
+       switch (bpc) {
+       case 0:
+               /* Temporary Work around, DRM don't parse color depth for
+                * EDID revision before 1.4
+                * TODO: Fix edid parsing
+                */
+               return COLOR_DEPTH_888;
+       case 6:
+               return COLOR_DEPTH_666;
+       case 8:
+               return COLOR_DEPTH_888;
+       case 10:
+               return COLOR_DEPTH_101010;
+       case 12:
+               return COLOR_DEPTH_121212;
+       case 14:
+               return COLOR_DEPTH_141414;
+       case 16:
+               return COLOR_DEPTH_161616;
+       default:
+               return COLOR_DEPTH_UNDEFINED;
+       }
+}
+
+static enum dc_aspect_ratio
+get_aspect_ratio(const struct drm_display_mode *mode_in)
+{
+       int32_t width = mode_in->crtc_hdisplay * 9;
+       int32_t height = mode_in->crtc_vdisplay * 16;
+
+       if ((width - height) < 10 && (width - height) > -10)
+               return ASPECT_RATIO_16_9;
+       else
+               return ASPECT_RATIO_4_3;
+}
+
+static enum dc_color_space
+get_output_color_space(const struct dc_crtc_timing *dc_crtc_timing)
+{
+       enum dc_color_space color_space = COLOR_SPACE_SRGB;
+
+       switch (dc_crtc_timing->pixel_encoding) {
+       case PIXEL_ENCODING_YCBCR422:
+       case PIXEL_ENCODING_YCBCR444:
+       case PIXEL_ENCODING_YCBCR420:
+       {
+               /*
+                * 27030khz is the separation point between HDTV and SDTV
+                * according to HDMI spec, we use YCbCr709 and YCbCr601
+                * respectively
+                */
+               if (dc_crtc_timing->pix_clk_khz > 27030) {
+                       if (dc_crtc_timing->flags.Y_ONLY)
+                               color_space =
+                                       COLOR_SPACE_YCBCR709_LIMITED;
+                       else
+                               color_space = COLOR_SPACE_YCBCR709;
+               } else {
+                       if (dc_crtc_timing->flags.Y_ONLY)
+                               color_space =
+                                       COLOR_SPACE_YCBCR601_LIMITED;
+                       else
+                               color_space = COLOR_SPACE_YCBCR601;
+               }
+
+       }
+       break;
+       case PIXEL_ENCODING_RGB:
+               color_space = COLOR_SPACE_SRGB;
+               break;
+
+       default:
+               WARN_ON(1);
+               break;
+       }
+
+       return color_space;
+}
+
+/*****************************************************************************/
+
+static void
+fill_stream_properties_from_drm_display_mode(struct dc_stream_state *stream,
+                                            const struct drm_display_mode *mode_in,
+                                            const struct drm_connector *connector)
+{
+       struct dc_crtc_timing *timing_out = &stream->timing;
+
+       memset(timing_out, 0, sizeof(struct dc_crtc_timing));
+
+       timing_out->h_border_left = 0;
+       timing_out->h_border_right = 0;
+       timing_out->v_border_top = 0;
+       timing_out->v_border_bottom = 0;
+       /* TODO: un-hardcode */
+
+       if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444)
+                       && stream->sink->sink_signal == SIGNAL_TYPE_HDMI_TYPE_A)
+               timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
+       else
+               timing_out->pixel_encoding = PIXEL_ENCODING_RGB;
+
+       timing_out->timing_3d_format = TIMING_3D_FORMAT_NONE;
+       timing_out->display_color_depth = convert_color_depth_from_display_info(
+                       connector);
+       timing_out->scan_type = SCANNING_TYPE_NODATA;
+       timing_out->hdmi_vic = 0;
+       timing_out->vic = drm_match_cea_mode(mode_in);
+
+       timing_out->h_addressable = mode_in->crtc_hdisplay;
+       timing_out->h_total = mode_in->crtc_htotal;
+       timing_out->h_sync_width =
+               mode_in->crtc_hsync_end - mode_in->crtc_hsync_start;
+       timing_out->h_front_porch =
+               mode_in->crtc_hsync_start - mode_in->crtc_hdisplay;
+       timing_out->v_total = mode_in->crtc_vtotal;
+       timing_out->v_addressable = mode_in->crtc_vdisplay;
+       timing_out->v_front_porch =
+               mode_in->crtc_vsync_start - mode_in->crtc_vdisplay;
+       timing_out->v_sync_width =
+               mode_in->crtc_vsync_end - mode_in->crtc_vsync_start;
+       timing_out->pix_clk_khz = mode_in->crtc_clock;
+       timing_out->aspect_ratio = get_aspect_ratio(mode_in);
+       if (mode_in->flags & DRM_MODE_FLAG_PHSYNC)
+               timing_out->flags.HSYNC_POSITIVE_POLARITY = 1;
+       if (mode_in->flags & DRM_MODE_FLAG_PVSYNC)
+               timing_out->flags.VSYNC_POSITIVE_POLARITY = 1;
+
+       stream->output_color_space = get_output_color_space(timing_out);
+
+       {
+               struct dc_transfer_func *tf = dc_create_transfer_func();
+
+               tf->type = TF_TYPE_PREDEFINED;
+               tf->tf = TRANSFER_FUNCTION_SRGB;
+               stream->out_transfer_func = tf;
+       }
+}
+
+static void fill_audio_info(struct audio_info *audio_info,
+                           const struct drm_connector *drm_connector,
+                           const struct dc_sink *dc_sink)
+{
+       int i = 0;
+       int cea_revision = 0;
+       const struct dc_edid_caps *edid_caps = &dc_sink->edid_caps;
+
+       audio_info->manufacture_id = edid_caps->manufacturer_id;
+       audio_info->product_id = edid_caps->product_id;
+
+       cea_revision = drm_connector->display_info.cea_rev;
+
+       strncpy(audio_info->display_name,
+               edid_caps->display_name,
+               AUDIO_INFO_DISPLAY_NAME_SIZE_IN_CHARS - 1);
+
+       if (cea_revision >= 3) {
+               audio_info->mode_count = edid_caps->audio_mode_count;
+
+               for (i = 0; i < audio_info->mode_count; ++i) {
+                       audio_info->modes[i].format_code =
+                                       (enum audio_format_code)
+                                       (edid_caps->audio_modes[i].format_code);
+                       audio_info->modes[i].channel_count =
+                                       edid_caps->audio_modes[i].channel_count;
+                       audio_info->modes[i].sample_rates.all =
+                                       edid_caps->audio_modes[i].sample_rate;
+                       audio_info->modes[i].sample_size =
+                                       edid_caps->audio_modes[i].sample_size;
+               }
+       }
+
+       audio_info->flags.all = edid_caps->speaker_flags;
+
+       /* TODO: We only check for the progressive mode, check for interlace mode too */
+       if (drm_connector->latency_present[0]) {
+               audio_info->video_latency = drm_connector->video_latency[0];
+               audio_info->audio_latency = drm_connector->audio_latency[0];
+       }
+
+       /* TODO: For DP, video and audio latency should be calculated from DPCD caps */
+
+}
+
+static void
+copy_crtc_timing_for_drm_display_mode(const struct drm_display_mode *src_mode,
+                                     struct drm_display_mode *dst_mode)
+{
+       dst_mode->crtc_hdisplay = src_mode->crtc_hdisplay;
+       dst_mode->crtc_vdisplay = src_mode->crtc_vdisplay;
+       dst_mode->crtc_clock = src_mode->crtc_clock;
+       dst_mode->crtc_hblank_start = src_mode->crtc_hblank_start;
+       dst_mode->crtc_hblank_end = src_mode->crtc_hblank_end;
+       dst_mode->crtc_hsync_start =  src_mode->crtc_hsync_start;
+       dst_mode->crtc_hsync_end = src_mode->crtc_hsync_end;
+       dst_mode->crtc_htotal = src_mode->crtc_htotal;
+       dst_mode->crtc_hskew = src_mode->crtc_hskew;
+       dst_mode->crtc_vblank_start = src_mode->crtc_vblank_start;
+       dst_mode->crtc_vblank_end = src_mode->crtc_vblank_end;
+       dst_mode->crtc_vsync_start = src_mode->crtc_vsync_start;
+       dst_mode->crtc_vsync_end = src_mode->crtc_vsync_end;
+       dst_mode->crtc_vtotal = src_mode->crtc_vtotal;
+}
+
+static void
+decide_crtc_timing_for_drm_display_mode(struct drm_display_mode *drm_mode,
+                                       const struct drm_display_mode *native_mode,
+                                       bool scale_enabled)
+{
+       if (scale_enabled) {
+               copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
+       } else if (native_mode->clock == drm_mode->clock &&
+                       native_mode->htotal == drm_mode->htotal &&
+                       native_mode->vtotal == drm_mode->vtotal) {
+               copy_crtc_timing_for_drm_display_mode(native_mode, drm_mode);
+       } else {
+               /* no scaling nor amdgpu inserted, no need to patch */
+       }
+}
+
+static int create_fake_sink(struct amdgpu_dm_connector *aconnector)
+{
+       struct dc_sink *sink = NULL;
+       struct dc_sink_init_data sink_init_data = { 0 };
+
+       sink_init_data.link = aconnector->dc_link;
+       sink_init_data.sink_signal = aconnector->dc_link->connector_signal;
+
+       sink = dc_sink_create(&sink_init_data);
+       if (!sink) {
+               DRM_ERROR("Failed to create sink!\n");
+               return -ENOMEM;
+       }
+
+       sink->sink_signal = SIGNAL_TYPE_VIRTUAL;
+       aconnector->fake_enable = true;
+
+       aconnector->dc_sink = sink;
+       aconnector->dc_link->local_sink = sink;
+
+       return 0;
+}
+
+static struct dc_stream_state *
+create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+                      const struct drm_display_mode *drm_mode,
+                      const struct dm_connector_state *dm_state)
+{
+       struct drm_display_mode *preferred_mode = NULL;
+       const struct drm_connector *drm_connector;
+       struct dc_stream_state *stream = NULL;
+       struct drm_display_mode mode = *drm_mode;
+       bool native_mode_found = false;
+
+       if (aconnector == NULL) {
+               DRM_ERROR("aconnector is NULL!\n");
+               goto drm_connector_null;
+       }
+
+       if (dm_state == NULL) {
+               DRM_ERROR("dm_state is NULL!\n");
+               goto dm_state_null;
+       }
+
+       drm_connector = &aconnector->base;
+
+       if (!aconnector->dc_sink) {
+               /*
+                * Exclude MST from creating fake_sink
+                * TODO: need to enable MST into fake_sink feature
+                */
+               if (aconnector->mst_port)
+                       goto stream_create_fail;
+
+               if (create_fake_sink(aconnector))
+                       goto stream_create_fail;
+       }
+
+       stream = dc_create_stream_for_sink(aconnector->dc_sink);
+
+       if (stream == NULL) {
+               DRM_ERROR("Failed to create stream for sink!\n");
+               goto stream_create_fail;
+       }
+
+       list_for_each_entry(preferred_mode, &aconnector->base.modes, head) {
+               /* Search for preferred mode */
+               if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED) {
+                       native_mode_found = true;
+                       break;
+               }
+       }
+       if (!native_mode_found)
+               preferred_mode = list_first_entry_or_null(
+                               &aconnector->base.modes,
+                               struct drm_display_mode,
+                               head);
+
+       if (preferred_mode == NULL) {
+               /* This may not be an error, the use case is when we we have no
+                * usermode calls to reset and set mode upon hotplug. In this
+                * case, we call set mode ourselves to restore the previous mode
+                * and the modelist may not be filled in in time.
+                */
+               DRM_DEBUG_DRIVER("No preferred mode found\n");
+       } else {
+               decide_crtc_timing_for_drm_display_mode(
+                               &mode, preferred_mode,
+                               dm_state->scaling != RMX_OFF);
+       }
+
+       fill_stream_properties_from_drm_display_mode(stream,
+                       &mode, &aconnector->base);
+       update_stream_scaling_settings(&mode, dm_state, stream);
+
+       fill_audio_info(
+               &stream->audio_info,
+               drm_connector,
+               aconnector->dc_sink);
+
+stream_create_fail:
+dm_state_null:
+drm_connector_null:
+       return stream;
+}
+
+static void amdgpu_dm_crtc_destroy(struct drm_crtc *crtc)
+{
+       drm_crtc_cleanup(crtc);
+       kfree(crtc);
+}
+
+static void dm_crtc_destroy_state(struct drm_crtc *crtc,
+                                 struct drm_crtc_state *state)
+{
+       struct dm_crtc_state *cur = to_dm_crtc_state(state);
+
+       /* TODO Destroy dc_stream objects are stream object is flattened */
+       if (cur->stream)
+               dc_stream_release(cur->stream);
+
+
+       __drm_atomic_helper_crtc_destroy_state(state);
+
+
+       kfree(state);
+}
+
+static void dm_crtc_reset_state(struct drm_crtc *crtc)
+{
+       struct dm_crtc_state *state;
+
+       if (crtc->state)
+               dm_crtc_destroy_state(crtc, crtc->state);
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (WARN_ON(!state))
+               return;
+
+       crtc->state = &state->base;
+       crtc->state->crtc = crtc;
+
+}
+
+static struct drm_crtc_state *
+dm_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+       struct dm_crtc_state *state, *cur;
+
+       cur = to_dm_crtc_state(crtc->state);
+
+       if (WARN_ON(!crtc->state))
+               return NULL;
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return NULL;
+
+       __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
+
+       if (cur->stream) {
+               state->stream = cur->stream;
+               dc_stream_retain(state->stream);
+       }
+
+       /* TODO Duplicate dc_stream after objects are stream object is flattened */
+
+       return &state->base;
+}
+
+/* Implemented only the options currently availible for the driver */
+static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
+       .reset = dm_crtc_reset_state,
+       .destroy = amdgpu_dm_crtc_destroy,
+       .gamma_set = drm_atomic_helper_legacy_gamma_set,
+       .set_config = drm_atomic_helper_set_config,
+       .page_flip = drm_atomic_helper_page_flip,
+       .atomic_duplicate_state = dm_crtc_duplicate_state,
+       .atomic_destroy_state = dm_crtc_destroy_state,
+};
+
+static enum drm_connector_status
+amdgpu_dm_connector_detect(struct drm_connector *connector, bool force)
+{
+       bool connected;
+       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+
+       /* Notes:
+        * 1. This interface is NOT called in context of HPD irq.
+        * 2. This interface *is called* in context of user-mode ioctl. Which
+        * makes it a bad place for *any* MST-related activit. */
+
+       if (aconnector->base.force == DRM_FORCE_UNSPECIFIED &&
+           !aconnector->fake_enable)
+               connected = (aconnector->dc_sink != NULL);
+       else
+               connected = (aconnector->base.force == DRM_FORCE_ON);
+
+       return (connected ? connector_status_connected :
+                       connector_status_disconnected);
+}
+
+int amdgpu_dm_connector_atomic_set_property(struct drm_connector *connector,
+                                           struct drm_connector_state *connector_state,
+                                           struct drm_property *property,
+                                           uint64_t val)
+{
+       struct drm_device *dev = connector->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct dm_connector_state *dm_old_state =
+               to_dm_connector_state(connector->state);
+       struct dm_connector_state *dm_new_state =
+               to_dm_connector_state(connector_state);
+
+       int ret = -EINVAL;
+
+       if (property == dev->mode_config.scaling_mode_property) {
+               enum amdgpu_rmx_type rmx_type;
+
+               switch (val) {
+               case DRM_MODE_SCALE_CENTER:
+                       rmx_type = RMX_CENTER;
+                       break;
+               case DRM_MODE_SCALE_ASPECT:
+                       rmx_type = RMX_ASPECT;
+                       break;
+               case DRM_MODE_SCALE_FULLSCREEN:
+                       rmx_type = RMX_FULL;
+                       break;
+               case DRM_MODE_SCALE_NONE:
+               default:
+                       rmx_type = RMX_OFF;
+                       break;
+               }
+
+               if (dm_old_state->scaling == rmx_type)
+                       return 0;
+
+               dm_new_state->scaling = rmx_type;
+               ret = 0;
+       } else if (property == adev->mode_info.underscan_hborder_property) {
+               dm_new_state->underscan_hborder = val;
+               ret = 0;
+       } else if (property == adev->mode_info.underscan_vborder_property) {
+               dm_new_state->underscan_vborder = val;
+               ret = 0;
+       } else if (property == adev->mode_info.underscan_property) {
+               dm_new_state->underscan_enable = val;
+               ret = 0;
+       }
+
+       return ret;
+}
+
+int amdgpu_dm_connector_atomic_get_property(struct drm_connector *connector,
+                                           const struct drm_connector_state *state,
+                                           struct drm_property *property,
+                                           uint64_t *val)
+{
+       struct drm_device *dev = connector->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct dm_connector_state *dm_state =
+               to_dm_connector_state(state);
+       int ret = -EINVAL;
+
+       if (property == dev->mode_config.scaling_mode_property) {
+               switch (dm_state->scaling) {
+               case RMX_CENTER:
+                       *val = DRM_MODE_SCALE_CENTER;
+                       break;
+               case RMX_ASPECT:
+                       *val = DRM_MODE_SCALE_ASPECT;
+                       break;
+               case RMX_FULL:
+                       *val = DRM_MODE_SCALE_FULLSCREEN;
+                       break;
+               case RMX_OFF:
+               default:
+                       *val = DRM_MODE_SCALE_NONE;
+                       break;
+               }
+               ret = 0;
+       } else if (property == adev->mode_info.underscan_hborder_property) {
+               *val = dm_state->underscan_hborder;
+               ret = 0;
+       } else if (property == adev->mode_info.underscan_vborder_property) {
+               *val = dm_state->underscan_vborder;
+               ret = 0;
+       } else if (property == adev->mode_info.underscan_property) {
+               *val = dm_state->underscan_enable;
+               ret = 0;
+       }
+       return ret;
+}
+
+static void amdgpu_dm_connector_destroy(struct drm_connector *connector)
+{
+       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+       const struct dc_link *link = aconnector->dc_link;
+       struct amdgpu_device *adev = connector->dev->dev_private;
+       struct amdgpu_display_manager *dm = &adev->dm;
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
+       defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+
+       if (link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) {
+               amdgpu_dm_register_backlight_device(dm);
+
+               if (dm->backlight_dev) {
+                       backlight_device_unregister(dm->backlight_dev);
+                       dm->backlight_dev = NULL;
+               }
+
+       }
+#endif
+       drm_connector_unregister(connector);
+       drm_connector_cleanup(connector);
+       kfree(connector);
+}
+
+void amdgpu_dm_connector_funcs_reset(struct drm_connector *connector)
+{
+       struct dm_connector_state *state =
+               to_dm_connector_state(connector->state);
+
+       kfree(state);
+
+       state = kzalloc(sizeof(*state), GFP_KERNEL);
+
+       if (state) {
+               state->scaling = RMX_OFF;
+               state->underscan_enable = false;
+               state->underscan_hborder = 0;
+               state->underscan_vborder = 0;
+
+               connector->state = &state->base;
+               connector->state->connector = connector;
+       }
+}
+
+struct drm_connector_state *
+amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector)
+{
+       struct dm_connector_state *state =
+               to_dm_connector_state(connector->state);
+
+       struct dm_connector_state *new_state =
+                       kmemdup(state, sizeof(*state), GFP_KERNEL);
+
+       if (new_state) {
+               __drm_atomic_helper_connector_duplicate_state(connector,
+                                                             &new_state->base);
+               return &new_state->base;
+       }
+
+       return NULL;
+}
+
+static const struct drm_connector_funcs amdgpu_dm_connector_funcs = {
+       .reset = amdgpu_dm_connector_funcs_reset,
+       .detect = amdgpu_dm_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = amdgpu_dm_connector_destroy,
+       .atomic_duplicate_state = amdgpu_dm_connector_atomic_duplicate_state,
+       .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+       .atomic_set_property = amdgpu_dm_connector_atomic_set_property,
+       .atomic_get_property = amdgpu_dm_connector_atomic_get_property
+};
+
+static struct drm_encoder *best_encoder(struct drm_connector *connector)
+{
+       int enc_id = connector->encoder_ids[0];
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+
+       DRM_DEBUG_DRIVER("Finding the best encoder\n");
+
+       /* pick the encoder ids */
+       if (enc_id) {
+               obj = drm_mode_object_find(connector->dev, NULL, enc_id, DRM_MODE_OBJECT_ENCODER);
+               if (!obj) {
+                       DRM_ERROR("Couldn't find a matching encoder for our connector\n");
+                       return NULL;
+               }
+               encoder = obj_to_encoder(obj);
+               return encoder;
+       }
+       DRM_ERROR("No encoder id\n");
+       return NULL;
+}
+
+static int get_modes(struct drm_connector *connector)
+{
+       return amdgpu_dm_connector_get_modes(connector);
+}
+
+static void create_eml_sink(struct amdgpu_dm_connector *aconnector)
+{
+       struct dc_sink_init_data init_params = {
+                       .link = aconnector->dc_link,
+                       .sink_signal = SIGNAL_TYPE_VIRTUAL
+       };
+       struct edid *edid = (struct edid *) aconnector->base.edid_blob_ptr->data;
+
+       if (!aconnector->base.edid_blob_ptr ||
+               !aconnector->base.edid_blob_ptr->data) {
+               DRM_ERROR("No EDID firmware found on connector: %s ,forcing to OFF!\n",
+                               aconnector->base.name);
+
+               aconnector->base.force = DRM_FORCE_OFF;
+               aconnector->base.override_edid = false;
+               return;
+       }
+
+       aconnector->edid = edid;
+
+       aconnector->dc_em_sink = dc_link_add_remote_sink(
+               aconnector->dc_link,
+               (uint8_t *)edid,
+               (edid->extensions + 1) * EDID_LENGTH,
+               &init_params);
+
+       if (aconnector->base.force == DRM_FORCE_ON)
+               aconnector->dc_sink = aconnector->dc_link->local_sink ?
+               aconnector->dc_link->local_sink :
+               aconnector->dc_em_sink;
+}
+
+static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
+{
+       struct dc_link *link = (struct dc_link *)aconnector->dc_link;
+
+       /* In case of headless boot with force on for DP managed connector
+        * Those settings have to be != 0 to get initial modeset
+        */
+       if (link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT) {
+               link->verified_link_cap.lane_count = LANE_COUNT_FOUR;
+               link->verified_link_cap.link_rate = LINK_RATE_HIGH2;
+       }
+
+
+       aconnector->base.override_edid = true;
+       create_eml_sink(aconnector);
+}
+
+int amdgpu_dm_connector_mode_valid(struct drm_connector *connector,
+                                  struct drm_display_mode *mode)
+{
+       int result = MODE_ERROR;
+       struct dc_sink *dc_sink;
+       struct amdgpu_device *adev = connector->dev->dev_private;
+       /* TODO: Unhardcode stream count */
+       struct dc_stream_state *stream;
+       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+
+       if ((mode->flags & DRM_MODE_FLAG_INTERLACE) ||
+                       (mode->flags & DRM_MODE_FLAG_DBLSCAN))
+               return result;
+
+       /* Only run this the first time mode_valid is called to initilialize
+        * EDID mgmt
+        */
+       if (aconnector->base.force != DRM_FORCE_UNSPECIFIED &&
+               !aconnector->dc_em_sink)
+               handle_edid_mgmt(aconnector);
+
+       dc_sink = to_amdgpu_dm_connector(connector)->dc_sink;
+
+       if (dc_sink == NULL) {
+               DRM_ERROR("dc_sink is NULL!\n");
+               goto fail;
+       }
+
+       stream = dc_create_stream_for_sink(dc_sink);
+       if (stream == NULL) {
+               DRM_ERROR("Failed to create stream for sink!\n");
+               goto fail;
+       }
+
+       drm_mode_set_crtcinfo(mode, 0);
+       fill_stream_properties_from_drm_display_mode(stream, mode, connector);
+
+       stream->src.width = mode->hdisplay;
+       stream->src.height = mode->vdisplay;
+       stream->dst = stream->src;
+
+       if (dc_validate_stream(adev->dm.dc, stream) == DC_OK)
+               result = MODE_OK;
+
+       dc_stream_release(stream);
+
+fail:
+       /* TODO: error handling*/
+       return result;
+}
+
+static const struct drm_connector_helper_funcs
+amdgpu_dm_connector_helper_funcs = {
+       /*
+        * If hotplug a second bigger display in FB Con mode, bigger resolution
+        * modes will be filtered by drm_mode_validate_size(), and those modes
+        * is missing after user start lightdm. So we need to renew modes list.
+        * in get_modes call back, not just return the modes count
+        */
+       .get_modes = get_modes,
+       .mode_valid = amdgpu_dm_connector_mode_valid,
+       .best_encoder = best_encoder
+};
+
+static void dm_crtc_helper_disable(struct drm_crtc *crtc)
+{
+}
+
+static int dm_crtc_helper_atomic_check(struct drm_crtc *crtc,
+                                      struct drm_crtc_state *state)
+{
+       struct amdgpu_device *adev = crtc->dev->dev_private;
+       struct dc *dc = adev->dm.dc;
+       struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(state);
+       int ret = -EINVAL;
+
+       if (unlikely(!dm_crtc_state->stream &&
+                    modeset_required(state, NULL, dm_crtc_state->stream))) {
+               WARN_ON(1);
+               return ret;
+       }
+
+       /* In some use cases, like reset, no stream  is attached */
+       if (!dm_crtc_state->stream)
+               return 0;
+
+       if (dc_validate_stream(dc, dm_crtc_state->stream) == DC_OK)
+               return 0;
+
+       return ret;
+}
+
+static bool dm_crtc_helper_mode_fixup(struct drm_crtc *crtc,
+                                     const struct drm_display_mode *mode,
+                                     struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static const struct drm_crtc_helper_funcs amdgpu_dm_crtc_helper_funcs = {
+       .disable = dm_crtc_helper_disable,
+       .atomic_check = dm_crtc_helper_atomic_check,
+       .mode_fixup = dm_crtc_helper_mode_fixup
+};
+
+static void dm_encoder_helper_disable(struct drm_encoder *encoder)
+{
+
+}
+
+static int dm_encoder_helper_atomic_check(struct drm_encoder *encoder,
+                                         struct drm_crtc_state *crtc_state,
+                                         struct drm_connector_state *conn_state)
+{
+       return 0;
+}
+
+const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs = {
+       .disable = dm_encoder_helper_disable,
+       .atomic_check = dm_encoder_helper_atomic_check
+};
+
+static void dm_drm_plane_reset(struct drm_plane *plane)
+{
+       struct dm_plane_state *amdgpu_state = NULL;
+
+       if (plane->state)
+               plane->funcs->atomic_destroy_state(plane, plane->state);
+
+       amdgpu_state = kzalloc(sizeof(*amdgpu_state), GFP_KERNEL);
+       WARN_ON(amdgpu_state == NULL);
+       
+       if (amdgpu_state) {
+               plane->state = &amdgpu_state->base;
+               plane->state->plane = plane;
+               plane->state->rotation = DRM_MODE_ROTATE_0;
+       }
+}
+
+static struct drm_plane_state *
+dm_drm_plane_duplicate_state(struct drm_plane *plane)
+{
+       struct dm_plane_state *dm_plane_state, *old_dm_plane_state;
+
+       old_dm_plane_state = to_dm_plane_state(plane->state);
+       dm_plane_state = kzalloc(sizeof(*dm_plane_state), GFP_KERNEL);
+       if (!dm_plane_state)
+               return NULL;
+
+       __drm_atomic_helper_plane_duplicate_state(plane, &dm_plane_state->base);
+
+       if (old_dm_plane_state->dc_state) {
+               dm_plane_state->dc_state = old_dm_plane_state->dc_state;
+               dc_plane_state_retain(dm_plane_state->dc_state);
+       }
+
+       return &dm_plane_state->base;
+}
+
+void dm_drm_plane_destroy_state(struct drm_plane *plane,
+                               struct drm_plane_state *state)
+{
+       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
+
+       if (dm_plane_state->dc_state)
+               dc_plane_state_release(dm_plane_state->dc_state);
+
+       drm_atomic_helper_plane_destroy_state(plane, state);
+}
+
+static const struct drm_plane_funcs dm_plane_funcs = {
+       .update_plane   = drm_atomic_helper_update_plane,
+       .disable_plane  = drm_atomic_helper_disable_plane,
+       .destroy        = drm_plane_cleanup,
+       .reset = dm_drm_plane_reset,
+       .atomic_duplicate_state = dm_drm_plane_duplicate_state,
+       .atomic_destroy_state = dm_drm_plane_destroy_state,
+};
+
+static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
+                                     struct drm_plane_state *new_state)
+{
+       struct amdgpu_framebuffer *afb;
+       struct drm_gem_object *obj;
+       struct amdgpu_bo *rbo;
+       uint64_t chroma_addr = 0;
+       int r;
+       struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
+       unsigned int awidth;
+
+       dm_plane_state_old = to_dm_plane_state(plane->state);
+       dm_plane_state_new = to_dm_plane_state(new_state);
+
+       if (!new_state->fb) {
+               DRM_DEBUG_DRIVER("No FB bound\n");
+               return 0;
+       }
+
+       afb = to_amdgpu_framebuffer(new_state->fb);
+
+       obj = afb->obj;
+       rbo = gem_to_amdgpu_bo(obj);
+       r = amdgpu_bo_reserve(rbo, false);
+       if (unlikely(r != 0))
+               return r;
+
+       r = amdgpu_bo_pin(rbo, AMDGPU_GEM_DOMAIN_VRAM, &afb->address);
+
+
+       amdgpu_bo_unreserve(rbo);
+
+       if (unlikely(r != 0)) {
+               if (r != -ERESTARTSYS)
+                       DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
+               return r;
+       }
+
+       amdgpu_bo_ref(rbo);
+
+       if (dm_plane_state_new->dc_state &&
+                       dm_plane_state_old->dc_state != dm_plane_state_new->dc_state) {
+               struct dc_plane_state *plane_state = dm_plane_state_new->dc_state;
+
+               if (plane_state->format < SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
+                       plane_state->address.grph.addr.low_part = lower_32_bits(afb->address);
+                       plane_state->address.grph.addr.high_part = upper_32_bits(afb->address);
+               } else {
+                       awidth = ALIGN(new_state->fb->width, 64);
+                       plane_state->address.type = PLN_ADDR_TYPE_VIDEO_PROGRESSIVE;
+                       plane_state->address.video_progressive.luma_addr.low_part
+                                                       = lower_32_bits(afb->address);
+                       plane_state->address.video_progressive.luma_addr.high_part
+                                                       = upper_32_bits(afb->address);
+                       chroma_addr = afb->address + (u64)(awidth * new_state->fb->height);
+                       plane_state->address.video_progressive.chroma_addr.low_part
+                                                       = lower_32_bits(chroma_addr);
+                       plane_state->address.video_progressive.chroma_addr.high_part
+                                                       = upper_32_bits(chroma_addr);
+               }
+       }
+
+       /* It's a hack for s3 since in 4.9 kernel filter out cursor buffer
+        * prepare and cleanup in drm_atomic_helper_prepare_planes
+        * and drm_atomic_helper_cleanup_planes because fb doens't in s3.
+        * IN 4.10 kernel this code should be removed and amdgpu_device_suspend
+        * code touching fram buffers should be avoided for DC.
+        */
+       if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_state->crtc);
+
+               acrtc->cursor_bo = obj;
+       }
+       return 0;
+}
+
+static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
+                                      struct drm_plane_state *old_state)
+{
+       struct amdgpu_bo *rbo;
+       struct amdgpu_framebuffer *afb;
+       int r;
+
+       if (!old_state->fb)
+               return;
+
+       afb = to_amdgpu_framebuffer(old_state->fb);
+       rbo = gem_to_amdgpu_bo(afb->obj);
+       r = amdgpu_bo_reserve(rbo, false);
+       if (unlikely(r)) {
+               DRM_ERROR("failed to reserve rbo before unpin\n");
+               return;
+       }
+
+       amdgpu_bo_unpin(rbo);
+       amdgpu_bo_unreserve(rbo);
+       amdgpu_bo_unref(&rbo);
+}
+
+static int dm_plane_atomic_check(struct drm_plane *plane,
+                                struct drm_plane_state *state)
+{
+       struct amdgpu_device *adev = plane->dev->dev_private;
+       struct dc *dc = adev->dm.dc;
+       struct dm_plane_state *dm_plane_state = to_dm_plane_state(state);
+
+       if (!dm_plane_state->dc_state)
+               return 0;
+
+       if (dc_validate_plane(dc, dm_plane_state->dc_state) == DC_OK)
+               return 0;
+
+       return -EINVAL;
+}
+
+static const struct drm_plane_helper_funcs dm_plane_helper_funcs = {
+       .prepare_fb = dm_plane_helper_prepare_fb,
+       .cleanup_fb = dm_plane_helper_cleanup_fb,
+       .atomic_check = dm_plane_atomic_check,
+};
+
+/*
+ * TODO: these are currently initialized to rgb formats only.
+ * For future use cases we should either initialize them dynamically based on
+ * plane capabilities, or initialize this array to all formats, so internal drm
+ * check will succeed, and let DC to implement proper check
+ */
+static const uint32_t rgb_formats[] = {
+       DRM_FORMAT_RGB888,
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ARGB8888,
+       DRM_FORMAT_RGBA8888,
+       DRM_FORMAT_XRGB2101010,
+       DRM_FORMAT_XBGR2101010,
+       DRM_FORMAT_ARGB2101010,
+       DRM_FORMAT_ABGR2101010,
+};
+
+static const uint32_t yuv_formats[] = {
+       DRM_FORMAT_NV12,
+       DRM_FORMAT_NV21,
+};
+
+static const u32 cursor_formats[] = {
+       DRM_FORMAT_ARGB8888
+};
+
+static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
+                               struct amdgpu_plane *aplane,
+                               unsigned long possible_crtcs)
+{
+       int res = -EPERM;
+
+       switch (aplane->base.type) {
+       case DRM_PLANE_TYPE_PRIMARY:
+               aplane->base.format_default = true;
+
+               res = drm_universal_plane_init(
+                               dm->adev->ddev,
+                               &aplane->base,
+                               possible_crtcs,
+                               &dm_plane_funcs,
+                               rgb_formats,
+                               ARRAY_SIZE(rgb_formats),
+                               NULL, aplane->base.type, NULL);
+               break;
+       case DRM_PLANE_TYPE_OVERLAY:
+               res = drm_universal_plane_init(
+                               dm->adev->ddev,
+                               &aplane->base,
+                               possible_crtcs,
+                               &dm_plane_funcs,
+                               yuv_formats,
+                               ARRAY_SIZE(yuv_formats),
+                               NULL, aplane->base.type, NULL);
+               break;
+       case DRM_PLANE_TYPE_CURSOR:
+               res = drm_universal_plane_init(
+                               dm->adev->ddev,
+                               &aplane->base,
+                               possible_crtcs,
+                               &dm_plane_funcs,
+                               cursor_formats,
+                               ARRAY_SIZE(cursor_formats),
+                               NULL, aplane->base.type, NULL);
+               break;
+       }
+
+       drm_plane_helper_add(&aplane->base, &dm_plane_helper_funcs);
+
+       /* Create (reset) the plane state */
+       if (aplane->base.funcs->reset)
+               aplane->base.funcs->reset(&aplane->base);
+
+
+       return res;
+}
+
+static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
+                              struct drm_plane *plane,
+                              uint32_t crtc_index)
+{
+       struct amdgpu_crtc *acrtc = NULL;
+       struct amdgpu_plane *cursor_plane;
+
+       int res = -ENOMEM;
+
+       cursor_plane = kzalloc(sizeof(*cursor_plane), GFP_KERNEL);
+       if (!cursor_plane)
+               goto fail;
+
+       cursor_plane->base.type = DRM_PLANE_TYPE_CURSOR;
+       res = amdgpu_dm_plane_init(dm, cursor_plane, 0);
+
+       acrtc = kzalloc(sizeof(struct amdgpu_crtc), GFP_KERNEL);
+       if (!acrtc)
+               goto fail;
+
+       res = drm_crtc_init_with_planes(
+                       dm->ddev,
+                       &acrtc->base,
+                       plane,
+                       &cursor_plane->base,
+                       &amdgpu_dm_crtc_funcs, NULL);
+
+       if (res)
+               goto fail;
+
+       drm_crtc_helper_add(&acrtc->base, &amdgpu_dm_crtc_helper_funcs);
+
+       /* Create (reset) the plane state */
+       if (acrtc->base.funcs->reset)
+               acrtc->base.funcs->reset(&acrtc->base);
+
+       acrtc->max_cursor_width = dm->adev->dm.dc->caps.max_cursor_size;
+       acrtc->max_cursor_height = dm->adev->dm.dc->caps.max_cursor_size;
+
+       acrtc->crtc_id = crtc_index;
+       acrtc->base.enabled = false;
+
+       dm->adev->mode_info.crtcs[crtc_index] = acrtc;
+       drm_mode_crtc_set_gamma_size(&acrtc->base, 256);
+
+       return 0;
+
+fail:
+       kfree(acrtc);
+       kfree(cursor_plane);
+       return res;
+}
+
+
+static int to_drm_connector_type(enum signal_type st)
+{
+       switch (st) {
+       case SIGNAL_TYPE_HDMI_TYPE_A:
+               return DRM_MODE_CONNECTOR_HDMIA;
+       case SIGNAL_TYPE_EDP:
+               return DRM_MODE_CONNECTOR_eDP;
+       case SIGNAL_TYPE_RGB:
+               return DRM_MODE_CONNECTOR_VGA;
+       case SIGNAL_TYPE_DISPLAY_PORT:
+       case SIGNAL_TYPE_DISPLAY_PORT_MST:
+               return DRM_MODE_CONNECTOR_DisplayPort;
+       case SIGNAL_TYPE_DVI_DUAL_LINK:
+       case SIGNAL_TYPE_DVI_SINGLE_LINK:
+               return DRM_MODE_CONNECTOR_DVID;
+       case SIGNAL_TYPE_VIRTUAL:
+               return DRM_MODE_CONNECTOR_VIRTUAL;
+
+       default:
+               return DRM_MODE_CONNECTOR_Unknown;
+       }
+}
+
+static void amdgpu_dm_get_native_mode(struct drm_connector *connector)
+{
+       const struct drm_connector_helper_funcs *helper =
+               connector->helper_private;
+       struct drm_encoder *encoder;
+       struct amdgpu_encoder *amdgpu_encoder;
+
+       encoder = helper->best_encoder(connector);
+
+       if (encoder == NULL)
+               return;
+
+       amdgpu_encoder = to_amdgpu_encoder(encoder);
+
+       amdgpu_encoder->native_mode.clock = 0;
+
+       if (!list_empty(&connector->probed_modes)) {
+               struct drm_display_mode *preferred_mode = NULL;
+
+               list_for_each_entry(preferred_mode,
+                                   &connector->probed_modes,
+                                   head) {
+                       if (preferred_mode->type & DRM_MODE_TYPE_PREFERRED)
+                               amdgpu_encoder->native_mode = *preferred_mode;
+
+                       break;
+               }
+
+       }
+}
+
+static struct drm_display_mode *
+amdgpu_dm_create_common_mode(struct drm_encoder *encoder,
+                            char *name,
+                            int hdisplay, int vdisplay)
+{
+       struct drm_device *dev = encoder->dev;
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       struct drm_display_mode *mode = NULL;
+       struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+
+       mode = drm_mode_duplicate(dev, native_mode);
+
+       if (mode == NULL)
+               return NULL;
+
+       mode->hdisplay = hdisplay;
+       mode->vdisplay = vdisplay;
+       mode->type &= ~DRM_MODE_TYPE_PREFERRED;
+       strncpy(mode->name, name, DRM_DISPLAY_MODE_LEN);
+
+       return mode;
+
+}
+
+static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
+                                                struct drm_connector *connector)
+{
+       struct amdgpu_encoder *amdgpu_encoder = to_amdgpu_encoder(encoder);
+       struct drm_display_mode *mode = NULL;
+       struct drm_display_mode *native_mode = &amdgpu_encoder->native_mode;
+       struct amdgpu_dm_connector *amdgpu_dm_connector =
+                               to_amdgpu_dm_connector(connector);
+       int i;
+       int n;
+       struct mode_size {
+               char name[DRM_DISPLAY_MODE_LEN];
+               int w;
+               int h;
+       } common_modes[] = {
+               {  "640x480",  640,  480},
+               {  "800x600",  800,  600},
+               { "1024x768", 1024,  768},
+               { "1280x720", 1280,  720},
+               { "1280x800", 1280,  800},
+               {"1280x1024", 1280, 1024},
+               { "1440x900", 1440,  900},
+               {"1680x1050", 1680, 1050},
+               {"1600x1200", 1600, 1200},
+               {"1920x1080", 1920, 1080},
+               {"1920x1200", 1920, 1200}
+       };
+
+       n = ARRAY_SIZE(common_modes);
+
+       for (i = 0; i < n; i++) {
+               struct drm_display_mode *curmode = NULL;
+               bool mode_existed = false;
+
+               if (common_modes[i].w > native_mode->hdisplay ||
+                   common_modes[i].h > native_mode->vdisplay ||
+                  (common_modes[i].w == native_mode->hdisplay &&
+                   common_modes[i].h == native_mode->vdisplay))
+                       continue;
+
+               list_for_each_entry(curmode, &connector->probed_modes, head) {
+                       if (common_modes[i].w == curmode->hdisplay &&
+                           common_modes[i].h == curmode->vdisplay) {
+                               mode_existed = true;
+                               break;
+                       }
+               }
+
+               if (mode_existed)
+                       continue;
+
+               mode = amdgpu_dm_create_common_mode(encoder,
+                               common_modes[i].name, common_modes[i].w,
+                               common_modes[i].h);
+               drm_mode_probed_add(connector, mode);
+               amdgpu_dm_connector->num_modes++;
+       }
+}
+
+static void amdgpu_dm_connector_ddc_get_modes(struct drm_connector *connector,
+                                             struct edid *edid)
+{
+       struct amdgpu_dm_connector *amdgpu_dm_connector =
+                       to_amdgpu_dm_connector(connector);
+
+       if (edid) {
+               /* empty probed_modes */
+               INIT_LIST_HEAD(&connector->probed_modes);
+               amdgpu_dm_connector->num_modes =
+                               drm_add_edid_modes(connector, edid);
+
+               drm_edid_to_eld(connector, edid);
+
+               amdgpu_dm_get_native_mode(connector);
+       } else {
+               amdgpu_dm_connector->num_modes = 0;
+       }
+}
+
+static int amdgpu_dm_connector_get_modes(struct drm_connector *connector)
+{
+       const struct drm_connector_helper_funcs *helper =
+                       connector->helper_private;
+       struct amdgpu_dm_connector *amdgpu_dm_connector =
+                       to_amdgpu_dm_connector(connector);
+       struct drm_encoder *encoder;
+       struct edid *edid = amdgpu_dm_connector->edid;
+
+       encoder = helper->best_encoder(connector);
+
+       amdgpu_dm_connector_ddc_get_modes(connector, edid);
+       amdgpu_dm_connector_add_common_modes(encoder, connector);
+       return amdgpu_dm_connector->num_modes;
+}
+
+void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
+                                    struct amdgpu_dm_connector *aconnector,
+                                    int connector_type,
+                                    struct dc_link *link,
+                                    int link_index)
+{
+       struct amdgpu_device *adev = dm->ddev->dev_private;
+
+       aconnector->connector_id = link_index;
+       aconnector->dc_link = link;
+       aconnector->base.interlace_allowed = false;
+       aconnector->base.doublescan_allowed = false;
+       aconnector->base.stereo_allowed = false;
+       aconnector->base.dpms = DRM_MODE_DPMS_OFF;
+       aconnector->hpd.hpd = AMDGPU_HPD_NONE; /* not used */
+
+       mutex_init(&aconnector->hpd_lock);
+
+       /* configure support HPD hot plug connector_>polled default value is 0
+        * which means HPD hot plug not supported
+        */
+       switch (connector_type) {
+       case DRM_MODE_CONNECTOR_HDMIA:
+               aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
+               break;
+       case DRM_MODE_CONNECTOR_DisplayPort:
+               aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
+               break;
+       case DRM_MODE_CONNECTOR_DVID:
+               aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
+               break;
+       default:
+               break;
+       }
+
+       drm_object_attach_property(&aconnector->base.base,
+                               dm->ddev->mode_config.scaling_mode_property,
+                               DRM_MODE_SCALE_NONE);
+
+       drm_object_attach_property(&aconnector->base.base,
+                               adev->mode_info.underscan_property,
+                               UNDERSCAN_OFF);
+       drm_object_attach_property(&aconnector->base.base,
+                               adev->mode_info.underscan_hborder_property,
+                               0);
+       drm_object_attach_property(&aconnector->base.base,
+                               adev->mode_info.underscan_vborder_property,
+                               0);
+
+}
+
+static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap,
+                             struct i2c_msg *msgs, int num)
+{
+       struct amdgpu_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
+       struct ddc_service *ddc_service = i2c->ddc_service;
+       struct i2c_command cmd;
+       int i;
+       int result = -EIO;
+
+       cmd.payloads = kcalloc(num, sizeof(struct i2c_payload), GFP_KERNEL);
+
+       if (!cmd.payloads)
+               return result;
+
+       cmd.number_of_payloads = num;
+       cmd.engine = I2C_COMMAND_ENGINE_DEFAULT;
+       cmd.speed = 100;
+
+       for (i = 0; i < num; i++) {
+               cmd.payloads[i].write = !(msgs[i].flags & I2C_M_RD);
+               cmd.payloads[i].address = msgs[i].addr;
+               cmd.payloads[i].length = msgs[i].len;
+               cmd.payloads[i].data = msgs[i].buf;
+       }
+
+       if (dal_i2caux_submit_i2c_command(
+                       ddc_service->ctx->i2caux,
+                       ddc_service->ddc_pin,
+                       &cmd))
+               result = num;
+
+       kfree(cmd.payloads);
+       return result;
+}
+
+static u32 amdgpu_dm_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm amdgpu_dm_i2c_algo = {
+       .master_xfer = amdgpu_dm_i2c_xfer,
+       .functionality = amdgpu_dm_i2c_func,
+};
+
+static struct amdgpu_i2c_adapter *
+create_i2c(struct ddc_service *ddc_service,
+          int link_index,
+          int *res)
+{
+       struct amdgpu_device *adev = ddc_service->ctx->driver_context;
+       struct amdgpu_i2c_adapter *i2c;
+
+       i2c = kzalloc(sizeof(struct amdgpu_i2c_adapter), GFP_KERNEL);
+       if (!i2c)
+               return NULL;
+       i2c->base.owner = THIS_MODULE;
+       i2c->base.class = I2C_CLASS_DDC;
+       i2c->base.dev.parent = &adev->pdev->dev;
+       i2c->base.algo = &amdgpu_dm_i2c_algo;
+       snprintf(i2c->base.name, sizeof(i2c->base.name), "AMDGPU DM i2c hw bus %d", link_index);
+       i2c_set_adapdata(&i2c->base, i2c);
+       i2c->ddc_service = ddc_service;
+
+       return i2c;
+}
+
+/* Note: this function assumes that dc_link_detect() was called for the
+ * dc_link which will be represented by this aconnector.
+ */
+static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
+                                   struct amdgpu_dm_connector *aconnector,
+                                   uint32_t link_index,
+                                   struct amdgpu_encoder *aencoder)
+{
+       int res = 0;
+       int connector_type;
+       struct dc *dc = dm->dc;
+       struct dc_link *link = dc_get_link_at_index(dc, link_index);
+       struct amdgpu_i2c_adapter *i2c;
+
+       link->priv = aconnector;
+
+       DRM_DEBUG_DRIVER("%s()\n", __func__);
+
+       i2c = create_i2c(link->ddc, link->link_index, &res);
+       if (!i2c) {
+               DRM_ERROR("Failed to create i2c adapter data\n");
+               return -ENOMEM;
+       }
+
+       aconnector->i2c = i2c;
+       res = i2c_add_adapter(&i2c->base);
+
+       if (res) {
+               DRM_ERROR("Failed to register hw i2c %d\n", link->link_index);
+               goto out_free;
+       }
+
+       connector_type = to_drm_connector_type(link->connector_signal);
+
+       res = drm_connector_init(
+                       dm->ddev,
+                       &aconnector->base,
+                       &amdgpu_dm_connector_funcs,
+                       connector_type);
+
+       if (res) {
+               DRM_ERROR("connector_init failed\n");
+               aconnector->connector_id = -1;
+               goto out_free;
+       }
+
+       drm_connector_helper_add(
+                       &aconnector->base,
+                       &amdgpu_dm_connector_helper_funcs);
+
+       if (aconnector->base.funcs->reset)
+               aconnector->base.funcs->reset(&aconnector->base);
+
+       amdgpu_dm_connector_init_helper(
+               dm,
+               aconnector,
+               connector_type,
+               link,
+               link_index);
+
+       drm_mode_connector_attach_encoder(
+               &aconnector->base, &aencoder->base);
+
+       drm_connector_register(&aconnector->base);
+
+       if (connector_type == DRM_MODE_CONNECTOR_DisplayPort
+               || connector_type == DRM_MODE_CONNECTOR_eDP)
+               amdgpu_dm_initialize_dp_connector(dm, aconnector);
+
+#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
+       defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
+
+       /* NOTE: this currently will create backlight device even if a panel
+        * is not connected to the eDP/LVDS connector.
+        *
+        * This is less than ideal but we don't have sink information at this
+        * stage since detection happens after. We can't do detection earlier
+        * since MST detection needs connectors to be created first.
+        */
+       if (link->connector_signal & (SIGNAL_TYPE_EDP | SIGNAL_TYPE_LVDS)) {
+               /* Event if registration failed, we should continue with
+                * DM initialization because not having a backlight control
+                * is better then a black screen.
+                */
+               amdgpu_dm_register_backlight_device(dm);
+
+               if (dm->backlight_dev)
+                       dm->backlight_link = link;
+       }
+#endif
+
+out_free:
+       if (res) {
+               kfree(i2c);
+               aconnector->i2c = NULL;
+       }
+       return res;
+}
+
+int amdgpu_dm_get_encoder_crtc_mask(struct amdgpu_device *adev)
+{
+       switch (adev->mode_info.num_crtc) {
+       case 1:
+               return 0x1;
+       case 2:
+               return 0x3;
+       case 3:
+               return 0x7;
+       case 4:
+               return 0xf;
+       case 5:
+               return 0x1f;
+       case 6:
+       default:
+               return 0x3f;
+       }
+}
+
+static int amdgpu_dm_encoder_init(struct drm_device *dev,
+                                 struct amdgpu_encoder *aencoder,
+                                 uint32_t link_index)
+{
+       struct amdgpu_device *adev = dev->dev_private;
+
+       int res = drm_encoder_init(dev,
+                                  &aencoder->base,
+                                  &amdgpu_dm_encoder_funcs,
+                                  DRM_MODE_ENCODER_TMDS,
+                                  NULL);
+
+       aencoder->base.possible_crtcs = amdgpu_dm_get_encoder_crtc_mask(adev);
+
+       if (!res)
+               aencoder->encoder_id = link_index;
+       else
+               aencoder->encoder_id = -1;
+
+       drm_encoder_helper_add(&aencoder->base, &amdgpu_dm_encoder_helper_funcs);
+
+       return res;
+}
+
+static void manage_dm_interrupts(struct amdgpu_device *adev,
+                                struct amdgpu_crtc *acrtc,
+                                bool enable)
+{
+       /*
+        * this is not correct translation but will work as soon as VBLANK
+        * constant is the same as PFLIP
+        */
+       int irq_type =
+               amdgpu_crtc_idx_to_irq_type(
+                       adev,
+                       acrtc->crtc_id);
+
+       if (enable) {
+               drm_crtc_vblank_on(&acrtc->base);
+               amdgpu_irq_get(
+                       adev,
+                       &adev->pageflip_irq,
+                       irq_type);
+       } else {
+
+               amdgpu_irq_put(
+                       adev,
+                       &adev->pageflip_irq,
+                       irq_type);
+               drm_crtc_vblank_off(&acrtc->base);
+       }
+}
+
+static bool
+is_scaling_state_different(const struct dm_connector_state *dm_state,
+                          const struct dm_connector_state *old_dm_state)
+{
+       if (dm_state->scaling != old_dm_state->scaling)
+               return true;
+       if (!dm_state->underscan_enable && old_dm_state->underscan_enable) {
+               if (old_dm_state->underscan_hborder != 0 && old_dm_state->underscan_vborder != 0)
+                       return true;
+       } else  if (dm_state->underscan_enable && !old_dm_state->underscan_enable) {
+               if (dm_state->underscan_hborder != 0 && dm_state->underscan_vborder != 0)
+                       return true;
+       } else if (dm_state->underscan_hborder != old_dm_state->underscan_hborder ||
+                  dm_state->underscan_vborder != old_dm_state->underscan_vborder)
+               return true;
+       return false;
+}
+
+static void remove_stream(struct amdgpu_device *adev,
+                         struct amdgpu_crtc *acrtc,
+                         struct dc_stream_state *stream)
+{
+       /* this is the update mode case */
+       if (adev->dm.freesync_module)
+               mod_freesync_remove_stream(adev->dm.freesync_module, stream);
+
+       acrtc->otg_inst = -1;
+       acrtc->enabled = false;
+}
+
+static int get_cursor_position(struct drm_plane *plane, struct drm_crtc *crtc,
+                              struct dc_cursor_position *position)
+{
+       struct amdgpu_crtc *amdgpu_crtc = amdgpu_crtc = to_amdgpu_crtc(crtc);
+       int x, y;
+       int xorigin = 0, yorigin = 0;
+
+       if (!crtc || !plane->state->fb) {
+               position->enable = false;
+               position->x = 0;
+               position->y = 0;
+               return 0;
+       }
+
+       if ((plane->state->crtc_w > amdgpu_crtc->max_cursor_width) ||
+           (plane->state->crtc_h > amdgpu_crtc->max_cursor_height)) {
+               DRM_ERROR("%s: bad cursor width or height %d x %d\n",
+                         __func__,
+                         plane->state->crtc_w,
+                         plane->state->crtc_h);
+               return -EINVAL;
+       }
+
+       x = plane->state->crtc_x;
+       y = plane->state->crtc_y;
+       /* avivo cursor are offset into the total surface */
+       x += crtc->primary->state->src_x >> 16;
+       y += crtc->primary->state->src_y >> 16;
+       if (x < 0) {
+               xorigin = min(-x, amdgpu_crtc->max_cursor_width - 1);
+               x = 0;
+       }
+       if (y < 0) {
+               yorigin = min(-y, amdgpu_crtc->max_cursor_height - 1);
+               y = 0;
+       }
+       position->enable = true;
+       position->x = x;
+       position->y = y;
+       position->x_hotspot = xorigin;
+       position->y_hotspot = yorigin;
+
+       return 0;
+}
+
+static void handle_cursor_update(struct drm_plane *plane,
+                                struct drm_plane_state *old_plane_state)
+{
+       struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(plane->state->fb);
+       struct drm_crtc *crtc = afb ? plane->state->crtc : old_plane_state->crtc;
+       struct dm_crtc_state *crtc_state = crtc ? to_dm_crtc_state(crtc->state) : NULL;
+       struct amdgpu_crtc *amdgpu_crtc = to_amdgpu_crtc(crtc);
+       uint64_t address = afb ? afb->address : 0;
+       struct dc_cursor_position position;
+       struct dc_cursor_attributes attributes;
+       int ret;
+
+       if (!plane->state->fb && !old_plane_state->fb)
+               return;
+
+       DRM_DEBUG_DRIVER("%s: crtc_id=%d with size %d to %d\n",
+                        __func__,
+                        amdgpu_crtc->crtc_id,
+                        plane->state->crtc_w,
+                        plane->state->crtc_h);
+
+       ret = get_cursor_position(plane, crtc, &position);
+       if (ret)
+               return;
+
+       if (!position.enable) {
+               /* turn off cursor */
+               if (crtc_state && crtc_state->stream)
+                       dc_stream_set_cursor_position(crtc_state->stream,
+                                                     &position);
+               return;
+       }
+
+       amdgpu_crtc->cursor_width = plane->state->crtc_w;
+       amdgpu_crtc->cursor_height = plane->state->crtc_h;
+
+       attributes.address.high_part = upper_32_bits(address);
+       attributes.address.low_part  = lower_32_bits(address);
+       attributes.width             = plane->state->crtc_w;
+       attributes.height            = plane->state->crtc_h;
+       attributes.color_format      = CURSOR_MODE_COLOR_PRE_MULTIPLIED_ALPHA;
+       attributes.rotation_angle    = 0;
+       attributes.attribute_flags.value = 0;
+
+       attributes.pitch = attributes.width;
+
+       if (crtc_state->stream) {
+               if (!dc_stream_set_cursor_attributes(crtc_state->stream,
+                                                        &attributes))
+                       DRM_ERROR("DC failed to set cursor attributes\n");
+
+               if (!dc_stream_set_cursor_position(crtc_state->stream,
+                                                  &position))
+                       DRM_ERROR("DC failed to set cursor position\n");
+       }
+}
+
+static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
+{
+
+       assert_spin_locked(&acrtc->base.dev->event_lock);
+       WARN_ON(acrtc->event);
+
+       acrtc->event = acrtc->base.state->event;
+
+       /* Set the flip status */
+       acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
+
+       /* Mark this event as consumed */
+       acrtc->base.state->event = NULL;
+
+       DRM_DEBUG_DRIVER("crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
+                                                acrtc->crtc_id);
+}
+
+/*
+ * Executes flip
+ *
+ * Waits on all BO's fences and for proper vblank count
+ */
+static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
+                             struct drm_framebuffer *fb,
+                             uint32_t target,
+                             struct dc_state *state)
+{
+       unsigned long flags;
+       uint32_t target_vblank;
+       int r, vpos, hpos;
+       struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+       struct amdgpu_framebuffer *afb = to_amdgpu_framebuffer(fb);
+       struct amdgpu_bo *abo = gem_to_amdgpu_bo(afb->obj);
+       struct amdgpu_device *adev = crtc->dev->dev_private;
+       bool async_flip = (crtc->state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC) != 0;
+       struct dc_flip_addrs addr = { {0} };
+       /* TODO eliminate or rename surface_update */
+       struct dc_surface_update surface_updates[1] = { {0} };
+       struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
+
+
+       /* Prepare wait for target vblank early - before the fence-waits */
+       target_vblank = target - drm_crtc_vblank_count(crtc) +
+                       amdgpu_get_vblank_counter_kms(crtc->dev, acrtc->crtc_id);
+
+       /* TODO This might fail and hence better not used, wait
+        * explicitly on fences instead
+        * and in general should be called for
+        * blocking commit to as per framework helpers
+        */
+       r = amdgpu_bo_reserve(abo, true);
+       if (unlikely(r != 0)) {
+               DRM_ERROR("failed to reserve buffer before flip\n");
+               WARN_ON(1);
+       }
+
+       /* Wait for all fences on this FB */
+       WARN_ON(reservation_object_wait_timeout_rcu(abo->tbo.resv, true, false,
+                                                                   MAX_SCHEDULE_TIMEOUT) < 0);
+
+       amdgpu_bo_unreserve(abo);
+
+       /* Wait until we're out of the vertical blank period before the one
+        * targeted by the flip
+        */
+       while ((acrtc->enabled &&
+               (amdgpu_get_crtc_scanoutpos(adev->ddev, acrtc->crtc_id, 0,
+                                       &vpos, &hpos, NULL, NULL,
+                                       &crtc->hwmode)
+                & (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK)) ==
+               (DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_IN_VBLANK) &&
+               (int)(target_vblank -
+                 amdgpu_get_vblank_counter_kms(adev->ddev, acrtc->crtc_id)) > 0)) {
+               usleep_range(1000, 1100);
+       }
+
+       /* Flip */
+       spin_lock_irqsave(&crtc->dev->event_lock, flags);
+       /* update crtc fb */
+       crtc->primary->fb = fb;
+
+       WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
+       WARN_ON(!acrtc_state->stream);
+
+       addr.address.grph.addr.low_part = lower_32_bits(afb->address);
+       addr.address.grph.addr.high_part = upper_32_bits(afb->address);
+       addr.flip_immediate = async_flip;
+
+
+       if (acrtc->base.state->event)
+               prepare_flip_isr(acrtc);
+
+       surface_updates->surface = dc_stream_get_status(acrtc_state->stream)->plane_states[0];
+       surface_updates->flip_addr = &addr;
+
+
+       dc_commit_updates_for_stream(adev->dm.dc,
+                                            surface_updates,
+                                            1,
+                                            acrtc_state->stream,
+                                            NULL,
+                                            &surface_updates->surface,
+                                            state);
+
+       DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n",
+                        __func__,
+                        addr.address.grph.addr.high_part,
+                        addr.address.grph.addr.low_part);
+
+
+       spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+}
+
+static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
+                                   struct drm_device *dev,
+                                   struct amdgpu_display_manager *dm,
+                                   struct drm_crtc *pcrtc,
+                                   bool *wait_for_vblank)
+{
+       uint32_t i;
+       struct drm_plane *plane;
+       struct drm_plane_state *old_plane_state, *new_plane_state;
+       struct dc_stream_state *dc_stream_attach;
+       struct dc_plane_state *plane_states_constructed[MAX_SURFACES];
+       struct amdgpu_crtc *acrtc_attach = to_amdgpu_crtc(pcrtc);
+       struct drm_crtc_state *new_pcrtc_state =
+                       drm_atomic_get_new_crtc_state(state, pcrtc);
+       struct dm_crtc_state *acrtc_state = to_dm_crtc_state(new_pcrtc_state);
+       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
+       int planes_count = 0;
+       unsigned long flags;
+
+       /* update planes when needed */
+       for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
+               struct drm_crtc *crtc = new_plane_state->crtc;
+               struct drm_crtc_state *new_crtc_state;
+               struct drm_framebuffer *fb = new_plane_state->fb;
+               bool pflip_needed;
+               struct dm_plane_state *dm_new_plane_state = to_dm_plane_state(new_plane_state);
+
+               if (plane->type == DRM_PLANE_TYPE_CURSOR) {
+                       handle_cursor_update(plane, old_plane_state);
+                       continue;
+               }
+
+               if (!fb || !crtc || pcrtc != crtc)
+                       continue;
+
+               new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+               if (!new_crtc_state->active)
+                       continue;
+
+               pflip_needed = !state->allow_modeset;
+
+               spin_lock_irqsave(&crtc->dev->event_lock, flags);
+               if (acrtc_attach->pflip_status != AMDGPU_FLIP_NONE) {
+                       DRM_ERROR("%s: acrtc %d, already busy\n",
+                                 __func__,
+                                 acrtc_attach->crtc_id);
+                       /* In commit tail framework this cannot happen */
+                       WARN_ON(1);
+               }
+               spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
+
+               if (!pflip_needed) {
+                       WARN_ON(!dm_new_plane_state->dc_state);
+
+                       plane_states_constructed[planes_count] = dm_new_plane_state->dc_state;
+
+                       dc_stream_attach = acrtc_state->stream;
+                       planes_count++;
+
+               } else if (new_crtc_state->planes_changed) {
+                       /* Assume even ONE crtc with immediate flip means
+                        * entire can't wait for VBLANK
+                        * TODO Check if it's correct
+                        */
+                       *wait_for_vblank =
+                                       new_pcrtc_state->pageflip_flags & DRM_MODE_PAGE_FLIP_ASYNC ?
+                               false : true;
+
+                       /* TODO: Needs rework for multiplane flip */
+                       if (plane->type == DRM_PLANE_TYPE_PRIMARY)
+                               drm_crtc_vblank_get(crtc);
+
+                       amdgpu_dm_do_flip(
+                               crtc,
+                               fb,
+                               drm_crtc_vblank_count(crtc) + *wait_for_vblank,
+                               dm_state->context);
+               }
+
+       }
+
+       if (planes_count) {
+               unsigned long flags;
+
+               if (new_pcrtc_state->event) {
+
+                       drm_crtc_vblank_get(pcrtc);
+
+                       spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
+                       prepare_flip_isr(acrtc_attach);
+                       spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
+               }
+
+               if (false == dc_commit_planes_to_stream(dm->dc,
+                                                       plane_states_constructed,
+                                                       planes_count,
+                                                       dc_stream_attach,
+                                                       dm_state->context))
+                       dm_error("%s: Failed to attach plane!\n", __func__);
+       } else {
+               /*TODO BUG Here should go disable planes on CRTC. */
+       }
+}
+
+
+static int amdgpu_dm_atomic_commit(struct drm_device *dev,
+                                  struct drm_atomic_state *state,
+                                  bool nonblock)
+{
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct amdgpu_device *adev = dev->dev_private;
+       int i;
+
+       /*
+        * We evade vblanks and pflips on crtc that
+        * should be changed. We do it here to flush & disable
+        * interrupts before drm_swap_state is called in drm_atomic_helper_commit
+        * it will update crtc->dm_crtc_state->stream pointer which is used in
+        * the ISRs.
+        */
+       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+
+               if (drm_atomic_crtc_needs_modeset(new_crtc_state) && dm_old_crtc_state->stream)
+                       manage_dm_interrupts(adev, acrtc, false);
+       }
+       /* Add check here for SoC's that support hardware cursor plane, to
+        * unset legacy_cursor_update */
+
+       return drm_atomic_helper_commit(dev, state, nonblock);
+
+       /*TODO Handle EINTR, reenable IRQ*/
+}
+
+static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
+{
+       struct drm_device *dev = state->dev;
+       struct amdgpu_device *adev = dev->dev_private;
+       struct amdgpu_display_manager *dm = &adev->dm;
+       struct dm_atomic_state *dm_state;
+       uint32_t i, j;
+       uint32_t new_crtcs_count = 0;
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct amdgpu_crtc *new_crtcs[MAX_STREAMS];
+       struct dc_stream_state *new_stream = NULL;
+       unsigned long flags;
+       bool wait_for_vblank = true;
+       struct drm_connector *connector;
+       struct drm_connector_state *old_con_state, *new_con_state;
+       struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
+
+       drm_atomic_helper_update_legacy_modeset_state(dev, state);
+
+       dm_state = to_dm_atomic_state(state);
+
+       /* update changed items */
+       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+               dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+
+               DRM_DEBUG_DRIVER(
+                       "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
+                       "planes_changed:%d, mode_changed:%d,active_changed:%d,"
+                       "connectors_changed:%d\n",
+                       acrtc->crtc_id,
+                       new_crtc_state->enable,
+                       new_crtc_state->active,
+                       new_crtc_state->planes_changed,
+                       new_crtc_state->mode_changed,
+                       new_crtc_state->active_changed,
+                       new_crtc_state->connectors_changed);
+
+               /* handles headless hotplug case, updating new_state and
+                * aconnector as needed
+                */
+
+               if (modeset_required(new_crtc_state, dm_new_crtc_state->stream, dm_old_crtc_state->stream)) {
+
+                       DRM_DEBUG_DRIVER("Atomic commit: SET crtc id %d: [%p]\n", acrtc->crtc_id, acrtc);
+
+                       if (!dm_new_crtc_state->stream) {
+                               /*
+                                * this could happen because of issues with
+                                * userspace notifications delivery.
+                                * In this case userspace tries to set mode on
+                                * display which is disconnect in fact.
+                                * dc_sink in NULL in this case on aconnector.
+                                * We expect reset mode will come soon.
+                                *
+                                * This can also happen when unplug is done
+                                * during resume sequence ended
+                                *
+                                * In this case, we want to pretend we still
+                                * have a sink to keep the pipe running so that
+                                * hw state is consistent with the sw state
+                                */
+                               DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n",
+                                               __func__, acrtc->base.base.id);
+                               continue;
+                       }
+
+
+                       if (dm_old_crtc_state->stream)
+                               remove_stream(adev, acrtc, dm_old_crtc_state->stream);
+
+
+                       /*
+                        * this loop saves set mode crtcs
+                        * we needed to enable vblanks once all
+                        * resources acquired in dc after dc_commit_streams
+                        */
+
+                       /*TODO move all this into dm_crtc_state, get rid of
+                        * new_crtcs array and use old and new atomic states
+                        * instead
+                        */
+                       new_crtcs[new_crtcs_count] = acrtc;
+                       new_crtcs_count++;
+
+                       new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+                       acrtc->enabled = true;
+                       acrtc->hw_mode = new_crtc_state->mode;
+                       crtc->hwmode = new_crtc_state->mode;
+               } else if (modereset_required(new_crtc_state)) {
+                       DRM_DEBUG_DRIVER("Atomic commit: RESET. crtc id %d:[%p]\n", acrtc->crtc_id, acrtc);
+
+                       /* i.e. reset mode */
+                       if (dm_old_crtc_state->stream)
+                               remove_stream(adev, acrtc, dm_old_crtc_state->stream);
+               }
+       } /* for_each_crtc_in_state() */
+
+       /*
+        * Add streams after required streams from new and replaced streams
+        * are removed from freesync module
+        */
+       if (adev->dm.freesync_module) {
+               for (i = 0; i < new_crtcs_count; i++) {
+                       struct amdgpu_dm_connector *aconnector = NULL;
+
+                       new_crtc_state = drm_atomic_get_new_crtc_state(state,
+                                       &new_crtcs[i]->base);
+                       dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+                       new_stream = dm_new_crtc_state->stream;
+                       aconnector = amdgpu_dm_find_first_crtc_matching_connector(
+                                       state,
+                                       &new_crtcs[i]->base);
+                       if (!aconnector) {
+                               DRM_DEBUG_DRIVER("Atomic commit: Failed to find connector for acrtc id:%d "
+                                        "skipping freesync init\n",
+                                        new_crtcs[i]->crtc_id);
+                               continue;
+                       }
+
+                       mod_freesync_add_stream(adev->dm.freesync_module,
+                                               new_stream, &aconnector->caps);
+               }
+       }
+
+       if (dm_state->context)
+               WARN_ON(!dc_commit_state(dm->dc, dm_state->context));
+
+       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+               if (dm_new_crtc_state->stream != NULL) {
+                       const struct dc_stream_status *status =
+                                       dc_stream_get_status(dm_new_crtc_state->stream);
+
+                       if (!status)
+                               DC_ERR("got no status for stream %p on acrtc%p\n", dm_new_crtc_state->stream, acrtc);
+                       else
+                               acrtc->otg_inst = status->primary_otg_inst;
+               }
+       }
+
+       /* Handle scaling and underscan changes*/
+       for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) {
+               struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state);
+               struct dm_connector_state *dm_old_con_state = to_dm_connector_state(old_con_state);
+               struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc);
+               struct dc_stream_status *status = NULL;
+
+               if (acrtc)
+                       new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
+
+               /* Skip any modesets/resets */
+               if (!acrtc || drm_atomic_crtc_needs_modeset(new_crtc_state))
+                       continue;
+
+               /* Skip any thing not scale or underscan changes */
+               if (!is_scaling_state_different(dm_new_con_state, dm_old_con_state))
+                       continue;
+
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+               update_stream_scaling_settings(&dm_new_con_state->base.crtc->mode,
+                               dm_new_con_state, (struct dc_stream_state *)dm_new_crtc_state->stream);
+
+               status = dc_stream_get_status(dm_new_crtc_state->stream);
+               WARN_ON(!status);
+               WARN_ON(!status->plane_count);
+
+               if (!dm_new_crtc_state->stream)
+                       continue;
+
+               /*TODO How it works with MPO ?*/
+               if (!dc_commit_planes_to_stream(
+                               dm->dc,
+                               status->plane_states,
+                               status->plane_count,
+                               dm_new_crtc_state->stream,
+                               dm_state->context))
+                       dm_error("%s: Failed to update stream scaling!\n", __func__);
+       }
+
+       for (i = 0; i < new_crtcs_count; i++) {
+               /*
+                * loop to enable interrupts on newly arrived crtc
+                */
+               struct amdgpu_crtc *acrtc = new_crtcs[i];
+
+               new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base);
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+               if (adev->dm.freesync_module)
+                       mod_freesync_notify_mode_change(
+                               adev->dm.freesync_module, &dm_new_crtc_state->stream, 1);
+
+               manage_dm_interrupts(adev, acrtc, true);
+       }
+
+       /* update planes when needed per crtc*/
+       for_each_new_crtc_in_state(state, crtc, new_crtc_state, j) {
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+               if (dm_new_crtc_state->stream)
+                       amdgpu_dm_commit_planes(state, dev, dm, crtc, &wait_for_vblank);
+       }
+
+
+       /*
+        * send vblank event on all events not handled in flip and
+        * mark consumed event for drm_atomic_helper_commit_hw_done
+        */
+       spin_lock_irqsave(&adev->ddev->event_lock, flags);
+       for_each_new_crtc_in_state(state, crtc, new_crtc_state, i) {
+
+               if (new_crtc_state->event)
+                       drm_send_event_locked(dev, &new_crtc_state->event->base);
+
+               new_crtc_state->event = NULL;
+       }
+       spin_unlock_irqrestore(&adev->ddev->event_lock, flags);
+
+       /* Signal HW programming completion */
+       drm_atomic_helper_commit_hw_done(state);
+
+       if (wait_for_vblank)
+               drm_atomic_helper_wait_for_vblanks(dev, state);
+
+       drm_atomic_helper_cleanup_planes(dev, state);
+}
+
+
+static int dm_force_atomic_commit(struct drm_connector *connector)
+{
+       int ret = 0;
+       struct drm_device *ddev = connector->dev;
+       struct drm_atomic_state *state = drm_atomic_state_alloc(ddev);
+       struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
+       struct drm_plane *plane = disconnected_acrtc->base.primary;
+       struct drm_connector_state *conn_state;
+       struct drm_crtc_state *crtc_state;
+       struct drm_plane_state *plane_state;
+
+       if (!state)
+               return -ENOMEM;
+
+       state->acquire_ctx = ddev->mode_config.acquire_ctx;
+
+       /* Construct an atomic state to restore previous display setting */
+
+       /*
+        * Attach connectors to drm_atomic_state
+        */
+       conn_state = drm_atomic_get_connector_state(state, connector);
+
+       ret = PTR_ERR_OR_ZERO(conn_state);
+       if (ret)
+               goto err;
+
+       /* Attach crtc to drm_atomic_state*/
+       crtc_state = drm_atomic_get_crtc_state(state, &disconnected_acrtc->base);
+
+       ret = PTR_ERR_OR_ZERO(crtc_state);
+       if (ret)
+               goto err;
+
+       /* force a restore */
+       crtc_state->mode_changed = true;
+
+       /* Attach plane to drm_atomic_state */
+       plane_state = drm_atomic_get_plane_state(state, plane);
+
+       ret = PTR_ERR_OR_ZERO(plane_state);
+       if (ret)
+               goto err;
+
+
+       /* Call commit internally with the state we just constructed */
+       ret = drm_atomic_commit(state);
+       if (!ret)
+               return 0;
+
+err:
+       DRM_ERROR("Restoring old state failed with %i\n", ret);
+       drm_atomic_state_put(state);
+
+       return ret;
+}
+
+/*
+ * This functions handle all cases when set mode does not come upon hotplug.
+ * This include when the same display is unplugged then plugged back into the
+ * same port and when we are running without usermode desktop manager supprot
+ */
+void dm_restore_drm_connector_state(struct drm_device *dev,
+                                   struct drm_connector *connector)
+{
+       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
+       struct amdgpu_crtc *disconnected_acrtc;
+       struct dm_crtc_state *acrtc_state;
+
+       if (!aconnector->dc_sink || !connector->state || !connector->encoder)
+               return;
+
+       disconnected_acrtc = to_amdgpu_crtc(connector->encoder->crtc);
+       acrtc_state = to_dm_crtc_state(disconnected_acrtc->base.state);
+
+       if (!disconnected_acrtc || !acrtc_state->stream)
+               return;
+
+       /*
+        * If the previous sink is not released and different from the current,
+        * we deduce we are in a state where we can not rely on usermode call
+        * to turn on the display, so we do it here
+        */
+       if (acrtc_state->stream->sink != aconnector->dc_sink)
+               dm_force_atomic_commit(&aconnector->base);
+}
+
+/*`
+ * Grabs all modesetting locks to serialize against any blocking commits,
+ * Waits for completion of all non blocking commits.
+ */
+static int do_aquire_global_lock(struct drm_device *dev,
+                                struct drm_atomic_state *state)
+{
+       struct drm_crtc *crtc;
+       struct drm_crtc_commit *commit;
+       long ret;
+
+       /* Adding all modeset locks to aquire_ctx will
+        * ensure that when the framework release it the
+        * extra locks we are locking here will get released to
+        */
+       ret = drm_modeset_lock_all_ctx(dev, state->acquire_ctx);
+       if (ret)
+               return ret;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               spin_lock(&crtc->commit_lock);
+               commit = list_first_entry_or_null(&crtc->commit_list,
+                               struct drm_crtc_commit, commit_entry);
+               if (commit)
+                       drm_crtc_commit_get(commit);
+               spin_unlock(&crtc->commit_lock);
+
+               if (!commit)
+                       continue;
+
+               /* Make sure all pending HW programming completed and
+                * page flips done
+                */
+               ret = wait_for_completion_interruptible_timeout(&commit->hw_done, 10*HZ);
+
+               if (ret > 0)
+                       ret = wait_for_completion_interruptible_timeout(
+                                       &commit->flip_done, 10*HZ);
+
+               if (ret == 0)
+                       DRM_ERROR("[CRTC:%d:%s] hw_done or flip_done "
+                                 "timed out\n", crtc->base.id, crtc->name);
+
+               drm_crtc_commit_put(commit);
+       }
+
+       return ret < 0 ? ret : 0;
+}
+
+static int dm_update_crtcs_state(struct dc *dc,
+                                struct drm_atomic_state *state,
+                                bool enable,
+                                bool *lock_and_validation_needed)
+{
+       struct drm_crtc *crtc;
+       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       int i;
+       struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
+       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
+       struct dc_stream_state *new_stream;
+       int ret = 0;
+
+       /*TODO Move this code into dm_crtc_atomic_check once we get rid of dc_validation_set */
+       /* update changed items */
+       for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+               struct amdgpu_crtc *acrtc = NULL;
+               struct amdgpu_dm_connector *aconnector = NULL;
+               struct drm_connector_state *new_con_state = NULL;
+               struct dm_connector_state *dm_conn_state = NULL;
+
+               new_stream = NULL;
+
+               dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+               acrtc = to_amdgpu_crtc(crtc);
+
+               aconnector = amdgpu_dm_find_first_crtc_matching_connector(state, crtc);
+
+               /* TODO This hack should go away */
+               if (aconnector && enable) {
+                       // Make sure fake sink is created in plug-in scenario
+                       new_con_state = drm_atomic_get_connector_state(state,
+                                                                   &aconnector->base);
+
+                       if (IS_ERR(new_con_state)) {
+                               ret = PTR_ERR_OR_ZERO(new_con_state);
+                               break;
+                       }
+
+                       dm_conn_state = to_dm_connector_state(new_con_state);
+
+                       new_stream = create_stream_for_sink(aconnector,
+                                                            &new_crtc_state->mode,
+                                                           dm_conn_state);
+
+                       /*
+                        * we can have no stream on ACTION_SET if a display
+                        * was disconnected during S3, in this case it not and
+                        * error, the OS will be updated after detection, and
+                        * do the right thing on next atomic commit
+                        */
+
+                       if (!new_stream) {
+                               DRM_DEBUG_DRIVER("%s: Failed to create new stream for crtc %d\n",
+                                               __func__, acrtc->base.base.id);
+                               break;
+                       }
+               }
+
+               if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
+                               dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) {
+
+                       new_crtc_state->mode_changed = false;
+
+                       DRM_DEBUG_DRIVER("Mode change not required, setting mode_changed to %d",
+                                        new_crtc_state->mode_changed);
+               }
+
+
+               if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
+                       goto next_crtc;
+
+               DRM_DEBUG_DRIVER(
+                       "amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
+                       "planes_changed:%d, mode_changed:%d,active_changed:%d,"
+                       "connectors_changed:%d\n",
+                       acrtc->crtc_id,
+                       new_crtc_state->enable,
+                       new_crtc_state->active,
+                       new_crtc_state->planes_changed,
+                       new_crtc_state->mode_changed,
+                       new_crtc_state->active_changed,
+                       new_crtc_state->connectors_changed);
+
+               /* Remove stream for any changed/disabled CRTC */
+               if (!enable) {
+
+                       if (!dm_old_crtc_state->stream)
+                               goto next_crtc;
+
+                       DRM_DEBUG_DRIVER("Disabling DRM crtc: %d\n",
+                                       crtc->base.id);
+
+                       /* i.e. reset mode */
+                       if (dc_remove_stream_from_ctx(
+                                       dc,
+                                       dm_state->context,
+                                       dm_old_crtc_state->stream) != DC_OK) {
+                               ret = -EINVAL;
+                               goto fail;
+                       }
+
+                       dc_stream_release(dm_old_crtc_state->stream);
+                       dm_new_crtc_state->stream = NULL;
+
+                       *lock_and_validation_needed = true;
+
+               } else {/* Add stream for any updated/enabled CRTC */
+                       /*
+                        * Quick fix to prevent NULL pointer on new_stream when
+                        * added MST connectors not found in existing crtc_state in the chained mode
+                        * TODO: need to dig out the root cause of that
+                        */
+                       if (!aconnector || (!aconnector->dc_sink && aconnector->mst_port))
+                               goto next_crtc;
+
+                       if (modereset_required(new_crtc_state))
+                               goto next_crtc;
+
+                       if (modeset_required(new_crtc_state, new_stream,
+                                            dm_old_crtc_state->stream)) {
+
+                               WARN_ON(dm_new_crtc_state->stream);
+
+                               dm_new_crtc_state->stream = new_stream;
+                               dc_stream_retain(new_stream);
+
+                               DRM_DEBUG_DRIVER("Enabling DRM crtc: %d\n",
+                                                       crtc->base.id);
+
+                               if (dc_add_stream_to_ctx(
+                                               dc,
+                                               dm_state->context,
+                                               dm_new_crtc_state->stream) != DC_OK) {
+                                       ret = -EINVAL;
+                                       goto fail;
+                               }
+
+                               *lock_and_validation_needed = true;
+                       }
+               }
+
+next_crtc:
+               /* Release extra reference */
+               if (new_stream)
+                        dc_stream_release(new_stream);
+       }
+
+       return ret;
+
+fail:
+       if (new_stream)
+               dc_stream_release(new_stream);
+       return ret;
+}
+
+static int dm_update_planes_state(struct dc *dc,
+                                 struct drm_atomic_state *state,
+                                 bool enable,
+                                 bool *lock_and_validation_needed)
+{
+       struct drm_crtc *new_plane_crtc, *old_plane_crtc;
+       struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+       struct drm_plane *plane;
+       struct drm_plane_state *old_plane_state, *new_plane_state;
+       struct dm_crtc_state *dm_new_crtc_state, *dm_old_crtc_state;
+       struct dm_atomic_state *dm_state = to_dm_atomic_state(state);
+       struct dm_plane_state *dm_new_plane_state, *dm_old_plane_state;
+       int i ;
+       /* TODO return page_flip_needed() function */
+       bool pflip_needed  = !state->allow_modeset;
+       int ret = 0;
+
+       if (pflip_needed)
+               return ret;
+
+       /* Add new planes */
+       for_each_oldnew_plane_in_state(state, plane, old_plane_state, new_plane_state, i) {
+               new_plane_crtc = new_plane_state->crtc;
+               old_plane_crtc = old_plane_state->crtc;
+               dm_new_plane_state = to_dm_plane_state(new_plane_state);
+               dm_old_plane_state = to_dm_plane_state(old_plane_state);
+
+               /*TODO Implement atomic check for cursor plane */
+            &nbs