aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/amd/display
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2022-08-02 10:06:12 -0700
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2022-08-02 10:06:12 -0700
commit8bb5e7f4dcd9b9ef22a3ea25c9066a8a968f12dd (patch)
tree0f1383880607a227142f9388a066959926233ff1 /drivers/gpu/drm/amd/display
parentInput: document the units for resolution of size axes (diff)
parentInput: adc-joystick - fix ordering in adc_joystick_probe() (diff)
downloadlinux-rng-8bb5e7f4dcd9b9ef22a3ea25c9066a8a968f12dd.tar.xz
linux-rng-8bb5e7f4dcd9b9ef22a3ea25c9066a8a968f12dd.zip
Merge branch 'next' into for-linus
Prepare input updates for 5.20 (or 6.0) merge window.
Diffstat (limited to 'drivers/gpu/drm/amd/display')
-rw-r--r--drivers/gpu/drm/amd/display/Kconfig1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c335
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h27
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c179
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c6
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c205
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c6
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c295
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h17
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c248
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c77
-rw-r--r--drivers/gpu/drm/amd/display/dc/Makefile10
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table2.c4
-rw-r--r--drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/calcs/Makefile68
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile19
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c37
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c19
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c18
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.h67
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h74
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c45
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c687
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.h49
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c349
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.h130
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c719
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.h49
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.c338
-rw-r--r--drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.h139
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc.c185
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_debug.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link.c1146
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c11
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c1974
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c31
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c917
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_resource.c229
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_stream.c49
-rw-r--r--drivers/gpu/drm/amd/display/dc/core/dc_surface.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc.h133
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dp_types.h102
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_helper.c60
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_hw_types.h20
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_link.h70
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_stream.h13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_types.h7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_aux.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c135
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c26
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_i2c.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c17
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c25
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c7
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c207
-rw-r--r--drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c134
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c93
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/Makefile25
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h15
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c97
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c1375
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h31
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn21/Makefile25
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c567
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c18
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c10
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c531
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c1
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn302/Makefile12
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c328
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn303/Makefile26
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c333
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/Makefile26
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c174
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c62
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c39
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c31
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c413
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h16
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn315/Makefile30
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c2053
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h45
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn316/Makefile30
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c2055
-rw-r--r--drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h45
-rw-r--r--drivers/gpu/drm/amd/display/dc/dm_helpers.h11
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/Makefile21
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/calcs/bw_fixed.c (renamed from drivers/gpu/drm/amd/display/dc/calcs/bw_fixed.c)0
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/calcs/calcs_logger.h (renamed from drivers/gpu/drm/amd/display/dc/calcs/calcs_logger.h)0
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/calcs/custom_float.c (renamed from drivers/gpu/drm/amd/display/dc/calcs/custom_float.c)0
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c (renamed from drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c)48
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_auto.c (renamed from drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c)0
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_auto.h (renamed from drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.h)0
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_math.c (renamed from drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.c)0
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c (renamed from drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c)19
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c123
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h30
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c1936
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h51
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c617
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.h67
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c357
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.h32
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c362
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.h32
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c784
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h44
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c29
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c13
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c24
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c8
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/Makefile11
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_factory_dcn315.c260
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_factory_dcn315.h31
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.c374
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.h33
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c6
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/core_types.h37
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h61
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h22
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h5
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h1
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h6
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h4
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h8
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/link_hwss.h93
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/reg_helper.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/inc/resource.h16
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/Makefile11
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c2
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c14
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c9
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.h3
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c438
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/irq/irq_service.c5
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/Makefile30
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c166
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h62
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c189
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h54
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c79
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c290
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h35
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.c62
-rw-r--r--drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h34
-rw-r--r--drivers/gpu/drm/amd/display/dc/os_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/dc/virtual/Makefile2
-rw-r--r--drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c3
-rw-r--r--drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.c48
-rw-r--r--drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.h35
-rw-r--r--drivers/gpu/drm/amd/display/dmub/dmub_srv.h3
-rw-r--r--drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h205
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/Makefile2
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c14
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h3
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn315.c62
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn315.h68
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn316.c62
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_dcn316.h33
-rw-r--r--drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c11
-rw-r--r--drivers/gpu/drm/amd/display/include/bios_parser_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/include/dal_asic_id.h13
-rw-r--r--drivers/gpu/drm/amd/display/include/dal_types.h2
-rw-r--r--drivers/gpu/drm/amd/display/include/ddc_service_types.h11
-rw-r--r--drivers/gpu/drm/amd/display/include/dpcd_defs.h6
-rw-r--r--drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h22
-rw-r--r--drivers/gpu/drm/amd/display/include/grph_object_defs.h2
-rw-r--r--drivers/gpu/drm/amd/display/include/grph_object_id.h3
-rw-r--r--drivers/gpu/drm/amd/display/include/link_service_types.h12
-rw-r--r--drivers/gpu/drm/amd/display/modules/freesync/freesync.c76
-rw-r--r--drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c38
-rw-r--r--drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h12
-rw-r--r--drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c6
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h12
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h2
-rw-r--r--drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h3
-rw-r--r--drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c30
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power_helpers.c38
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power_helpers.h1
260 files changed, 19086 insertions, 7599 deletions
diff --git a/drivers/gpu/drm/amd/display/Kconfig b/drivers/gpu/drm/amd/display/Kconfig
index 127667e549c1..b4029c0d5d8c 100644
--- a/drivers/gpu/drm/amd/display/Kconfig
+++ b/drivers/gpu/drm/amd/display/Kconfig
@@ -20,6 +20,7 @@ config DRM_AMD_DC_DCN
config DRM_AMD_DC_HDCP
bool "Enable HDCP support in DC"
depends on DRM_AMD_DC
+ select DRM_DISPLAY_HDCP_HELPER
help
Choose this option if you want to support HDCP authentication.
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index 075429bea427..9dd2e0601ea8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -48,7 +48,7 @@
#include "amdgpu_dm.h"
#ifdef CONFIG_DRM_AMD_DC_HDCP
#include "amdgpu_dm_hdcp.h"
-#include <drm/drm_hdcp.h>
+#include <drm/display/drm_hdcp_helper.h>
#endif
#include "amdgpu_pm.h"
#include "amdgpu_atombios.h"
@@ -73,17 +73,17 @@
#include <linux/firmware.h>
#include <linux/component.h>
+#include <drm/display/drm_dp_mst_helper.h>
+#include <drm/display/drm_hdmi_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_uapi.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_fb_helper.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_edid.h>
#include <drm/drm_vblank.h>
#include <drm/drm_audio_component.h>
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
#include "dcn/dcn_1_0_offset.h"
@@ -92,7 +92,6 @@
#include "vega10_ip_offset.h"
#include "soc15_common.h"
-#endif
#include "modules/inc/mod_freesync.h"
#include "modules/power/power_helpers.h"
@@ -114,6 +113,10 @@ MODULE_FIRMWARE(FIRMWARE_DIMGREY_CAVEFISH_DMUB);
MODULE_FIRMWARE(FIRMWARE_BEIGE_GOBY_DMUB);
#define FIRMWARE_YELLOW_CARP_DMUB "amdgpu/yellow_carp_dmcub.bin"
MODULE_FIRMWARE(FIRMWARE_YELLOW_CARP_DMUB);
+#define FIRMWARE_DCN_315_DMUB "amdgpu/dcn_3_1_5_dmcub.bin"
+MODULE_FIRMWARE(FIRMWARE_DCN_315_DMUB);
+#define FIRMWARE_DCN316_DMUB "amdgpu/dcn_3_1_6_dmcub.bin"
+MODULE_FIRMWARE(FIRMWARE_DCN316_DMUB);
#define FIRMWARE_RAVEN_DMCU "amdgpu/raven_dmcu.bin"
MODULE_FIRMWARE(FIRMWARE_RAVEN_DMCU);
@@ -599,7 +602,6 @@ static void dm_crtc_high_irq(void *interrupt_params)
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
/**
* dm_dcn_vertical_interrupt0_high_irq() - Handles OTG Vertical interrupt0 for
@@ -767,7 +769,7 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params)
do {
dc_stat_get_dmub_notification(adev->dm.dc, &notify);
- if (notify.type > ARRAY_SIZE(dm->dmub_thread_offload)) {
+ if (notify.type >= ARRAY_SIZE(dm->dmub_thread_offload)) {
DRM_ERROR("DM: notify type %d invalid!", notify.type);
continue;
}
@@ -823,7 +825,6 @@ static void dm_dmub_outbox1_low_irq(void *interrupt_params)
if (count > DMUB_TRACE_MAX_READ)
DRM_DEBUG_DRIVER("Warning : count > DMUB_TRACE_MAX_READ");
}
-#endif /* CONFIG_DRM_AMD_DC_DCN */
static int dm_set_clockgating_state(void *handle,
enum amd_clockgating_state state)
@@ -1027,7 +1028,6 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
const unsigned char *fw_inst_const, *fw_bss_data;
uint32_t i, fw_inst_const_size, fw_bss_data_size;
bool has_hw_support;
- struct dc *dc = adev->dm.dc;
if (!dmub_srv)
/* DMUB isn't supported on the ASIC. */
@@ -1119,14 +1119,10 @@ static int dm_dmub_hw_init(struct amdgpu_device *adev)
for (i = 0; i < fb_info->num_fb; ++i)
hw_params.fb[i] = &fb_info->fb[i];
- switch (adev->asic_type) {
- case CHIP_YELLOW_CARP:
- if (dc->ctx->asic_id.hw_internal_rev != YELLOW_CARP_A0) {
- hw_params.dpia_supported = true;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- hw_params.disable_dpia = dc->debug.dpia_debug.bits.disable_dpia;
-#endif
- }
+ switch (adev->ip_versions[DCE_HWIP][0]) {
+ case IP_VERSION(3, 1, 3): /* Only for this asic hw internal rev B0 */
+ hw_params.dpia_supported = true;
+ hw_params.disable_dpia = adev->dm.dc->debug.dpia_debug.bits.disable_dpia;
break;
default:
break;
@@ -1188,7 +1184,6 @@ static void dm_dmub_hw_resume(struct amdgpu_device *adev)
}
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_addr_space_config *pa_config)
{
uint64_t pt_base;
@@ -1243,8 +1238,7 @@ static void mmhub_read_system_context(struct amdgpu_device *adev, struct dc_phy_
pa_config->is_hvm_enabled = 0;
}
-#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+
static void vblank_control_worker(struct work_struct *work)
{
struct vblank_control_work *vblank_work =
@@ -1281,8 +1275,6 @@ static void vblank_control_worker(struct work_struct *work)
kfree(vblank_work);
}
-#endif
-
static void dm_handle_hpd_rx_offload_work(struct work_struct *work)
{
struct hpd_rx_irq_offload_work *offload_work;
@@ -1409,9 +1401,7 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
mutex_init(&adev->dm.dc_lock);
mutex_init(&adev->dm.audio_lock);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
spin_lock_init(&adev->dm.vblank_lock);
-#endif
if(amdgpu_dm_irq_init(adev)) {
DRM_ERROR("amdgpu: failed to initialize DM IRQ support.\n");
@@ -1442,6 +1432,25 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
init_data.dce_environment = DCE_ENV_PRODUCTION_DRV;
+ switch (adev->ip_versions[DCE_HWIP][0]) {
+ case IP_VERSION(2, 1, 0):
+ switch (adev->dm.dmcub_fw_version) {
+ case 0: /* development */
+ case 0x1: /* linux-firmware.git hash 6d9f399 */
+ case 0x01000000: /* linux-firmware.git hash 9a0b0f4 */
+ init_data.flags.disable_dmcu = false;
+ break;
+ default:
+ init_data.flags.disable_dmcu = true;
+ }
+ break;
+ case IP_VERSION(2, 0, 3):
+ init_data.flags.disable_dmcu = true;
+ break;
+ default:
+ break;
+ }
+
switch (adev->asic_type) {
case CHIP_CARRIZO:
case CHIP_STONEY:
@@ -1449,34 +1458,30 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
break;
default:
switch (adev->ip_versions[DCE_HWIP][0]) {
- case IP_VERSION(2, 1, 0):
- init_data.flags.gpu_vm_support = true;
- switch (adev->dm.dmcub_fw_version) {
- case 0: /* development */
- case 0x1: /* linux-firmware.git hash 6d9f399 */
- case 0x01000000: /* linux-firmware.git hash 9a0b0f4 */
- init_data.flags.disable_dmcu = false;
- break;
- default:
- init_data.flags.disable_dmcu = true;
- }
- break;
case IP_VERSION(1, 0, 0):
case IP_VERSION(1, 0, 1):
+ /* enable S/G on PCO and RV2 */
+ if ((adev->apu_flags & AMD_APU_IS_RAVEN2) ||
+ (adev->apu_flags & AMD_APU_IS_PICASSO))
+ init_data.flags.gpu_vm_support = true;
+ break;
+ case IP_VERSION(2, 1, 0):
case IP_VERSION(3, 0, 1):
case IP_VERSION(3, 1, 2):
case IP_VERSION(3, 1, 3):
+ case IP_VERSION(3, 1, 5):
+ case IP_VERSION(3, 1, 6):
init_data.flags.gpu_vm_support = true;
break;
- case IP_VERSION(2, 0, 3):
- init_data.flags.disable_dmcu = true;
- break;
default:
break;
}
break;
}
+ if (init_data.flags.gpu_vm_support)
+ adev->mode_info.gpu_vm_support = true;
+
if (amdgpu_dc_feature_mask & DC_FBC_MASK)
init_data.flags.fbc_support = true;
@@ -1489,17 +1494,15 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
if (amdgpu_dc_feature_mask & DC_EDP_NO_POWER_SEQUENCING)
init_data.flags.edp_no_power_sequencing = true;
-#ifdef CONFIG_DRM_AMD_DC_DCN
if (amdgpu_dc_feature_mask & DC_DISABLE_LTTPR_DP1_4A)
init_data.flags.allow_lttpr_non_transparent_mode.bits.DP1_4A = true;
if (amdgpu_dc_feature_mask & DC_DISABLE_LTTPR_DP2_0)
init_data.flags.allow_lttpr_non_transparent_mode.bits.DP2_0 = true;
-#endif
- init_data.flags.power_down_display_on_boot = true;
+ init_data.flags.seamless_boot_edp_requested = false;
if (check_seamless_boot_capability(adev)) {
- init_data.flags.power_down_display_on_boot = false;
+ init_data.flags.seamless_boot_edp_requested = true;
init_data.flags.allow_seamless_boot_optimization = true;
DRM_INFO("Seamless boot condition check passed\n");
}
@@ -1550,7 +1553,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
goto error;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if ((adev->flags & AMD_IS_APU) && (adev->asic_type >= CHIP_CARRIZO)) {
struct dc_phy_addr_space_config pa_config;
@@ -1559,7 +1561,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
// Call the DC init_memory func
dc_setup_system_context(adev->dm.dc, &pa_config);
}
-#endif
adev->dm.freesync_module = mod_freesync_create(adev->dm.dc);
if (!adev->dm.freesync_module) {
@@ -1571,14 +1572,12 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
amdgpu_dm_init_color_mod();
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (adev->dm.dc->caps.max_links > 0) {
adev->dm.vblank_control_workqueue =
create_singlethread_workqueue("dm_vblank_control_workqueue");
if (!adev->dm.vblank_control_workqueue)
DRM_ERROR("amdgpu: failed to initialize vblank_workqueue.\n");
}
-#endif
#ifdef CONFIG_DRM_AMD_DC_HDCP
if (adev->dm.dc->caps.max_links > 0 && adev->family >= AMDGPU_FAMILY_RV) {
@@ -1610,7 +1609,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
}
amdgpu_dm_outbox_init(adev);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (!register_dmub_notify_callback(adev, DMUB_NOTIFICATION_AUX_REPLY,
dmub_aux_setconfig_callback, false)) {
DRM_ERROR("amdgpu: fail to register dmub aux callback");
@@ -1624,7 +1622,6 @@ static int amdgpu_dm_init(struct amdgpu_device *adev)
DRM_ERROR("amdgpu: fail to register dmub hpd callback");
goto error;
}
-#endif /* CONFIG_DRM_AMD_DC_DCN */
}
if (amdgpu_dm_initialize_drm_device(adev)) {
@@ -1671,12 +1668,10 @@ static void amdgpu_dm_fini(struct amdgpu_device *adev)
{
int i;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (adev->dm.vblank_control_workqueue) {
destroy_workqueue(adev->dm.vblank_control_workqueue);
adev->dm.vblank_control_workqueue = NULL;
}
-#endif
for (i = 0; i < adev->dm.display_indexes_num; i++) {
drm_encoder_cleanup(&adev->dm.mst_encoders[i].base);
@@ -1804,6 +1799,8 @@ static int load_dmcu_fw(struct amdgpu_device *adev)
case IP_VERSION(3, 0, 1):
case IP_VERSION(3, 1, 2):
case IP_VERSION(3, 1, 3):
+ case IP_VERSION(3, 1, 5):
+ case IP_VERSION(3, 1, 6):
return 0;
default:
break;
@@ -1919,7 +1916,14 @@ static int dm_dmub_sw_init(struct amdgpu_device *adev)
dmub_asic = (adev->external_rev_id == YELLOW_CARP_B0) ? DMUB_ASIC_DCN31B : DMUB_ASIC_DCN31;
fw_name_dmub = FIRMWARE_YELLOW_CARP_DMUB;
break;
-
+ case IP_VERSION(3, 1, 5):
+ dmub_asic = DMUB_ASIC_DCN315;
+ fw_name_dmub = FIRMWARE_DCN_315_DMUB;
+ break;
+ case IP_VERSION(3, 1, 6):
+ dmub_asic = DMUB_ASIC_DCN316;
+ fw_name_dmub = FIRMWARE_DCN316_DMUB;
+ break;
default:
/* ASIC doesn't support DMUB. */
return 0;
@@ -2179,12 +2183,8 @@ static void s3_handle_mst(struct drm_device *dev, bool suspend)
static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
{
- struct smu_context *smu = &adev->smu;
int ret = 0;
- if (!is_support_sw_smu(adev))
- return 0;
-
/* This interface is for dGPU Navi1x.Linux dc-pplib interface depends
* on window driver dc implementation.
* For Navi1x, clock settings of dcn watermarks are fixed. the settings
@@ -2223,7 +2223,7 @@ static int amdgpu_dm_smu_write_watermarks_table(struct amdgpu_device *adev)
return 0;
}
- ret = smu_write_watermarks_table(smu);
+ ret = amdgpu_dpm_write_watermarks_table(adev);
if (ret) {
DRM_ERROR("Failed to update WMTABLE!\n");
return ret;
@@ -2382,9 +2382,7 @@ static int dm_suspend(void *handle)
if (amdgpu_in_reset(adev)) {
mutex_lock(&dm->dc_lock);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
dc_allow_idle_optimizations(adev->dm.dc, false);
-#endif
dm->cached_dc_state = dc_copy_state(dm->dc->current_state);
@@ -2413,7 +2411,7 @@ static int dm_suspend(void *handle)
return 0;
}
-static struct amdgpu_dm_connector *
+struct amdgpu_dm_connector *
amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
struct drm_crtc *crtc)
{
@@ -2613,10 +2611,13 @@ static int dm_resume(void *handle)
* before the 0 streams commit.
*
* DC expects that link encoder assignments are *not* valid
- * when committing a state, so as a workaround it needs to be
- * cleared here.
+ * when committing a state, so as a workaround we can copy
+ * off of the current state.
+ *
+ * We lose the previous assignments, but we had already
+ * commit 0 streams anyway.
*/
- link_enc_cfg_init(dm->dc, dc_state);
+ link_enc_cfg_copy(adev->dm.dc->current_state, dc_state);
if (dc_enable_dmub_notifications(adev->dm.dc))
amdgpu_dm_outbox_init(adev);
@@ -2690,7 +2691,8 @@ static int dm_resume(void *handle)
* this is the case when traversing through already created
* MST connectors, should be skipped
*/
- if (aconnector->mst_port)
+ if (aconnector->dc_link &&
+ aconnector->dc_link->type == dc_connection_mst_branch)
continue;
mutex_lock(&aconnector->hpd_lock);
@@ -2810,7 +2812,7 @@ static struct drm_mode_config_helper_funcs amdgpu_dm_mode_config_helperfuncs = {
static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
{
- u32 max_cll, min_cll, max, min, q, r;
+ u32 max_avg, min_cll, max, min, q, r;
struct amdgpu_dm_backlight_caps *caps;
struct amdgpu_display_manager *dm;
struct drm_connector *conn_base;
@@ -2840,7 +2842,7 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
caps = &dm->backlight_caps[i];
caps->ext_caps = &aconnector->dc_link->dpcd_sink_ext_caps;
caps->aux_support = false;
- max_cll = conn_base->hdr_sink_metadata.hdmi_type1.max_cll;
+ max_avg = conn_base->hdr_sink_metadata.hdmi_type1.max_fall;
min_cll = conn_base->hdr_sink_metadata.hdmi_type1.min_cll;
if (caps->ext_caps->bits.oled == 1 /*||
@@ -2868,8 +2870,8 @@ static void update_connector_ext_caps(struct amdgpu_dm_connector *aconnector)
* The results of the above expressions can be verified at
* pre_computed_values.
*/
- q = max_cll >> 5;
- r = max_cll % 32;
+ q = max_avg >> 5;
+ r = max_avg % 32;
max = (1 << q) * pre_computed_values[r];
// min luminance: maxLum * (CV/255)^2 / 100
@@ -3533,7 +3535,6 @@ static int dce110_register_irq_handlers(struct amdgpu_device *adev)
return 0;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* Register IRQ sources and initialize IRQ callbacks */
static int dcn10_register_irq_handlers(struct amdgpu_device *adev)
{
@@ -3722,7 +3723,6 @@ static int register_outbox_irq_handlers(struct amdgpu_device *adev)
return 0;
}
-#endif
/*
* Acquires the lock for the atomic state object and returns
@@ -3730,8 +3730,8 @@ static int register_outbox_irq_handlers(struct amdgpu_device *adev)
*
* This should only be called during atomic check.
*/
-static int dm_atomic_get_state(struct drm_atomic_state *state,
- struct dm_atomic_state **dm_state)
+int dm_atomic_get_state(struct drm_atomic_state *state,
+ struct dm_atomic_state **dm_state)
{
struct drm_device *dev = state->dev;
struct amdgpu_device *adev = drm_to_adev(dev);
@@ -3948,7 +3948,7 @@ static u32 convert_brightness_to_user(const struct amdgpu_dm_backlight_caps *cap
max - min);
}
-static int amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
+static void amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
int bl_idx,
u32 user_brightness)
{
@@ -3979,7 +3979,8 @@ static int amdgpu_dm_backlight_set_level(struct amdgpu_display_manager *dm,
DRM_DEBUG("DM: Failed to update backlight on eDP[%d]\n", bl_idx);
}
- return rc ? 0 : 1;
+ if (rc)
+ dm->actual_brightness[bl_idx] = user_brightness;
}
static int amdgpu_dm_backlight_update_status(struct backlight_device *bd)
@@ -4225,12 +4226,13 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
goto fail;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* Use Outbox interrupt */
switch (adev->ip_versions[DCE_HWIP][0]) {
case IP_VERSION(3, 0, 0):
case IP_VERSION(3, 1, 2):
case IP_VERSION(3, 1, 3):
+ case IP_VERSION(3, 1, 5):
+ case IP_VERSION(3, 1, 6):
case IP_VERSION(2, 1, 0):
if (register_outbox_irq_handlers(dm->adev)) {
DRM_ERROR("DM: Failed to initialize IRQ\n");
@@ -4247,6 +4249,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
switch (adev->ip_versions[DCE_HWIP][0]) {
case IP_VERSION(3, 1, 2):
case IP_VERSION(3, 1, 3):
+ case IP_VERSION(3, 1, 5):
+ case IP_VERSION(3, 1, 6):
psr_feature_enabled = true;
break;
default:
@@ -4254,10 +4258,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
break;
}
}
-#endif
-
- /* Disable vblank IRQs aggressively for power-saving. */
- adev_to_drm(adev)->vblank_disable_immediate = true;
/* loops over all connectors on the board */
for (i = 0; i < link_cnt; i++) {
@@ -4350,7 +4350,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
}
break;
default:
-#if defined(CONFIG_DRM_AMD_DC_DCN)
switch (adev->ip_versions[DCE_HWIP][0]) {
case IP_VERSION(1, 0, 0):
case IP_VERSION(1, 0, 1):
@@ -4364,6 +4363,8 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
case IP_VERSION(3, 0, 1):
case IP_VERSION(3, 1, 2):
case IP_VERSION(3, 1, 3):
+ case IP_VERSION(3, 1, 5):
+ case IP_VERSION(3, 1, 6):
if (dcn10_register_irq_handlers(dm->adev)) {
DRM_ERROR("DM: Failed to initialize IRQ\n");
goto fail;
@@ -4374,7 +4375,6 @@ static int amdgpu_dm_initialize_drm_device(struct amdgpu_device *adev)
adev->ip_versions[DCE_HWIP][0]);
goto fail;
}
-#endif
break;
}
@@ -4523,7 +4523,7 @@ static int dm_early_init(void *handle)
adev->mode_info.num_dig = 6;
break;
default:
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+
switch (adev->ip_versions[DCE_HWIP][0]) {
case IP_VERSION(2, 0, 2):
case IP_VERSION(3, 0, 0):
@@ -4549,6 +4549,8 @@ static int dm_early_init(void *handle)
case IP_VERSION(2, 1, 0):
case IP_VERSION(3, 1, 2):
case IP_VERSION(3, 1, 3):
+ case IP_VERSION(3, 1, 5):
+ case IP_VERSION(3, 1, 6):
adev->mode_info.num_crtc = 4;
adev->mode_info.num_hpd = 4;
adev->mode_info.num_dig = 4;
@@ -4558,7 +4560,6 @@ static int dm_early_init(void *handle)
adev->ip_versions[DCE_HWIP][0]);
return -EINVAL;
}
-#endif
break;
}
@@ -5221,6 +5222,8 @@ get_plane_modifiers(const struct amdgpu_device *adev, unsigned int plane_type, u
case AMDGPU_FAMILY_NV:
case AMDGPU_FAMILY_VGH:
case AMDGPU_FAMILY_YC:
+ case AMDGPU_FAMILY_GC_10_3_6:
+ case AMDGPU_FAMILY_GC_10_3_7:
if (adev->ip_versions[GC_HWIP][0] >= IP_VERSION(10, 3, 0))
add_gfx10_3_modifiers(adev, mods, &size, &capacity);
else
@@ -5375,17 +5378,19 @@ fill_plane_buffer_attributes(struct amdgpu_device *adev,
static void
fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
- bool *per_pixel_alpha, bool *global_alpha,
- int *global_alpha_value)
+ bool *per_pixel_alpha, bool *pre_multiplied_alpha,
+ bool *global_alpha, int *global_alpha_value)
{
*per_pixel_alpha = false;
+ *pre_multiplied_alpha = true;
*global_alpha = false;
*global_alpha_value = 0xff;
if (plane_state->plane->type != DRM_PLANE_TYPE_OVERLAY)
return;
- if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI) {
+ if (plane_state->pixel_blend_mode == DRM_MODE_BLEND_PREMULTI ||
+ plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE) {
static const uint32_t alpha_formats[] = {
DRM_FORMAT_ARGB8888,
DRM_FORMAT_RGBA8888,
@@ -5400,6 +5405,9 @@ fill_blending_from_plane_state(const struct drm_plane_state *plane_state,
break;
}
}
+
+ if (per_pixel_alpha && plane_state->pixel_blend_mode == DRM_MODE_BLEND_COVERAGE)
+ *pre_multiplied_alpha = false;
}
if (plane_state->alpha < 0xffff) {
@@ -5562,7 +5570,7 @@ fill_dc_plane_info_and_addr(struct amdgpu_device *adev,
return ret;
fill_blending_from_plane_state(
- plane_state, &plane_info->per_pixel_alpha,
+ plane_state, &plane_info->per_pixel_alpha, &plane_info->pre_multiplied_alpha,
&plane_info->global_alpha, &plane_info->global_alpha_value);
return 0;
@@ -5609,6 +5617,7 @@ static int fill_dc_plane_attributes(struct amdgpu_device *adev,
dc_plane_state->tiling_info = plane_info.tiling_info;
dc_plane_state->visible = plane_info.visible;
dc_plane_state->per_pixel_alpha = plane_info.per_pixel_alpha;
+ dc_plane_state->pre_multiplied_alpha = plane_info.pre_multiplied_alpha;
dc_plane_state->global_alpha = plane_info.global_alpha;
dc_plane_state->global_alpha_value = plane_info.global_alpha_value;
dc_plane_state->dcc = plane_info.dcc;
@@ -5857,7 +5866,7 @@ static void fill_stream_properties_from_drm_display_mode(
else if (drm_mode_is_420_also(info, mode_in)
&& aconnector->force_yuv420_output)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR420;
- else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCRCB444)
+ else if ((connector->display_info.color_formats & DRM_COLOR_FORMAT_YCBCR444)
&& stream->signal == SIGNAL_TYPE_HDMI_TYPE_A)
timing_out->pixel_encoding = PIXEL_ENCODING_YCBCR444;
else
@@ -6187,7 +6196,7 @@ static void apply_dsc_policy_for_stream(struct amdgpu_dm_connector *aconnector,
if (stream->link && stream->link->local_sink)
max_dsc_target_bpp_limit_override =
stream->link->local_sink->edid_caps.panel_patch.max_dsc_target_bpp_limit;
-
+
/* Set DSC policy according to dsc_clock_en */
dc_dsc_policy_set_enable_dsc_when_not_needed(
aconnector->dsc_settings.dsc_force_enable == DSC_CLK_FORCE_ENABLE);
@@ -6326,7 +6335,7 @@ get_highest_refresh_rate_mode(struct amdgpu_dm_connector *aconnector,
}
}
- aconnector->freesync_vid_base = *m_pref;
+ drm_mode_copy(&aconnector->freesync_vid_base, m_pref);
return m_pref;
}
@@ -6436,12 +6445,11 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
*/
DRM_DEBUG_DRIVER("No preferred mode found\n");
} else {
- recalculate_timing = amdgpu_freesync_vid_mode &&
- is_freesync_video_mode(&mode, aconnector);
+ recalculate_timing = is_freesync_video_mode(&mode, aconnector);
if (recalculate_timing) {
freesync_mode = get_highest_refresh_rate_mode(aconnector, false);
- saved_mode = mode;
- mode = *freesync_mode;
+ drm_mode_copy(&saved_mode, &mode);
+ drm_mode_copy(&mode, freesync_mode);
} else {
decide_crtc_timing_for_drm_display_mode(
&mode, preferred_mode, scale);
@@ -6500,7 +6508,7 @@ create_stream_for_sink(struct amdgpu_dm_connector *aconnector,
if (stream->link->dpcd_caps.dprx_feature.bits.VSC_SDP_COLORIMETRY_SUPPORTED)
stream->use_vsc_sdp_for_colorimetry = true;
}
- mod_build_vsc_infopacket(stream, &stream->vsc_infopacket);
+ mod_build_vsc_infopacket(stream, &stream->vsc_infopacket, stream->output_color_space);
aconnector->psr_skip_count = AMDGPU_DM_PSR_ENTRY_DELAY;
}
@@ -6611,10 +6619,8 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
struct amdgpu_device *adev = drm_to_adev(crtc->dev);
struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct amdgpu_display_manager *dm = &adev->dm;
struct vblank_control_work *work;
-#endif
int rc = 0;
if (enable) {
@@ -6637,7 +6643,6 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
if (amdgpu_in_reset(adev))
return 0;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dm->vblank_control_workqueue) {
work = kzalloc(sizeof(*work), GFP_ATOMIC);
if (!work)
@@ -6655,7 +6660,6 @@ static inline int dm_set_vblank(struct drm_crtc *crtc, bool enable)
queue_work(dm->vblank_control_workqueue, &work->work);
}
-#endif
return 0;
}
@@ -7011,7 +7015,7 @@ static void handle_edid_mgmt(struct amdgpu_dm_connector *aconnector)
create_eml_sink(aconnector);
}
-static struct dc_stream_state *
+struct dc_stream_state *
create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
const struct drm_display_mode *drm_mode,
const struct dm_connector_state *dm_state,
@@ -7548,9 +7552,6 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
struct amdgpu_device *adev;
struct amdgpu_bo *rbo;
struct dm_plane_state *dm_plane_state_new, *dm_plane_state_old;
- struct list_head list;
- struct ttm_validate_buffer tv;
- struct ww_acquire_ctx ticket;
uint32_t domain;
int r;
@@ -7563,18 +7564,19 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
obj = new_state->fb->obj[0];
rbo = gem_to_amdgpu_bo(obj);
adev = amdgpu_ttm_adev(rbo->tbo.bdev);
- INIT_LIST_HEAD(&list);
-
- tv.bo = &rbo->tbo;
- tv.num_shared = 1;
- list_add(&tv.head, &list);
- r = ttm_eu_reserve_buffers(&ticket, &list, false, NULL);
+ r = amdgpu_bo_reserve(rbo, true);
if (r) {
dev_err(adev->dev, "fail to reserve bo (%d)\n", r);
return r;
}
+ r = dma_resv_reserve_fences(rbo->tbo.base.resv, 1);
+ if (r) {
+ dev_err(adev->dev, "reserving fence slot failed (%d)\n", r);
+ goto error_unlock;
+ }
+
if (plane->type != DRM_PLANE_TYPE_CURSOR)
domain = amdgpu_display_supported_domains(adev, rbo->flags);
else
@@ -7584,19 +7586,16 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
if (unlikely(r != 0)) {
if (r != -ERESTARTSYS)
DRM_ERROR("Failed to pin framebuffer with error %d\n", r);
- ttm_eu_backoff_reservation(&ticket, &list);
- return r;
+ goto error_unlock;
}
r = amdgpu_ttm_alloc_gart(&rbo->tbo);
if (unlikely(r != 0)) {
- amdgpu_bo_unpin(rbo);
- ttm_eu_backoff_reservation(&ticket, &list);
DRM_ERROR("%p bind failed\n", rbo);
- return r;
+ goto error_unpin;
}
- ttm_eu_backoff_reservation(&ticket, &list);
+ amdgpu_bo_unreserve(rbo);
afb->address = amdgpu_bo_gpu_offset(rbo);
@@ -7628,6 +7627,13 @@ static int dm_plane_helper_prepare_fb(struct drm_plane *plane,
}
return 0;
+
+error_unpin:
+ amdgpu_bo_unpin(rbo);
+
+error_unlock:
+ amdgpu_bo_unreserve(rbo);
+ return r;
}
static void dm_plane_helper_cleanup_fb(struct drm_plane *plane,
@@ -7895,6 +7901,9 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
if (res)
return res;
+ if (modifiers == NULL)
+ adev_to_drm(dm->adev)->mode_config.fb_modifiers_not_supported = true;
+
res = drm_universal_plane_init(adev_to_drm(dm->adev), plane, possible_crtcs,
&dm_plane_funcs, formats, num_formats,
modifiers, plane->type, NULL);
@@ -7905,7 +7914,8 @@ static int amdgpu_dm_plane_init(struct amdgpu_display_manager *dm,
if (plane->type == DRM_PLANE_TYPE_OVERLAY &&
plane_cap && plane_cap->per_pixel_alpha) {
unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) |
- BIT(DRM_MODE_BLEND_PREMULTI);
+ BIT(DRM_MODE_BLEND_PREMULTI) |
+ BIT(DRM_MODE_BLEND_COVERAGE);
drm_plane_create_alpha_property(plane);
drm_plane_create_blend_mode_property(plane, blend_caps);
@@ -8144,6 +8154,9 @@ static void amdgpu_dm_connector_add_common_modes(struct drm_encoder *encoder,
mode = amdgpu_dm_create_common_mode(encoder,
common_modes[i].name, common_modes[i].w,
common_modes[i].h);
+ if (!mode)
+ continue;
+
drm_mode_probed_add(connector, mode);
amdgpu_dm_connector->num_modes++;
}
@@ -8305,7 +8318,7 @@ static void amdgpu_dm_connector_add_freesync_modes(struct drm_connector *connect
struct amdgpu_dm_connector *amdgpu_dm_connector =
to_amdgpu_dm_connector(connector);
- if (!(amdgpu_freesync_vid_mode && edid))
+ if (!edid)
return;
if (amdgpu_dm_connector->max_vfreq - amdgpu_dm_connector->min_vfreq > 10)
@@ -8372,7 +8385,7 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm,
break;
case DRM_MODE_CONNECTOR_DisplayPort:
aconnector->base.polled = DRM_CONNECTOR_POLL_HPD;
- link->link_enc = dp_get_link_enc(link);
+ link->link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link->link_enc);
if (link->link_enc)
aconnector->base.ycbcr_420_allowed =
@@ -9197,7 +9210,8 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
* deadlock during GPU reset when this fence will not signal
* but we hold reservation lock for the BO.
*/
- r = dma_resv_wait_timeout(abo->tbo.base.resv, true, false,
+ r = dma_resv_wait_timeout(abo->tbo.base.resv,
+ DMA_RESV_USAGE_WRITE, false,
msecs_to_jiffies(5000));
if (unlikely(r <= 0))
DRM_ERROR("Waiting for fences timed out!");
@@ -9209,7 +9223,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
&bundle->flip_addrs[planes_count].address,
afb->tmz_surface, false);
- DRM_DEBUG_ATOMIC("plane: id=%d dcc_en=%d\n",
+ drm_dbg_state(state->dev, "plane: id=%d dcc_en=%d\n",
new_plane_state->plane->index,
bundle->plane_infos[planes_count].dcc.enable);
@@ -9243,7 +9257,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
dc_plane,
bundle->flip_addrs[planes_count].flip_timestamp_in_us);
- DRM_DEBUG_ATOMIC("%s Flipping to hi: 0x%x, low: 0x%x\n",
+ drm_dbg_state(state->dev, "%s Flipping to hi: 0x%x, low: 0x%x\n",
__func__,
bundle->flip_addrs[planes_count].address.grph.addr.high_part,
bundle->flip_addrs[planes_count].address.grph.addr.low_part);
@@ -9324,14 +9338,12 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
/* Update the planes if changed or disable if we don't have any. */
if ((planes_count || acrtc_state->active_planes == 0) &&
acrtc_state->stream) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/*
* If PSR or idle optimizations are enabled then flush out
* any pending work before hardware programming.
*/
if (dm->vblank_control_workqueue)
flush_workqueue(dm->vblank_control_workqueue);
-#endif
bundle->stream_update.stream = acrtc_state->stream;
if (new_pcrtc_state->mode_changed) {
@@ -9585,7 +9597,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
- DRM_DEBUG_ATOMIC(
+ drm_dbg_state(state->dev,
"amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
"planes_changed:%d, mode_changed:%d,active_changed:%d,"
"connectors_changed:%d\n",
@@ -9664,21 +9676,19 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
if (dc_state) {
/* if there mode set or reset, disable eDP PSR */
if (mode_set_reset_required) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dm->vblank_control_workqueue)
flush_workqueue(dm->vblank_control_workqueue);
-#endif
+
amdgpu_dm_psr_disable_all(dm);
}
dm_enable_per_frame_crtc_master_sync(dc_state);
mutex_lock(&dm->dc_lock);
WARN_ON(!dc_commit_state(dm->dc, dc_state));
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- /* Allow idle optimization when vblank count is 0 for display off */
- if (dm->active_vblank_irq_count == 0)
- dc_allow_idle_optimizations(dm->dc,true);
-#endif
+
+ /* Allow idle optimization when vblank count is 0 for display off */
+ if (dm->active_vblank_irq_count == 0)
+ dc_allow_idle_optimizations(dm->dc, true);
mutex_unlock(&dm->dc_lock);
}
@@ -9908,7 +9918,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
/* restore the backlight level */
for (i = 0; i < dm->num_of_edps; i++) {
if (dm->backlight_dev[i] &&
- (amdgpu_dm_backlight_get_level(dm, i) != dm->brightness[i]))
+ (dm->actual_brightness[i] != dm->brightness[i]))
amdgpu_dm_backlight_set_level(dm, i, dm->brightness[i]);
}
#endif
@@ -10142,27 +10152,27 @@ static bool
is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
struct drm_crtc_state *new_crtc_state)
{
- struct drm_display_mode old_mode, new_mode;
+ const struct drm_display_mode *old_mode, *new_mode;
if (!old_crtc_state || !new_crtc_state)
return false;
- old_mode = old_crtc_state->mode;
- new_mode = new_crtc_state->mode;
-
- if (old_mode.clock == new_mode.clock &&
- old_mode.hdisplay == new_mode.hdisplay &&
- old_mode.vdisplay == new_mode.vdisplay &&
- old_mode.htotal == new_mode.htotal &&
- old_mode.vtotal != new_mode.vtotal &&
- old_mode.hsync_start == new_mode.hsync_start &&
- old_mode.vsync_start != new_mode.vsync_start &&
- old_mode.hsync_end == new_mode.hsync_end &&
- old_mode.vsync_end != new_mode.vsync_end &&
- old_mode.hskew == new_mode.hskew &&
- old_mode.vscan == new_mode.vscan &&
- (old_mode.vsync_end - old_mode.vsync_start) ==
- (new_mode.vsync_end - new_mode.vsync_start))
+ old_mode = &old_crtc_state->mode;
+ new_mode = &new_crtc_state->mode;
+
+ if (old_mode->clock == new_mode->clock &&
+ old_mode->hdisplay == new_mode->hdisplay &&
+ old_mode->vdisplay == new_mode->vdisplay &&
+ old_mode->htotal == new_mode->htotal &&
+ old_mode->vtotal != new_mode->vtotal &&
+ old_mode->hsync_start == new_mode->hsync_start &&
+ old_mode->vsync_start != new_mode->vsync_start &&
+ old_mode->hsync_end == new_mode->hsync_end &&
+ old_mode->vsync_end != new_mode->vsync_end &&
+ old_mode->hskew == new_mode->hskew &&
+ old_mode->vscan == new_mode->vscan &&
+ (old_mode->vsync_end - old_mode->vsync_start) ==
+ (new_mode->vsync_end - new_mode->vsync_start))
return true;
return false;
@@ -10183,12 +10193,12 @@ static void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state) {
}
static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
- struct drm_atomic_state *state,
- struct drm_crtc *crtc,
- struct drm_crtc_state *old_crtc_state,
- struct drm_crtc_state *new_crtc_state,
- bool enable,
- bool *lock_and_validation_needed)
+ struct drm_atomic_state *state,
+ struct drm_crtc *crtc,
+ struct drm_crtc_state *old_crtc_state,
+ struct drm_crtc_state *new_crtc_state,
+ bool enable,
+ bool *lock_and_validation_needed)
{
struct dm_atomic_state *dm_state = NULL;
struct dm_crtc_state *dm_old_crtc_state, *dm_new_crtc_state;
@@ -10272,8 +10282,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
* TODO: Refactor this function to allow this check to work
* in all conditions.
*/
- if (amdgpu_freesync_vid_mode &&
- dm_new_crtc_state->stream &&
+ if (dm_new_crtc_state->stream &&
is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state))
goto skip_modeset;
@@ -10290,7 +10299,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
if (!drm_atomic_crtc_needs_modeset(new_crtc_state))
goto skip_modeset;
- DRM_DEBUG_ATOMIC(
+ drm_dbg_state(state->dev,
"amdgpu_crtc id:%d crtc_state_flags: enable:%d, active:%d, "
"planes_changed:%d, mode_changed:%d,active_changed:%d,"
"connectors_changed:%d\n",
@@ -10308,7 +10317,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
if (!dm_old_crtc_state->stream)
goto skip_modeset;
- if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream &&
+ if (dm_new_crtc_state->stream &&
is_timing_unchanged_for_freesync(new_crtc_state,
old_crtc_state)) {
new_crtc_state->mode_changed = false;
@@ -10320,7 +10329,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
set_freesync_fixed_config(dm_new_crtc_state);
goto skip_modeset;
- } else if (amdgpu_freesync_vid_mode && aconnector &&
+ } else if (aconnector &&
is_freesync_video_mode(&new_crtc_state->mode,
aconnector)) {
struct drm_display_mode *high_mode;
@@ -10858,10 +10867,13 @@ static int dm_check_crtc_cursor(struct drm_atomic_state *state,
static int add_affected_mst_dsc_crtcs(struct drm_atomic_state *state, struct drm_crtc *crtc)
{
struct drm_connector *connector;
- struct drm_connector_state *conn_state;
+ struct drm_connector_state *conn_state, *old_conn_state;
struct amdgpu_dm_connector *aconnector = NULL;
int i;
- for_each_new_connector_in_state(state, connector, conn_state, i) {
+ for_each_oldnew_connector_in_state(state, connector, old_conn_state, conn_state, i) {
+ if (!conn_state->crtc)
+ conn_state = old_conn_state;
+
if (conn_state->crtc != crtc)
continue;
@@ -10968,6 +10980,7 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
}
}
}
+ pre_validate_dsc(state, &dm_state, vars);
}
#endif
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
index b9a69b0cef23..aa34c0068f41 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h
@@ -26,10 +26,10 @@
#ifndef __AMDGPU_DM_H__
#define __AMDGPU_DM_H__
+#include <drm/display/drm_dp_mst_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_connector.h>
#include <drm/drm_crtc.h>
-#include <drm/drm_dp_mst_helper.h>
#include <drm/drm_plane.h>
/*
@@ -358,14 +358,12 @@ struct amdgpu_display_manager {
*/
struct mutex audio_lock;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/**
* @vblank_lock:
*
* Guards access to deferred vblank work state.
*/
spinlock_t vblank_lock;
-#endif
/**
* @audio_component:
@@ -469,14 +467,12 @@ struct amdgpu_display_manager {
struct hdcp_workqueue *hdcp_workqueue;
#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/**
* @vblank_control_workqueue:
*
* Deferred work for vblank control events.
*/
struct workqueue_struct *vblank_control_workqueue;
-#endif
struct drm_atomic_state *cached_state;
struct dc_state *cached_dc_state;
@@ -493,14 +489,12 @@ struct amdgpu_display_manager {
*/
const struct gpu_info_soc_bounding_box_v1_0 *soc_bounding_box;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/**
* @active_vblank_irq_count:
*
* number of currently active vblank irqs
*/
uint32_t active_vblank_irq_count;
-#endif
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
/**
@@ -540,6 +534,12 @@ struct amdgpu_display_manager {
* cached backlight values.
*/
u32 brightness[AMDGPU_DM_MAX_NUM_EDP];
+ /**
+ * @actual_brightness:
+ *
+ * last successfully applied backlight values.
+ */
+ u32 actual_brightness[AMDGPU_DM_MAX_NUM_EDP];
};
enum dsc_clock_force_state {
@@ -604,6 +604,7 @@ struct amdgpu_dm_connector {
#endif
bool force_yuv420_output;
struct dsc_preferred_settings dsc_settings;
+ union dp_downstream_port_present mst_downstream_port_present;
/* Cached display modes */
struct drm_display_mode freesync_vid_base;
@@ -736,4 +737,16 @@ int amdgpu_dm_process_dmub_aux_transfer_sync(bool is_cmd_aux,
bool check_seamless_boot_capability(struct amdgpu_device *adev);
+struct dc_stream_state *
+ create_validate_stream_for_sink(struct amdgpu_dm_connector *aconnector,
+ const struct drm_display_mode *drm_mode,
+ const struct dm_connector_state *dm_state,
+ const struct dc_stream_state *old_stream);
+
+int dm_atomic_get_state(struct drm_atomic_state *state,
+ struct dm_atomic_state **dm_state);
+
+struct amdgpu_dm_connector *
+amdgpu_dm_find_first_crtc_matching_connector(struct drm_atomic_state *state,
+ struct drm_crtc *crtc);
#endif /* __AMDGPU_DM_H__ */
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
index 26719efa5396..c7a592d68feb 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_debugfs.c
@@ -23,6 +23,7 @@
*
*/
+#include <linux/string_helpers.h>
#include <linux/uaccess.h>
#include "dc.h"
@@ -49,11 +50,6 @@ struct dmub_debugfs_trace_entry {
uint32_t param1;
};
-static inline const char *yesno(bool v)
-{
- return v ? "yes" : "no";
-}
-
/* parse_write_buffer_into_params - Helper function to parse debugfs write buffer into an array
*
* Function takes in attributes passed to debugfs write entry
@@ -227,8 +223,10 @@ static ssize_t dp_link_settings_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -245,6 +243,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
{
struct amdgpu_dm_connector *connector = file_inode(f)->i_private;
struct dc_link *link = connector->dc_link;
+ struct amdgpu_device *adev = drm_to_adev(connector->base.dev);
struct dc *dc = (struct dc *)link->dc;
struct dc_link_settings prefer_link_settings;
char *wr_buf = NULL;
@@ -292,9 +291,7 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
case LINK_RATE_RBR2:
case LINK_RATE_HIGH2:
case LINK_RATE_HIGH3:
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case LINK_RATE_UHBR10:
-#endif
break;
default:
valid_input = false;
@@ -304,6 +301,9 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
if (!valid_input) {
kfree(wr_buf);
DRM_DEBUG_DRIVER("Invalid Input value No HW will be programmed\n");
+ mutex_lock(&adev->dm.dc_lock);
+ dc_link_set_preferred_training_settings(dc, NULL, NULL, link, false);
+ mutex_unlock(&adev->dm.dc_lock);
return size;
}
@@ -315,7 +315,9 @@ static ssize_t dp_link_settings_write(struct file *f, const char __user *buf,
prefer_link_settings.lane_count = param[0];
prefer_link_settings.link_rate = param[1];
- dc_link_set_preferred_training_settings(dc, &prefer_link_settings, NULL, link, true);
+ mutex_lock(&adev->dm.dc_lock);
+ dc_link_set_preferred_training_settings(dc, &prefer_link_settings, NULL, link, false);
+ mutex_unlock(&adev->dm.dc_lock);
kfree(wr_buf);
return size;
@@ -389,8 +391,10 @@ static ssize_t dp_phy_settings_read(struct file *f, char __user *buf,
break;
r = put_user((*(rd_buf + result)), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -853,12 +857,12 @@ static int psr_capability_show(struct seq_file *m, void *data)
if (!(link->connector_signal & SIGNAL_TYPE_EDP))
return -ENODEV;
- seq_printf(m, "Sink support: %s", yesno(link->dpcd_caps.psr_caps.psr_version != 0));
- if (link->dpcd_caps.psr_caps.psr_version)
- seq_printf(m, " [0x%02x]", link->dpcd_caps.psr_caps.psr_version);
+ seq_printf(m, "Sink support: %s", str_yes_no(link->dpcd_caps.psr_info.psr_version != 0));
+ if (link->dpcd_caps.psr_info.psr_version)
+ seq_printf(m, " [0x%02x]", link->dpcd_caps.psr_info.psr_version);
seq_puts(m, "\n");
- seq_printf(m, "Driver support: %s", yesno(link->psr_settings.psr_feature_enabled));
+ seq_printf(m, "Driver support: %s", str_yes_no(link->psr_settings.psr_feature_enabled));
if (link->psr_settings.psr_version)
seq_printf(m, " [0x%02x]", link->psr_settings.psr_version);
seq_puts(m, "\n");
@@ -1207,8 +1211,8 @@ static int dp_dsc_fec_support_show(struct seq_file *m, void *data)
drm_modeset_drop_locks(&ctx);
drm_modeset_acquire_fini(&ctx);
- seq_printf(m, "FEC_Sink_Support: %s\n", yesno(is_fec_supported));
- seq_printf(m, "DSC_Sink_Support: %s\n", yesno(is_dsc_supported));
+ seq_printf(m, "FEC_Sink_Support: %s\n", str_yes_no(is_fec_supported));
+ seq_printf(m, "DSC_Sink_Support: %s\n", str_yes_no(is_dsc_supported));
return ret;
}
@@ -1359,8 +1363,10 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf,
break;
}
- if (!pipe_ctx)
+ if (!pipe_ctx) {
+ kfree(rd_buf);
return -ENXIO;
+ }
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
@@ -1376,8 +1382,10 @@ static ssize_t dp_dsc_clock_en_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -1546,8 +1554,10 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf,
break;
}
- if (!pipe_ctx)
+ if (!pipe_ctx) {
+ kfree(rd_buf);
return -ENXIO;
+ }
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
@@ -1563,8 +1573,10 @@ static ssize_t dp_dsc_slice_width_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -1731,8 +1743,10 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf,
break;
}
- if (!pipe_ctx)
+ if (!pipe_ctx) {
+ kfree(rd_buf);
return -ENXIO;
+ }
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
@@ -1748,8 +1762,10 @@ static ssize_t dp_dsc_slice_height_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -1912,8 +1928,10 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf,
break;
}
- if (!pipe_ctx)
+ if (!pipe_ctx) {
+ kfree(rd_buf);
return -ENXIO;
+ }
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
@@ -1929,8 +1947,10 @@ static ssize_t dp_dsc_bits_per_pixel_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -2088,8 +2108,10 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf,
break;
}
- if (!pipe_ctx)
+ if (!pipe_ctx) {
+ kfree(rd_buf);
return -ENXIO;
+ }
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
@@ -2105,8 +2127,10 @@ static ssize_t dp_dsc_pic_width_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -2145,8 +2169,10 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf,
break;
}
- if (!pipe_ctx)
+ if (!pipe_ctx) {
+ kfree(rd_buf);
return -ENXIO;
+ }
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
@@ -2162,8 +2188,10 @@ static ssize_t dp_dsc_pic_height_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -2217,8 +2245,10 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf,
break;
}
- if (!pipe_ctx)
+ if (!pipe_ctx) {
+ kfree(rd_buf);
return -ENXIO;
+ }
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
@@ -2234,8 +2264,10 @@ static ssize_t dp_dsc_chunk_size_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -2289,8 +2321,10 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf,
break;
}
- if (!pipe_ctx)
+ if (!pipe_ctx) {
+ kfree(rd_buf);
return -ENXIO;
+ }
dsc = pipe_ctx->stream_res.dsc;
if (dsc)
@@ -2306,8 +2340,10 @@ static ssize_t dp_dsc_slice_bpg_offset_read(struct file *f, char __user *buf,
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
@@ -2851,7 +2887,9 @@ static ssize_t edp_ilr_write(struct file *f, const char __user *buf,
kfree(wr_buf);
DRM_DEBUG_DRIVER("Invalid Input value. No HW will be programmed\n");
prefer_link_settings.use_link_rate_set = false;
- dc_link_set_preferred_training_settings(dc, NULL, NULL, link, true);
+ mutex_lock(&adev->dm.dc_lock);
+ dc_link_set_preferred_training_settings(dc, NULL, NULL, link, false);
+ mutex_unlock(&adev->dm.dc_lock);
return size;
}
@@ -3371,7 +3409,6 @@ static int disable_hpd_get(void *data, u64 *val)
DEFINE_DEBUGFS_ATTRIBUTE(disable_hpd_ops, disable_hpd_get,
disable_hpd_set, "%llu\n");
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/*
* Temporary w/a to force sst sequence in M42D DP2 mst receiver
* Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dp_set_mst_en_for_sst
@@ -3395,7 +3432,30 @@ static int dp_force_sst_get(void *data, u64 *val)
}
DEFINE_DEBUGFS_ATTRIBUTE(dp_set_mst_en_for_sst_ops, dp_force_sst_get,
dp_force_sst_set, "%llu\n");
-#endif
+
+/*
+ * Force DP2 sequence without VESA certified cable.
+ * Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_dm_dp_ignore_cable_id
+ */
+static int dp_ignore_cable_id_set(void *data, u64 val)
+{
+ struct amdgpu_device *adev = data;
+
+ adev->dm.dc->debug.ignore_cable_id = val;
+
+ return 0;
+}
+
+static int dp_ignore_cable_id_get(void *data, u64 *val)
+{
+ struct amdgpu_device *adev = data;
+
+ *val = adev->dm.dc->debug.ignore_cable_id;
+
+ return 0;
+}
+DEFINE_DEBUGFS_ATTRIBUTE(dp_ignore_cable_id_ops, dp_ignore_cable_id_get,
+ dp_ignore_cable_id_set, "%llu\n");
/*
* Sets the DC visual confirm debug option from the given string.
@@ -3427,6 +3487,40 @@ DEFINE_SHOW_ATTRIBUTE(mst_topo);
DEFINE_DEBUGFS_ATTRIBUTE(visual_confirm_fops, visual_confirm_get,
visual_confirm_set, "%llu\n");
+
+/*
+ * Sets the DC skip_detection_link_training debug option from the given string.
+ * Example usage: echo 1 > /sys/kernel/debug/dri/0/amdgpu_skip_detection_link_training
+ */
+static int skip_detection_link_training_set(void *data, u64 val)
+{
+ struct amdgpu_device *adev = data;
+
+ if (val == 0)
+ adev->dm.dc->debug.skip_detection_link_training = false;
+ else
+ adev->dm.dc->debug.skip_detection_link_training = true;
+
+ return 0;
+}
+
+/*
+ * Reads the DC skip_detection_link_training debug option value into the given buffer.
+ * Example usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_skip_detection_link_training
+ */
+static int skip_detection_link_training_get(void *data, u64 *val)
+{
+ struct amdgpu_device *adev = data;
+
+ *val = adev->dm.dc->debug.skip_detection_link_training;
+
+ return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(skip_detection_link_training_fops,
+ skip_detection_link_training_get,
+ skip_detection_link_training_set, "%llu\n");
+
/*
* Dumps the DCC_EN bit for each pipe.
* Example usage: cat /sys/kernel/debug/dri/0/amdgpu_dm_dcc_en
@@ -3459,8 +3553,10 @@ static ssize_t dcc_en_bits_read(
dc->hwss.get_dcc_en_bits(dc, dcc_en_bits);
rd_buf = kcalloc(rd_buf_size, sizeof(char), GFP_KERNEL);
- if (!rd_buf)
+ if (!rd_buf) {
+ kfree(dcc_en_bits);
return -ENOMEM;
+ }
for (i = 0; i < num_pipes; i++)
offset += snprintf(rd_buf + offset, rd_buf_size - offset,
@@ -3473,8 +3569,10 @@ static ssize_t dcc_en_bits_read(
if (*pos >= rd_buf_size)
break;
r = put_user(*(rd_buf + result), buf);
- if (r)
+ if (r) {
+ kfree(rd_buf);
return r; /* r = -EFAULT */
+ }
buf += 1;
size -= 1;
*pos += 1;
@@ -3506,14 +3604,17 @@ void dtn_debugfs_init(struct amdgpu_device *adev)
adev, &mst_topo_fops);
debugfs_create_file("amdgpu_dm_dtn_log", 0644, root, adev,
&dtn_log_fops);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
debugfs_create_file("amdgpu_dm_dp_set_mst_en_for_sst", 0644, root, adev,
&dp_set_mst_en_for_sst_ops);
-#endif
+ debugfs_create_file("amdgpu_dm_dp_ignore_cable_id", 0644, root, adev,
+ &dp_ignore_cable_id_ops);
debugfs_create_file_unsafe("amdgpu_dm_visual_confirm", 0644, root, adev,
&visual_confirm_fops);
+ debugfs_create_file_unsafe("amdgpu_dm_skip_detection_link_training", 0644, root, adev,
+ &skip_detection_link_training_fops);
+
debugfs_create_file_unsafe("amdgpu_dm_dmub_tracebuffer", 0644, root,
adev, &dmub_tracebuffer_fops);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 5bfdc66b5867..15c0e3f2a9c3 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -27,7 +27,7 @@
#include "amdgpu.h"
#include "amdgpu_dm.h"
#include "dm_helpers.h"
-#include <drm/drm_hdcp.h>
+#include <drm/display/drm_hdcp_helper.h>
#include "hdcp_psp.h"
/*
@@ -663,7 +663,9 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
INIT_DELAYED_WORK(&hdcp_work[i].property_validate_dwork, event_property_validate);
hdcp_work[i].hdcp.config.psp.handle = &adev->psp;
- if (dc->ctx->dce_version == DCN_VERSION_3_1)
+ if (dc->ctx->dce_version == DCN_VERSION_3_1 ||
+ dc->ctx->dce_version == DCN_VERSION_3_15 ||
+ dc->ctx->dce_version == DCN_VERSION_3_16)
hdcp_work[i].hdcp.config.psp.caps.dtm_v3_supported = 1;
hdcp_work[i].hdcp.config.ddc.handle = dc_get_link_at_index(dc, i);
hdcp_work[i].hdcp.config.ddc.funcs.write_i2c = lp_write_i2c;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
index 29f07c26d080..7c799ddc1d27 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_helpers.c
@@ -39,6 +39,7 @@
#include "amdgpu_dm_mst_types.h"
#include "dm_helpers.h"
+#include "ddc_service_types.h"
struct monitor_patch_info {
unsigned int manufacturer_id;
@@ -89,7 +90,7 @@ enum dc_edid_status dm_helpers_parse_edid_caps(
{
struct amdgpu_dm_connector *aconnector = link->priv;
struct drm_connector *connector = &aconnector->base;
- struct edid *edid_buf = (struct edid *) edid->raw_edid;
+ struct edid *edid_buf = edid ? (struct edid *) edid->raw_edid : NULL;
struct cea_sad *sads;
int sad_count = -1;
int sadb_count = -1;
@@ -445,7 +446,7 @@ bool dm_helpers_dp_mst_start_top_mgr(
return (drm_dp_mst_topology_mgr_set_mst(&aconnector->mst_mgr, true) == 0);
}
-void dm_helpers_dp_mst_stop_top_mgr(
+bool dm_helpers_dp_mst_stop_top_mgr(
struct dc_context *ctx,
struct dc_link *link)
{
@@ -454,7 +455,7 @@ void dm_helpers_dp_mst_stop_top_mgr(
if (!aconnector) {
DRM_ERROR("Failed to find connector for link!");
- return;
+ return false;
}
DRM_INFO("DM_MST: stopping TM on aconnector: %p [id: %d]\n",
@@ -479,6 +480,8 @@ void dm_helpers_dp_mst_stop_top_mgr(
}
}
}
+
+ return false;
}
bool dm_helpers_dp_read_dpcd(
@@ -552,6 +555,177 @@ bool dm_helpers_submit_i2c(
return result;
}
+
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+static bool execute_synaptics_rc_command(struct drm_dp_aux *aux,
+ bool is_write_cmd,
+ unsigned char cmd,
+ unsigned int length,
+ unsigned int offset,
+ unsigned char *data)
+{
+ bool success = false;
+ unsigned char rc_data[16] = {0};
+ unsigned char rc_offset[4] = {0};
+ unsigned char rc_length[2] = {0};
+ unsigned char rc_cmd = 0;
+ unsigned char rc_result = 0xFF;
+ unsigned char i = 0;
+ uint8_t ret = 0;
+
+ if (is_write_cmd) {
+ // write rc data
+ memmove(rc_data, data, length);
+ ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_DATA, rc_data, sizeof(rc_data));
+ }
+
+ // write rc offset
+ rc_offset[0] = (unsigned char) offset & 0xFF;
+ rc_offset[1] = (unsigned char) (offset >> 8) & 0xFF;
+ rc_offset[2] = (unsigned char) (offset >> 16) & 0xFF;
+ rc_offset[3] = (unsigned char) (offset >> 24) & 0xFF;
+ ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_OFFSET, rc_offset, sizeof(rc_offset));
+
+ // write rc length
+ rc_length[0] = (unsigned char) length & 0xFF;
+ rc_length[1] = (unsigned char) (length >> 8) & 0xFF;
+ ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_LENGTH, rc_length, sizeof(rc_length));
+
+ // write rc cmd
+ rc_cmd = cmd | 0x80;
+ ret = drm_dp_dpcd_write(aux, SYNAPTICS_RC_COMMAND, &rc_cmd, sizeof(rc_cmd));
+
+ if (ret < 0) {
+ DRM_ERROR(" execute_synaptics_rc_command - write cmd ..., err = %d\n", ret);
+ return false;
+ }
+
+ // poll until active is 0
+ for (i = 0; i < 10; i++) {
+ drm_dp_dpcd_read(aux, SYNAPTICS_RC_COMMAND, &rc_cmd, sizeof(rc_cmd));
+ if (rc_cmd == cmd)
+ // active is 0
+ break;
+ msleep(10);
+ }
+
+ // read rc result
+ drm_dp_dpcd_read(aux, SYNAPTICS_RC_RESULT, &rc_result, sizeof(rc_result));
+ success = (rc_result == 0);
+
+ if (success && !is_write_cmd) {
+ // read rc data
+ drm_dp_dpcd_read(aux, SYNAPTICS_RC_DATA, data, length);
+ }
+
+ DC_LOG_DC(" execute_synaptics_rc_command - success = %d\n", success);
+
+ return success;
+}
+
+static void apply_synaptics_fifo_reset_wa(struct drm_dp_aux *aux)
+{
+ unsigned char data[16] = {0};
+
+ DC_LOG_DC("Start apply_synaptics_fifo_reset_wa\n");
+
+ // Step 2
+ data[0] = 'P';
+ data[1] = 'R';
+ data[2] = 'I';
+ data[3] = 'U';
+ data[4] = 'S';
+
+ if (!execute_synaptics_rc_command(aux, true, 0x01, 5, 0, data))
+ return;
+
+ // Step 3 and 4
+ if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x220998, data))
+ return;
+
+ data[0] &= (~(1 << 1)); // set bit 1 to 0
+ if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x220998, data))
+ return;
+
+ if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x220D98, data))
+ return;
+
+ data[0] &= (~(1 << 1)); // set bit 1 to 0
+ if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x220D98, data))
+ return;
+
+ if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x221198, data))
+ return;
+
+ data[0] &= (~(1 << 1)); // set bit 1 to 0
+ if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x221198, data))
+ return;
+
+ // Step 3 and 5
+ if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x220998, data))
+ return;
+
+ data[0] |= (1 << 1); // set bit 1 to 1
+ if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x220998, data))
+ return;
+
+ if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x220D98, data))
+ return;
+
+ data[0] |= (1 << 1); // set bit 1 to 1
+ return;
+
+ if (!execute_synaptics_rc_command(aux, false, 0x31, 4, 0x221198, data))
+ return;
+
+ data[0] |= (1 << 1); // set bit 1 to 1
+ if (!execute_synaptics_rc_command(aux, true, 0x21, 4, 0x221198, data))
+ return;
+
+ // Step 6
+ if (!execute_synaptics_rc_command(aux, true, 0x02, 0, 0, NULL))
+ return;
+
+ DC_LOG_DC("Done apply_synaptics_fifo_reset_wa\n");
+}
+
+static uint8_t write_dsc_enable_synaptics_non_virtual_dpcd_mst(
+ struct drm_dp_aux *aux,
+ const struct dc_stream_state *stream,
+ bool enable)
+{
+ uint8_t ret = 0;
+
+ DC_LOG_DC("Configure DSC to non-virtual dpcd synaptics\n");
+
+ if (enable) {
+ /* When DSC is enabled on previous boot and reboot with the hub,
+ * there is a chance that Synaptics hub gets stuck during reboot sequence.
+ * Applying a workaround to reset Synaptics SDP fifo before enabling the first stream
+ */
+ if (!stream->link->link_status.link_active &&
+ memcmp(stream->link->dpcd_caps.branch_dev_name,
+ (int8_t *)SYNAPTICS_DEVICE_ID, 4) == 0)
+ apply_synaptics_fifo_reset_wa(aux);
+
+ ret = drm_dp_dpcd_write(aux, DP_DSC_ENABLE, &enable, 1);
+ DRM_INFO("Send DSC enable to synaptics\n");
+
+ } else {
+ /* Synaptics hub not support virtual dpcd,
+ * external monitor occur garbage while disable DSC,
+ * Disable DSC only when entire link status turn to false,
+ */
+ if (!stream->link->link_status.link_active) {
+ ret = drm_dp_dpcd_write(aux, DP_DSC_ENABLE, &enable, 1);
+ DRM_INFO("Send DSC disable to synaptics\n");
+ }
+ }
+
+ return ret;
+}
+#endif
+
bool dm_helpers_dp_write_dsc_enable(
struct dc_context *ctx,
const struct dc_stream_state *stream,
@@ -570,7 +744,16 @@ bool dm_helpers_dp_write_dsc_enable(
if (!aconnector->dsc_aux)
return false;
+#if defined(CONFIG_DRM_AMD_DC_DCN)
+ // apply w/a to synaptics
+ if (needs_dsc_aux_workaround(aconnector->dc_link) &&
+ (aconnector->mst_downstream_port_present.byte & 0x7) != 0x3)
+ return write_dsc_enable_synaptics_non_virtual_dpcd_mst(
+ aconnector->dsc_aux, stream, enable_dsc);
+#endif
+
ret = drm_dp_dpcd_write(aconnector->dsc_aux, DP_DSC_ENABLE, &enable_dsc, 1);
+ DC_LOG_DC("Send DSC %s to MST RX\n", enable_dsc ? "enable" : "disable");
}
if (stream->signal == SIGNAL_TYPE_DISPLAY_PORT || stream->signal == SIGNAL_TYPE_EDP) {
@@ -648,14 +831,6 @@ enum dc_edid_status dm_helpers_read_local_edid(
/* We don't need the original edid anymore */
kfree(edid);
- /* connector->display_info is parsed from EDID and saved
- * into drm_connector->display_info
- *
- * drm_connector->display_info will be used by amdgpu_dm funcs,
- * like fill_stream_properties_from_drm_display_mode
- */
- amdgpu_dm_update_connector_after_detect(aconnector);
-
edid_status = dm_helpers_parse_edid_caps(
link,
&sink->dc_edid,
@@ -797,16 +972,12 @@ void dm_helpers_mst_enable_stream_features(const struct dc_stream_state *stream)
sizeof(new_downspread));
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz)
{
- // FPGA programming for this clock in diags framework that
- // needs to go through dm layer, therefore leave dummy interace here
+ // TODO
}
-
void dm_helpers_enable_periodic_detection(struct dc_context *ctx, bool enable)
{
- /* TODO: add peridic detection implementation */
+ /* TODO: add periodic detection implementation */
}
-#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
index 4aba0e8c84f8..19f543ba7205 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c
@@ -928,7 +928,11 @@ void amdgpu_dm_hpd_fini(struct amdgpu_device *adev)
to_amdgpu_dm_connector(connector);
const struct dc_link *dc_link = amdgpu_dm_connector->dc_link;
- dc_interrupt_set(adev->dm.dc, dc_link->irq_source_hpd, false);
+ if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd) {
+ dc_interrupt_set(adev->dm.dc,
+ dc_link->irq_source_hpd,
+ false);
+ }
if (DC_IRQ_SOURCE_INVALID != dc_link->irq_source_hpd_rx) {
dc_interrupt_set(adev->dm.dc,
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index cc34a35d0bcb..9221b6690a4a 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -23,10 +23,10 @@
*
*/
+#include <drm/display/drm_dp_helper.h>
+#include <drm/display/drm_dp_mst_helper.h>
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
-#include <drm/drm_dp_mst_helper.h>
-#include <drm/drm_dp_helper.h>
#include "dm_services.h"
#include "amdgpu.h"
#include "amdgpu_dm.h"
@@ -45,9 +45,10 @@
#include "amdgpu_dm_debugfs.h"
#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "dc/dcn20/dcn20_resource.h"
-#endif
+bool is_timing_changed(struct dc_stream_state *cur_stream,
+ struct dc_stream_state *new_stream);
+
static ssize_t dm_dp_aux_transfer(struct drm_dp_aux *aux,
struct drm_dp_aux_msg *msg)
@@ -159,7 +160,7 @@ static const struct drm_connector_funcs dm_dp_mst_connector_funcs = {
};
#if defined(CONFIG_DRM_AMD_DC_DCN)
-static bool needs_dsc_aux_workaround(struct dc_link *link)
+bool needs_dsc_aux_workaround(struct dc_link *link)
{
if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
(link->dpcd_caps.dpcd_rev.raw == DPCD_REV_14 || link->dpcd_caps.dpcd_rev.raw == DPCD_REV_12) &&
@@ -209,6 +210,25 @@ static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector *aconnecto
return true;
}
+
+static bool retrieve_downstream_port_device(struct amdgpu_dm_connector *aconnector)
+{
+ union dp_downstream_port_present ds_port_present;
+
+ if (!aconnector->dsc_aux)
+ return false;
+
+ if (drm_dp_dpcd_read(aconnector->dsc_aux, DP_DOWNSTREAMPORT_PRESENT, &ds_port_present, 1) < 0) {
+ DRM_INFO("Failed to read downstream_port_present 0x05 from DFP of branch device\n");
+ return false;
+ }
+
+ aconnector->mst_downstream_port_present = ds_port_present;
+ DRM_INFO("Downstream port present %d, type %d\n",
+ ds_port_present.fields.PORT_PRESENT, ds_port_present.fields.PORT_TYPE);
+
+ return true;
+}
#endif
static int dm_dp_mst_get_modes(struct drm_connector *connector)
@@ -289,6 +309,10 @@ static int dm_dp_mst_get_modes(struct drm_connector *connector)
if (!validate_dsc_caps_on_connector(aconnector))
memset(&aconnector->dc_sink->dsc_caps,
0, sizeof(aconnector->dc_sink->dsc_caps));
+
+ if (!retrieve_downstream_port_device(aconnector))
+ memset(&aconnector->mst_downstream_port_present,
+ 0, sizeof(aconnector->mst_downstream_port_present));
#endif
}
}
@@ -576,6 +600,21 @@ static void set_dsc_configs_from_fairness_vars(struct dsc_mst_fairness_params *p
} else {
params[i].timing->flags.DSC = 0;
}
+ params[i].timing->dsc_cfg.mst_pbn = vars[i + k].pbn;
+ }
+
+ for (i = 0; i < count; i++) {
+ if (params[i].sink) {
+ if (params[i].sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+ params[i].sink->sink_signal != SIGNAL_TYPE_NONE)
+ DRM_DEBUG_DRIVER("%s i=%d dispname=%s\n", __func__, i,
+ params[i].sink->edid_caps.display_name);
+ }
+
+ DRM_DEBUG_DRIVER("dsc=%d bits_per_pixel=%d pbn=%d\n",
+ params[i].timing->flags.DSC,
+ params[i].timing->dsc_cfg.bits_per_pixel,
+ vars[i + k].pbn);
}
}
@@ -888,22 +927,31 @@ static bool is_dsc_need_re_compute(
struct dc_state *dc_state,
struct dc_link *dc_link)
{
- int i;
+ int i, j;
bool is_dsc_need_re_compute = false;
+ struct amdgpu_dm_connector *stream_on_link[MAX_PIPES];
+ int new_stream_on_link_num = 0;
+ struct amdgpu_dm_connector *aconnector;
+ struct dc_stream_state *stream;
+ const struct dc *dc = dc_link->dc;
- /* only check phy used by mst branch */
+ /* only check phy used by dsc mst branch */
if (dc_link->type != dc_connection_mst_branch)
return false;
+ if (!(dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT ||
+ dc_link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_PASSTHROUGH_SUPPORT))
+ return false;
+
+ for (i = 0; i < MAX_PIPES; i++)
+ stream_on_link[i] = NULL;
+
/* check if there is mode change in new request */
for (i = 0; i < dc_state->stream_count; i++) {
- struct amdgpu_dm_connector *aconnector;
- struct dc_stream_state *stream;
struct drm_crtc_state *new_crtc_state;
struct drm_connector_state *new_conn_state;
stream = dc_state->streams[i];
-
if (!stream)
continue;
@@ -915,8 +963,10 @@ static bool is_dsc_need_re_compute(
if (!aconnector)
continue;
- new_conn_state = drm_atomic_get_new_connector_state(state, &aconnector->base);
+ stream_on_link[new_stream_on_link_num] = aconnector;
+ new_stream_on_link_num++;
+ new_conn_state = drm_atomic_get_new_connector_state(state, &aconnector->base);
if (!new_conn_state)
continue;
@@ -927,7 +977,6 @@ static bool is_dsc_need_re_compute(
continue;
new_crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc);
-
if (!new_crtc_state)
continue;
@@ -937,7 +986,34 @@ static bool is_dsc_need_re_compute(
if (new_crtc_state->enable && new_crtc_state->active) {
if (new_crtc_state->mode_changed || new_crtc_state->active_changed ||
new_crtc_state->connectors_changed)
- is_dsc_need_re_compute = true;
+ return true;
+ }
+ }
+
+ /* check current_state if there stream on link but it is not in
+ * new request state
+ */
+ for (i = 0; i < dc->current_state->stream_count; i++) {
+ stream = dc->current_state->streams[i];
+ /* only check stream on the mst hub */
+ if (stream->link != dc_link)
+ continue;
+
+ aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
+ if (!aconnector)
+ continue;
+
+ for (j = 0; j < new_stream_on_link_num; j++) {
+ if (stream_on_link[j]) {
+ if (aconnector == stream_on_link[j])
+ break;
+ }
+ }
+
+ if (j == new_stream_on_link_num) {
+ /* not in new state */
+ is_dsc_need_re_compute = true;
+ break;
}
}
@@ -1005,4 +1081,197 @@ bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
return true;
}
+static bool
+ pre_compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
+ struct dc_state *dc_state,
+ struct dsc_mst_fairness_vars *vars)
+{
+ int i, j;
+ struct dc_stream_state *stream;
+ bool computed_streams[MAX_PIPES];
+ struct amdgpu_dm_connector *aconnector;
+ int link_vars_start_index = 0;
+
+ for (i = 0; i < dc_state->stream_count; i++)
+ computed_streams[i] = false;
+
+ for (i = 0; i < dc_state->stream_count; i++) {
+ stream = dc_state->streams[i];
+
+ if (stream->signal != SIGNAL_TYPE_DISPLAY_PORT_MST)
+ continue;
+
+ aconnector = (struct amdgpu_dm_connector *)stream->dm_stream_context;
+
+ if (!aconnector || !aconnector->dc_sink)
+ continue;
+
+ if (!aconnector->dc_sink->dsc_caps.dsc_dec_caps.is_dsc_supported)
+ continue;
+
+ if (computed_streams[i])
+ continue;
+
+ if (!is_dsc_need_re_compute(state, dc_state, stream->link))
+ continue;
+
+ mutex_lock(&aconnector->mst_mgr.lock);
+ if (!compute_mst_dsc_configs_for_link(state,
+ dc_state,
+ stream->link,
+ vars,
+ &link_vars_start_index)) {
+ mutex_unlock(&aconnector->mst_mgr.lock);
+ return false;
+ }
+ mutex_unlock(&aconnector->mst_mgr.lock);
+
+ for (j = 0; j < dc_state->stream_count; j++) {
+ if (dc_state->streams[j]->link == stream->link)
+ computed_streams[j] = true;
+ }
+ }
+
+ return true;
+}
+
+static int find_crtc_index_in_state_by_stream(struct drm_atomic_state *state,
+ struct dc_stream_state *stream)
+{
+ int i;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *new_state, *old_state;
+
+ for_each_oldnew_crtc_in_state(state, crtc, old_state, new_state, i) {
+ struct dm_crtc_state *dm_state = to_dm_crtc_state(new_state);
+
+ if (dm_state->stream == stream)
+ return i;
+ }
+ return -1;
+}
+
+static bool is_link_to_dschub(struct dc_link *dc_link)
+{
+ union dpcd_dsc_basic_capabilities *dsc_caps =
+ &dc_link->dpcd_caps.dsc_caps.dsc_basic_caps;
+
+ /* only check phy used by dsc mst branch */
+ if (dc_link->type != dc_connection_mst_branch)
+ return false;
+
+ if (!(dsc_caps->fields.dsc_support.DSC_SUPPORT ||
+ dsc_caps->fields.dsc_support.DSC_PASSTHROUGH_SUPPORT))
+ return false;
+ return true;
+}
+
+static bool is_dsc_precompute_needed(struct drm_atomic_state *state)
+{
+ int i;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state, *new_crtc_state;
+ bool ret = false;
+
+ for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
+ struct dm_crtc_state *dm_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+ if (!amdgpu_dm_find_first_crtc_matching_connector(state, crtc)) {
+ ret = false;
+ break;
+ }
+ if (dm_crtc_state->stream && dm_crtc_state->stream->link)
+ if (is_link_to_dschub(dm_crtc_state->stream->link))
+ ret = true;
+ }
+ return ret;
+}
+
+void pre_validate_dsc(struct drm_atomic_state *state,
+ struct dm_atomic_state **dm_state_ptr,
+ struct dsc_mst_fairness_vars *vars)
+{
+ int i;
+ struct dm_atomic_state *dm_state;
+ struct dc_state *local_dc_state = NULL;
+
+ if (!is_dsc_precompute_needed(state)) {
+ DRM_INFO_ONCE("DSC precompute is not needed.\n");
+ return;
+ }
+ if (dm_atomic_get_state(state, dm_state_ptr)) {
+ DRM_INFO_ONCE("dm_atomic_get_state() failed\n");
+ return;
+ }
+ dm_state = *dm_state_ptr;
+
+ /*
+ * create local vailable for dc_state. copy content of streams of dm_state->context
+ * to local variable. make sure stream pointer of local variable not the same as stream
+ * from dm_state->context.
+ */
+
+ local_dc_state = kmemdup(dm_state->context, sizeof(struct dc_state), GFP_KERNEL);
+ if (!local_dc_state)
+ return;
+
+ for (i = 0; i < local_dc_state->stream_count; i++) {
+ struct dc_stream_state *stream = dm_state->context->streams[i];
+ int ind = find_crtc_index_in_state_by_stream(state, stream);
+
+ if (ind >= 0) {
+ struct amdgpu_dm_connector *aconnector;
+ struct drm_connector_state *drm_new_conn_state;
+ struct dm_connector_state *dm_new_conn_state;
+ struct dm_crtc_state *dm_old_crtc_state;
+
+ aconnector =
+ amdgpu_dm_find_first_crtc_matching_connector(state,
+ state->crtcs[ind].ptr);
+ drm_new_conn_state =
+ drm_atomic_get_new_connector_state(state,
+ &aconnector->base);
+ dm_new_conn_state = to_dm_connector_state(drm_new_conn_state);
+ dm_old_crtc_state = to_dm_crtc_state(state->crtcs[ind].old_state);
+
+ local_dc_state->streams[i] =
+ create_validate_stream_for_sink(aconnector,
+ &state->crtcs[ind].new_state->mode,
+ dm_new_conn_state,
+ dm_old_crtc_state->stream);
+ }
+ }
+
+ if (!pre_compute_mst_dsc_configs_for_state(state, local_dc_state, vars)) {
+ DRM_INFO_ONCE("pre_compute_mst_dsc_configs_for_state() failed\n");
+ goto clean_exit;
+ }
+
+ /*
+ * compare local_streams -> timing with dm_state->context,
+ * if the same set crtc_state->mode-change = 0;
+ */
+ for (i = 0; i < local_dc_state->stream_count; i++) {
+ struct dc_stream_state *stream = dm_state->context->streams[i];
+
+ if (local_dc_state->streams[i] &&
+ is_timing_changed(stream, local_dc_state->streams[i])) {
+ DRM_INFO_ONCE("crtc[%d] needs mode_changed\n", i);
+ } else {
+ int ind = find_crtc_index_in_state_by_stream(state, stream);
+
+ if (ind >= 0)
+ state->crtcs[ind].new_state->mode_changed = 0;
+ }
+ }
+clean_exit:
+ for (i = 0; i < local_dc_state->stream_count; i++) {
+ struct dc_stream_state *stream = dm_state->context->streams[i];
+
+ if (local_dc_state->streams[i] != stream)
+ dc_stream_release(local_dc_state->streams[i]);
+ }
+
+ kfree(local_dc_state);
+}
#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
index 900d3f7a8498..85628ad59e6c 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
@@ -26,6 +26,14 @@
#ifndef __DAL_AMDGPU_DM_MST_TYPES_H__
#define __DAL_AMDGPU_DM_MST_TYPES_H__
+#define DP_BRANCH_DEVICE_ID_90CC24 0x90CC24
+
+#define SYNAPTICS_RC_COMMAND 0x4B2
+#define SYNAPTICS_RC_RESULT 0x4B3
+#define SYNAPTICS_RC_LENGTH 0x4B8
+#define SYNAPTICS_RC_OFFSET 0x4BC
+#define SYNAPTICS_RC_DATA 0x4C0
+
struct amdgpu_display_manager;
struct amdgpu_dm_connector;
@@ -38,8 +46,6 @@ void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
void
dm_dp_create_fake_mst_encoders(struct amdgpu_device *adev);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-
struct dsc_mst_fairness_vars {
int pbn;
bool dsc_enabled;
@@ -50,6 +56,11 @@ struct dsc_mst_fairness_vars {
bool compute_mst_dsc_configs_for_state(struct drm_atomic_state *state,
struct dc_state *dc_state,
struct dsc_mst_fairness_vars *vars);
-#endif
+
+bool needs_dsc_aux_workaround(struct dc_link *link);
+
+void pre_validate_dsc(struct drm_atomic_state *state,
+ struct dm_atomic_state **dm_state_ptr,
+ struct dsc_mst_fairness_vars *vars);
#endif
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
index eba270121698..75284e2cec74 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c
@@ -99,12 +99,9 @@ bool dm_pp_apply_display_requirements(
adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1;
}
- if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->display_configuration_change)
- adev->powerplay.pp_funcs->display_configuration_change(
- adev->powerplay.pp_handle,
- &adev->pm.pm_display_cfg);
+ amdgpu_dpm_display_configuration_change(adev, &adev->pm.pm_display_cfg);
- amdgpu_pm_compute_clocks(adev);
+ amdgpu_dpm_compute_clocks(adev);
}
return true;
@@ -298,31 +295,25 @@ bool dm_pp_get_clock_levels_by_type(
struct dm_pp_clock_levels *dc_clks)
{
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
struct amd_pp_clocks pp_clks = { 0 };
struct amd_pp_simple_clock_info validation_clks = { 0 };
uint32_t i;
- if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_clock_by_type) {
- if (adev->powerplay.pp_funcs->get_clock_by_type(pp_handle,
- dc_to_pp_clock_type(clk_type), &pp_clks)) {
- /* Error in pplib. Provide default values. */
- get_default_clock_levels(clk_type, dc_clks);
- return true;
- }
+ if (amdgpu_dpm_get_clock_by_type(adev,
+ dc_to_pp_clock_type(clk_type), &pp_clks)) {
+ /* Error in pplib. Provide default values. */
+ get_default_clock_levels(clk_type, dc_clks);
+ return true;
}
pp_to_dc_clock_levels(&pp_clks, dc_clks, clk_type);
- if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_display_mode_validation_clocks) {
- if (adev->powerplay.pp_funcs->get_display_mode_validation_clocks(
- pp_handle, &validation_clks)) {
- /* Error in pplib. Provide default values. */
- DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n");
- validation_clks.engine_max_clock = 72000;
- validation_clks.memory_max_clock = 80000;
- validation_clks.level = 0;
- }
+ if (amdgpu_dpm_get_display_mode_validation_clks(adev, &validation_clks)) {
+ /* Error in pplib. Provide default values. */
+ DRM_INFO("DM_PPLIB: Warning: using default validation clocks!\n");
+ validation_clks.engine_max_clock = 72000;
+ validation_clks.memory_max_clock = 80000;
+ validation_clks.level = 0;
}
DRM_INFO("DM_PPLIB: Validation clocks:\n");
@@ -370,18 +361,14 @@ bool dm_pp_get_clock_levels_by_type_with_latency(
struct dm_pp_clock_levels_with_latency *clk_level_info)
{
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
struct pp_clock_levels_with_latency pp_clks = { 0 };
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
int ret;
- if (pp_funcs && pp_funcs->get_clock_by_type_with_latency) {
- ret = pp_funcs->get_clock_by_type_with_latency(pp_handle,
- dc_to_pp_clock_type(clk_type),
- &pp_clks);
- if (ret)
- return false;
- }
+ ret = amdgpu_dpm_get_clock_by_type_with_latency(adev,
+ dc_to_pp_clock_type(clk_type),
+ &pp_clks);
+ if (ret)
+ return false;
pp_to_dc_clock_levels_with_latency(&pp_clks, clk_level_info, clk_type);
@@ -394,18 +381,14 @@ bool dm_pp_get_clock_levels_by_type_with_voltage(
struct dm_pp_clock_levels_with_voltage *clk_level_info)
{
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
struct pp_clock_levels_with_voltage pp_clk_info = {0};
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
int ret;
- if (pp_funcs && pp_funcs->get_clock_by_type_with_voltage) {
- ret = pp_funcs->get_clock_by_type_with_voltage(pp_handle,
- dc_to_pp_clock_type(clk_type),
- &pp_clk_info);
- if (ret)
- return false;
- }
+ ret = amdgpu_dpm_get_clock_by_type_with_voltage(adev,
+ dc_to_pp_clock_type(clk_type),
+ &pp_clk_info);
+ if (ret)
+ return false;
pp_to_dc_clock_levels_with_voltage(&pp_clk_info, clk_level_info, clk_type);
@@ -417,19 +400,16 @@ bool dm_pp_notify_wm_clock_changes(
struct dm_pp_wm_sets_with_clock_ranges *wm_with_clock_ranges)
{
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
/*
* Limit this watermark setting for Polaris for now
* TODO: expand this to other ASICs
*/
- if ((adev->asic_type >= CHIP_POLARIS10) && (adev->asic_type <= CHIP_VEGAM)
- && pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges) {
- if (!pp_funcs->set_watermarks_for_clocks_ranges(pp_handle,
+ if ((adev->asic_type >= CHIP_POLARIS10) &&
+ (adev->asic_type <= CHIP_VEGAM) &&
+ !amdgpu_dpm_set_watermarks_for_clocks_ranges(adev,
(void *)wm_with_clock_ranges))
return true;
- }
return false;
}
@@ -456,12 +436,10 @@ bool dm_pp_apply_clock_for_voltage_request(
if (!pp_clock_request.clock_type)
return false;
- if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->display_clock_voltage_request)
- ret = adev->powerplay.pp_funcs->display_clock_voltage_request(
- adev->powerplay.pp_handle,
- &pp_clock_request);
- if (ret)
+ ret = amdgpu_dpm_display_clock_voltage_request(adev, &pp_clock_request);
+ if (ret && (ret != -EOPNOTSUPP))
return false;
+
return true;
}
@@ -471,15 +449,8 @@ bool dm_pp_get_static_clocks(
{
struct amdgpu_device *adev = ctx->driver_context;
struct amd_pp_clock_info pp_clk_info = {0};
- int ret = 0;
- if (adev->powerplay.pp_funcs && adev->powerplay.pp_funcs->get_current_clocks)
- ret = adev->powerplay.pp_funcs->get_current_clocks(
- adev->powerplay.pp_handle,
- &pp_clk_info);
- else
- return false;
- if (ret)
+ if (amdgpu_dpm_get_current_clocks(adev, &pp_clk_info))
return false;
static_clk_info->max_clocks_state = pp_to_dc_powerlevel_state(pp_clk_info.max_clocks_state);
@@ -494,8 +465,6 @@ static void pp_rv_set_wm_ranges(struct pp_smu *pp,
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
struct dm_pp_wm_sets_with_clock_ranges_soc15 wm_with_clock_ranges;
struct dm_pp_clock_range_for_dmif_wm_set_soc15 *wm_dce_clocks = wm_with_clock_ranges.wm_dmif_clocks_ranges;
struct dm_pp_clock_range_for_mcif_wm_set_soc15 *wm_soc_clocks = wm_with_clock_ranges.wm_mcif_clocks_ranges;
@@ -536,72 +505,48 @@ static void pp_rv_set_wm_ranges(struct pp_smu *pp,
ranges->writer_wm_sets[i].min_drain_clk_mhz * 1000;
}
- if (pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges)
- pp_funcs->set_watermarks_for_clocks_ranges(pp_handle,
- &wm_with_clock_ranges);
+ amdgpu_dpm_set_watermarks_for_clocks_ranges(adev,
+ &wm_with_clock_ranges);
}
static void pp_rv_set_pme_wa_enable(struct pp_smu *pp)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- if (pp_funcs && pp_funcs->notify_smu_enable_pwe)
- pp_funcs->notify_smu_enable_pwe(pp_handle);
+ amdgpu_dpm_notify_smu_enable_pwe(adev);
}
static void pp_rv_set_active_display_count(struct pp_smu *pp, int count)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- if (!pp_funcs || !pp_funcs->set_active_display_count)
- return;
-
- pp_funcs->set_active_display_count(pp_handle, count);
+ amdgpu_dpm_set_active_display_count(adev, count);
}
static void pp_rv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int clock)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
-
- if (!pp_funcs || !pp_funcs->set_min_deep_sleep_dcefclk)
- return;
- pp_funcs->set_min_deep_sleep_dcefclk(pp_handle, clock);
+ amdgpu_dpm_set_min_deep_sleep_dcefclk(adev, clock);
}
static void pp_rv_set_hard_min_dcefclk_by_freq(struct pp_smu *pp, int clock)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- if (!pp_funcs || !pp_funcs->set_hard_min_dcefclk_by_freq)
- return;
-
- pp_funcs->set_hard_min_dcefclk_by_freq(pp_handle, clock);
+ amdgpu_dpm_set_hard_min_dcefclk_by_freq(adev, clock);
}
static void pp_rv_set_hard_min_fclk_by_freq(struct pp_smu *pp, int mhz)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
-
- if (!pp_funcs || !pp_funcs->set_hard_min_fclk_by_freq)
- return;
- pp_funcs->set_hard_min_fclk_by_freq(pp_handle, mhz);
+ amdgpu_dpm_set_hard_min_fclk_by_freq(adev, mhz);
}
static enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp,
@@ -609,11 +554,8 @@ static enum pp_smu_status pp_nv_set_wm_ranges(struct pp_smu *pp,
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- if (pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges)
- pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, ranges);
+ amdgpu_dpm_set_watermarks_for_clocks_ranges(adev, ranges);
return PP_SMU_RESULT_OK;
}
@@ -622,14 +564,13 @@ static enum pp_smu_status pp_nv_set_display_count(struct pp_smu *pp, int count)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ int ret = 0;
- if (!pp_funcs || !pp_funcs->set_active_display_count)
+ ret = amdgpu_dpm_set_active_display_count(adev, count);
+ if (ret == -EOPNOTSUPP)
return PP_SMU_RESULT_UNSUPPORTED;
-
- /* 0: successful or smu.ppt_funcs->set_display_count = NULL; 1: fail */
- if (pp_funcs->set_active_display_count(pp_handle, count))
+ else if (ret)
+ /* 0: successful or smu.ppt_funcs->set_display_count = NULL; 1: fail */
return PP_SMU_RESULT_FAIL;
return PP_SMU_RESULT_OK;
@@ -640,14 +581,13 @@ pp_nv_set_min_deep_sleep_dcfclk(struct pp_smu *pp, int mhz)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
-
- if (!pp_funcs || !pp_funcs->set_min_deep_sleep_dcefclk)
- return PP_SMU_RESULT_UNSUPPORTED;
+ int ret = 0;
/* 0: successful or smu.ppt_funcs->set_deep_sleep_dcefclk = NULL;1: fail */
- if (pp_funcs->set_min_deep_sleep_dcefclk(pp_handle, mhz))
+ ret = amdgpu_dpm_set_min_deep_sleep_dcefclk(adev, mhz);
+ if (ret == -EOPNOTSUPP)
+ return PP_SMU_RESULT_UNSUPPORTED;
+ else if (ret)
return PP_SMU_RESULT_FAIL;
return PP_SMU_RESULT_OK;
@@ -658,12 +598,8 @@ static enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq(
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
struct pp_display_clock_request clock_req;
-
- if (!pp_funcs || !pp_funcs->display_clock_voltage_request)
- return PP_SMU_RESULT_UNSUPPORTED;
+ int ret = 0;
clock_req.clock_type = amd_pp_dcef_clock;
clock_req.clock_freq_in_khz = mhz * 1000;
@@ -671,7 +607,10 @@ static enum pp_smu_status pp_nv_set_hard_min_dcefclk_by_freq(
/* 0: successful or smu.ppt_funcs->display_clock_voltage_request = NULL
* 1: fail
*/
- if (pp_funcs->display_clock_voltage_request(pp_handle, &clock_req))
+ ret = amdgpu_dpm_display_clock_voltage_request(adev, &clock_req);
+ if (ret == -EOPNOTSUPP)
+ return PP_SMU_RESULT_UNSUPPORTED;
+ else if (ret)
return PP_SMU_RESULT_FAIL;
return PP_SMU_RESULT_OK;
@@ -682,12 +621,8 @@ pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz)
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
struct pp_display_clock_request clock_req;
-
- if (!pp_funcs || !pp_funcs->display_clock_voltage_request)
- return PP_SMU_RESULT_UNSUPPORTED;
+ int ret = 0;
clock_req.clock_type = amd_pp_mem_clock;
clock_req.clock_freq_in_khz = mhz * 1000;
@@ -695,7 +630,10 @@ pp_nv_set_hard_min_uclk_by_freq(struct pp_smu *pp, int mhz)
/* 0: successful or smu.ppt_funcs->display_clock_voltage_request = NULL
* 1: fail
*/
- if (pp_funcs->display_clock_voltage_request(pp_handle, &clock_req))
+ ret = amdgpu_dpm_display_clock_voltage_request(adev, &clock_req);
+ if (ret == -EOPNOTSUPP)
+ return PP_SMU_RESULT_UNSUPPORTED;
+ else if (ret)
return PP_SMU_RESULT_FAIL;
return PP_SMU_RESULT_OK;
@@ -706,14 +644,10 @@ static enum pp_smu_status pp_nv_set_pstate_handshake_support(
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- if (pp_funcs && pp_funcs->display_disable_memory_clock_switch) {
- if (pp_funcs->display_disable_memory_clock_switch(pp_handle,
- !pstate_handshake_supported))
- return PP_SMU_RESULT_FAIL;
- }
+ if (amdgpu_dpm_display_disable_memory_clock_switch(adev,
+ !pstate_handshake_supported))
+ return PP_SMU_RESULT_FAIL;
return PP_SMU_RESULT_OK;
}
@@ -723,12 +657,8 @@ static enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp,
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
struct pp_display_clock_request clock_req;
-
- if (!pp_funcs || !pp_funcs->display_clock_voltage_request)
- return PP_SMU_RESULT_UNSUPPORTED;
+ int ret = 0;
switch (clock_id) {
case PP_SMU_NV_DISPCLK:
@@ -748,7 +678,10 @@ static enum pp_smu_status pp_nv_set_voltage_by_freq(struct pp_smu *pp,
/* 0: successful or smu.ppt_funcs->display_clock_voltage_request = NULL
* 1: fail
*/
- if (pp_funcs->display_clock_voltage_request(pp_handle, &clock_req))
+ ret = amdgpu_dpm_display_clock_voltage_request(adev, &clock_req);
+ if (ret == -EOPNOTSUPP)
+ return PP_SMU_RESULT_UNSUPPORTED;
+ else if (ret)
return PP_SMU_RESULT_FAIL;
return PP_SMU_RESULT_OK;
@@ -759,16 +692,16 @@ static enum pp_smu_status pp_nv_get_maximum_sustainable_clocks(
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ int ret = 0;
- if (!pp_funcs || !pp_funcs->get_max_sustainable_clocks_by_dc)
+ ret = amdgpu_dpm_get_max_sustainable_clocks_by_dc(adev,
+ max_clocks);
+ if (ret == -EOPNOTSUPP)
return PP_SMU_RESULT_UNSUPPORTED;
+ else if (ret)
+ return PP_SMU_RESULT_FAIL;
- if (!pp_funcs->get_max_sustainable_clocks_by_dc(pp_handle, max_clocks))
- return PP_SMU_RESULT_OK;
-
- return PP_SMU_RESULT_FAIL;
+ return PP_SMU_RESULT_OK;
}
static enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp,
@@ -776,18 +709,17 @@ static enum pp_smu_status pp_nv_get_uclk_dpm_states(struct pp_smu *pp,
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ int ret = 0;
- if (!pp_funcs || !pp_funcs->get_uclk_dpm_states)
+ ret = amdgpu_dpm_get_uclk_dpm_states(adev,
+ clock_values_in_khz,
+ num_states);
+ if (ret == -EOPNOTSUPP)
return PP_SMU_RESULT_UNSUPPORTED;
+ else if (ret)
+ return PP_SMU_RESULT_FAIL;
- if (!pp_funcs->get_uclk_dpm_states(pp_handle,
- clock_values_in_khz,
- num_states))
- return PP_SMU_RESULT_OK;
-
- return PP_SMU_RESULT_FAIL;
+ return PP_SMU_RESULT_OK;
}
static enum pp_smu_status pp_rn_get_dpm_clock_table(
@@ -795,16 +727,15 @@ static enum pp_smu_status pp_rn_get_dpm_clock_table(
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
+ int ret = 0;
- if (!pp_funcs || !pp_funcs->get_dpm_clock_table)
+ ret = amdgpu_dpm_get_dpm_clock_table(adev, clock_table);
+ if (ret == -EOPNOTSUPP)
return PP_SMU_RESULT_UNSUPPORTED;
+ else if (ret)
+ return PP_SMU_RESULT_FAIL;
- if (!pp_funcs->get_dpm_clock_table(pp_handle, clock_table))
- return PP_SMU_RESULT_OK;
-
- return PP_SMU_RESULT_FAIL;
+ return PP_SMU_RESULT_OK;
}
static enum pp_smu_status pp_rn_set_wm_ranges(struct pp_smu *pp,
@@ -812,11 +743,8 @@ static enum pp_smu_status pp_rn_set_wm_ranges(struct pp_smu *pp,
{
const struct dc_context *ctx = pp->dm;
struct amdgpu_device *adev = ctx->driver_context;
- void *pp_handle = adev->powerplay.pp_handle;
- const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
- if (pp_funcs && pp_funcs->set_watermarks_for_clocks_ranges)
- pp_funcs->set_watermarks_for_clocks_ranges(pp_handle, ranges);
+ amdgpu_dpm_set_watermarks_for_clocks_ranges(adev, ranges);
return PP_SMU_RESULT_OK;
}
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
index c510638b4f99..141fd2721501 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_psr.c
@@ -27,51 +27,8 @@
#include "dc.h"
#include "dm_helpers.h"
#include "amdgpu_dm.h"
+#include "modules/power/power_helpers.h"
-static bool link_get_psr_caps(struct dc_link *link)
-{
- uint8_t psr_dpcd_data[EDP_PSR_RECEIVER_CAP_SIZE];
- uint8_t edp_rev_dpcd_data;
-
-
-
- if (!dm_helpers_dp_read_dpcd(NULL, link, DP_PSR_SUPPORT,
- psr_dpcd_data, sizeof(psr_dpcd_data)))
- return false;
-
- if (!dm_helpers_dp_read_dpcd(NULL, link, DP_EDP_DPCD_REV,
- &edp_rev_dpcd_data, sizeof(edp_rev_dpcd_data)))
- return false;
-
- link->dpcd_caps.psr_caps.psr_version = psr_dpcd_data[0];
- link->dpcd_caps.psr_caps.edp_revision = edp_rev_dpcd_data;
-
-#ifdef CONFIG_DRM_AMD_DC_DCN
- if (link->dpcd_caps.psr_caps.psr_version > 0x1) {
- uint8_t alpm_dpcd_data;
- uint8_t su_granularity_dpcd_data;
-
- if (!dm_helpers_dp_read_dpcd(NULL, link, DP_RECEIVER_ALPM_CAP,
- &alpm_dpcd_data, sizeof(alpm_dpcd_data)))
- return false;
-
- if (!dm_helpers_dp_read_dpcd(NULL, link, DP_PSR2_SU_Y_GRANULARITY,
- &su_granularity_dpcd_data, sizeof(su_granularity_dpcd_data)))
- return false;
-
- link->dpcd_caps.psr_caps.y_coordinate_required = psr_dpcd_data[1] & DP_PSR2_SU_Y_COORDINATE_REQUIRED;
- link->dpcd_caps.psr_caps.su_granularity_required = psr_dpcd_data[1] & DP_PSR2_SU_GRANULARITY_REQUIRED;
-
- link->dpcd_caps.psr_caps.alpm_cap = alpm_dpcd_data & DP_ALPM_CAP;
- link->dpcd_caps.psr_caps.standby_support = alpm_dpcd_data & (1 << 1);
-
- link->dpcd_caps.psr_caps.su_y_granularity = su_granularity_dpcd_data;
- }
-#endif
- return true;
-}
-
-#ifdef CONFIG_DRM_AMD_DC_DCN
static bool link_supports_psrsu(struct dc_link *link)
{
struct dc *dc = link->ctx->dc;
@@ -82,17 +39,19 @@ static bool link_supports_psrsu(struct dc_link *link)
if (dc->ctx->dce_version < DCN_VERSION_3_1)
return false;
- if (!link->dpcd_caps.psr_caps.alpm_cap ||
- !link->dpcd_caps.psr_caps.y_coordinate_required)
+ if (!is_psr_su_specific_panel(link))
return false;
- if (link->dpcd_caps.psr_caps.su_granularity_required &&
- !link->dpcd_caps.psr_caps.su_y_granularity)
+ if (!link->dpcd_caps.alpm_caps.bits.AUX_WAKE_ALPM_CAP ||
+ !link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED)
+ return false;
+
+ if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.SU_GRANULARITY_REQUIRED &&
+ !link->dpcd_caps.psr_info.psr2_su_y_granularity_cap)
return false;
return true;
}
-#endif
/*
* amdgpu_dm_set_psr_caps() - set link psr capabilities
@@ -107,27 +66,23 @@ void amdgpu_dm_set_psr_caps(struct dc_link *link)
if (link->type == dc_connection_none)
return;
- if (!link_get_psr_caps(link)) {
- DRM_ERROR("amdgpu: Failed to read PSR Caps!\n");
- return;
- }
-
- if (link->dpcd_caps.psr_caps.psr_version == 0) {
+ if (link->dpcd_caps.psr_info.psr_version == 0) {
link->psr_settings.psr_version = DC_PSR_VERSION_UNSUPPORTED;
link->psr_settings.psr_feature_enabled = false;
} else {
-#ifdef CONFIG_DRM_AMD_DC_DCN
if (link_supports_psrsu(link))
link->psr_settings.psr_version = DC_PSR_VERSION_SU_1;
else
-#endif
link->psr_settings.psr_version = DC_PSR_VERSION_1;
link->psr_settings.psr_feature_enabled = true;
}
- DRM_INFO("PSR support:%d\n", link->psr_settings.psr_feature_enabled);
+ DRM_INFO("PSR support %d, DC PSR ver %d, sink PSR ver %d\n",
+ link->psr_settings.psr_feature_enabled,
+ link->psr_settings.psr_version,
+ link->dpcd_caps.psr_info.psr_version);
}
@@ -149,10 +104,8 @@ bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream)
link = stream->link;
- psr_config.psr_version = link->dpcd_caps.psr_caps.psr_version;
-
- if (psr_config.psr_version > 0) {
- psr_config.psr_exit_link_training_required = 0x1;
+ if (link->psr_settings.psr_version != DC_PSR_VERSION_UNSUPPORTED) {
+ psr_config.psr_version = link->psr_settings.psr_version;
psr_config.psr_frame_capture_indication_req = 0;
psr_config.psr_rfb_setup_time = 0x37;
psr_config.psr_sdp_transmit_line_num_deadline = 0x20;
diff --git a/drivers/gpu/drm/amd/display/dc/Makefile b/drivers/gpu/drm/amd/display/dc/Makefile
index b1f0d6260226..b4eca0236435 100644
--- a/drivers/gpu/drm/amd/display/dc/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/Makefile
@@ -23,12 +23,12 @@
# Makefile for Display Core (dc) component.
#
-DC_LIBS = basics bios calcs clk_mgr dce gpio irq virtual
+DC_LIBS = basics bios dml clk_mgr dce gpio irq link virtual
ifdef CONFIG_DRM_AMD_DC_DCN
DC_LIBS += dcn20
DC_LIBS += dsc
-DC_LIBS += dcn10 dml
+DC_LIBS += dcn10
DC_LIBS += dcn21
DC_LIBS += dcn201
DC_LIBS += dcn30
@@ -36,6 +36,8 @@ DC_LIBS += dcn301
DC_LIBS += dcn302
DC_LIBS += dcn303
DC_LIBS += dcn31
+DC_LIBS += dcn315
+DC_LIBS += dcn316
endif
DC_LIBS += dce120
@@ -58,12 +60,10 @@ AMD_DC = $(addsuffix /Makefile, $(addprefix $(FULL_AMD_DISPLAY_PATH)/dc/,$(DC_LI
include $(AMD_DC)
DISPLAY_CORE = dc.o dc_stat.o dc_link.o dc_resource.o dc_hw_sequencer.o dc_sink.o \
-dc_surface.o dc_link_hwss.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \
+dc_surface.o dc_link_dp.o dc_link_ddc.o dc_debug.o dc_stream.o \
dc_link_enc_cfg.o dc_link_dpia.o dc_link_dpcd.o
-ifdef CONFIG_DRM_AMD_DC_DCN
DISPLAY_CORE += dc_vm_helper.o
-endif
AMD_DISPLAY_CORE = $(addprefix $(AMDDALPATH)/dc/core/,$(DISPLAY_CORE))
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
index 1e385d55e7fb..23a3b640f0ee 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser2.c
@@ -1692,7 +1692,6 @@ static enum bp_result bios_parser_get_encoder_cap_info(
ATOM_ENCODER_CAP_RECORD_HBR3_EN) ? 1 : 0;
info->HDMI_6GB_EN = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_HDMI6Gbps_EN) ? 1 : 0;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
info->IS_DP2_CAPABLE = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_DP2) ? 1 : 0;
info->DP_UHBR10_EN = (record->encodercaps &
@@ -1701,7 +1700,6 @@ static enum bp_result bios_parser_get_encoder_cap_info(
ATOM_ENCODER_CAP_RECORD_UHBR13_5_EN) ? 1 : 0;
info->DP_UHBR20_EN = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_UHBR20_EN) ? 1 : 0;
-#endif
info->DP_IS_USB_C = (record->encodercaps &
ATOM_ENCODER_CAP_RECORD_USB_C_TYPE) ? 1 : 0;
diff --git a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c
index a8cb039d2572..34e3a64f556e 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/bios_parser_common.c
@@ -213,6 +213,9 @@ static enum connector_id connector_id_from_bios_object_id(
case CONNECTOR_OBJECT_ID_MXM:
id = CONNECTOR_ID_MXM;
break;
+ case CONNECTOR_OBJECT_ID_USBC:
+ id = CONNECTOR_ID_USBC;
+ break;
default:
id = CONNECTOR_ID_UNKNOWN;
break;
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table.c b/drivers/gpu/drm/amd/display/dc/bios/command_table.c
index ad13e4e36d77..32efa92422e8 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table.c
@@ -456,7 +456,7 @@ static enum bp_result transmitter_control_v2(
if ((CONNECTOR_ID_DUAL_LINK_DVII == connector_id) ||
(CONNECTOR_ID_DUAL_LINK_DVID == connector_id))
/* on INIT this bit should be set according to the
- * phisycal connector
+ * physical connector
* Bit0: dual link connector flag
* =0 connector is single link connector
* =1 connector is dual link connector
@@ -468,7 +468,7 @@ static enum bp_result transmitter_control_v2(
cpu_to_le16((uint8_t)cntl->connector_obj_id.id);
break;
case TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS:
- /* votage swing and pre-emphsis */
+ /* voltage swing and pre-emphsis */
params.asMode.ucLaneSel = (uint8_t)cntl->lane_select;
params.asMode.ucLaneSet = (uint8_t)cntl->lane_settings;
break;
@@ -522,7 +522,8 @@ static enum bp_result transmitter_control_v2(
*/
params.acConfig.ucEncoderSel = 1;
- if (CONNECTOR_ID_DISPLAY_PORT == connector_id)
+ if (CONNECTOR_ID_DISPLAY_PORT == connector_id
+ || CONNECTOR_ID_USBC == connector_id)
/* Bit4: DP connector flag
* =0 connector is none-DP connector
* =1 connector is DP connector
@@ -2120,7 +2121,7 @@ static enum bp_result program_clock_v5(
memset(&params, 0, sizeof(params));
if (!bp->cmd_helper->clock_source_id_to_atom(
bp_params->pll_id, &atom_pll_id)) {
- BREAK_TO_DEBUGGER(); /* Invalid Inpute!! */
+ BREAK_TO_DEBUGGER(); /* Invalid Input!! */
return BP_RESULT_BADINPUT;
}
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
index 9afa5eb2e6d3..f52f7ff7ead4 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table2.c
@@ -338,12 +338,10 @@ static enum bp_result transmitter_control_v1_7(
const struct command_table_helper *cmd = bp->cmd_helper;
struct dmub_dig_transmitter_control_data_v1_7 dig_v1_7 = {0};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint8_t hpo_instance = (uint8_t)cntl->hpo_engine_id - ENGINE_ID_HPO_0;
if (dc_is_dp_signal(cntl->signal))
hpo_instance = (uint8_t)cntl->hpo_engine_id - ENGINE_ID_HPO_DP_0;
-#endif
dig_v1_7.phyid = cmd->phy_id_to_atom(cntl->transmitter);
dig_v1_7.action = (uint8_t)cntl->action;
@@ -358,9 +356,7 @@ static enum bp_result transmitter_control_v1_7(
dig_v1_7.hpdsel = cmd->hpd_sel_to_atom(cntl->hpd_sel);
dig_v1_7.digfe_sel = cmd->dig_encoder_sel_to_atom(cntl->engine_id);
dig_v1_7.connobj_id = (uint8_t)cntl->connector_obj_id.id;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
dig_v1_7.HPO_instance = hpo_instance;
-#endif
dig_v1_7.symclk_units.symclk_10khz = cntl->pixel_clock/10;
if (cntl->action == TRANSMITTER_CONTROL_ENABLE ||
diff --git a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
index eedc553f340e..f3792286f571 100644
--- a/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
+++ b/drivers/gpu/drm/amd/display/dc/bios/command_table_helper2.c
@@ -65,7 +65,6 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
case DCE_VERSION_12_1:
*h = dal_cmd_tbl_helper_dce112_get_table2();
return true;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case DCN_VERSION_1_0:
case DCN_VERSION_1_01:
case DCN_VERSION_2_0:
@@ -76,9 +75,11 @@ bool dal_bios_parser_init_cmd_tbl_helper2(
case DCN_VERSION_3_02:
case DCN_VERSION_3_03:
case DCN_VERSION_3_1:
+ case DCN_VERSION_3_15:
+ case DCN_VERSION_3_16:
*h = dal_cmd_tbl_helper_dce112_get_table2();
return true;
-#endif
+
default:
/* Unsupported DCE */
BREAK_TO_DEBUGGER();
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/Makefile b/drivers/gpu/drm/amd/display/dc/calcs/Makefile
deleted file mode 100644
index f3c00f479e1c..000000000000
--- a/drivers/gpu/drm/amd/display/dc/calcs/Makefile
+++ /dev/null
@@ -1,68 +0,0 @@
-#
-# Copyright 2017 Advanced Micro Devices, Inc.
-# Copyright 2019 Raptor Engineering, LLC
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the "Software"),
-# to deal in the Software without restriction, including without limitation
-# the rights to use, copy, modify, merge, publish, distribute, sublicense,
-# and/or sell copies of the Software, and to permit persons to whom the
-# Software is furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
-# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
-#
-#
-# Makefile for the 'calcs' sub-component of DAL.
-# It calculates Bandwidth and Watermarks values for HW programming
-#
-
-ifdef CONFIG_X86
-calcs_ccflags := -mhard-float -msse
-endif
-
-ifdef CONFIG_PPC64
-calcs_ccflags := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-calcs_ccflags += -mpreferred-stack-boundary=4
-else
-calcs_ccflags += -msse2
-endif
-endif
-
-CFLAGS_$(AMDDALPATH)/dc/calcs/dcn_calcs.o := $(calcs_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/calcs/dcn_calc_auto.o := $(calcs_ccflags)
-CFLAGS_$(AMDDALPATH)/dc/calcs/dcn_calc_math.o := $(calcs_ccflags) -Wno-tautological-compare
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/calcs/dcn_calcs.o := $(calcs_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/calcs/dcn_calc_auto.o := $(calcs_rcflags)
-CFLAGS_REMOVE_$(AMDDALPATH)/dc/calcs/dcn_calc_math.o := $(calcs_rcflags)
-
-BW_CALCS = dce_calcs.o bw_fixed.o custom_float.o
-
-ifdef CONFIG_DRM_AMD_DC_DCN
-BW_CALCS += dcn_calcs.o dcn_calc_math.o dcn_calc_auto.o
-endif
-
-AMD_DAL_BW_CALCS = $(addprefix $(AMDDALPATH)/dc/calcs/,$(BW_CALCS))
-
-AMD_DISPLAY_FILES += $(AMD_DAL_BW_CALCS)
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
index 6bd73e49a6d2..817871917632 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/Makefile
@@ -153,4 +153,23 @@ CLK_MGR_DCN31 = dcn31_smu.o dcn31_clk_mgr.o
AMD_DAL_CLK_MGR_DCN31 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn31/,$(CLK_MGR_DCN31))
AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN31)
+
+###############################################################################
+# DCN315
+###############################################################################
+CLK_MGR_DCN315 = dcn315_smu.o dcn315_clk_mgr.o
+
+AMD_DAL_CLK_MGR_DCN315 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn315/,$(CLK_MGR_DCN315))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN315)
+
+###############################################################################
+# DCN316
+###############################################################################
+CLK_MGR_DCN316 = dcn316_smu.o dcn316_clk_mgr.o
+
+AMD_DAL_CLK_MGR_DCN316 = $(addprefix $(AMDDALPATH)/dc/clk_mgr/dcn316/,$(CLK_MGR_DCN316))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_CLK_MGR_DCN316)
+
endif
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
index 9200c8ce02ba..772bffda68cc 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/clk_mgr.c
@@ -43,6 +43,8 @@
#include "dcn30/dcn30_clk_mgr.h"
#include "dcn301/vg_clk_mgr.h"
#include "dcn31/dcn31_clk_mgr.h"
+#include "dcn315/dcn315_clk_mgr.h"
+#include "dcn316/dcn316_clk_mgr.h"
int clk_mgr_helper_get_active_display_cnt(
@@ -289,6 +291,31 @@ struct clk_mgr *dc_clk_mgr_create(struct dc_context *ctx, struct pp_smu_funcs *p
dcn31_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
return &clk_mgr->base.base;
}
+ break;
+ case AMDGPU_FAMILY_GC_10_3_6: {
+ struct clk_mgr_dcn315 *clk_mgr = kzalloc(sizeof(*clk_mgr), GFP_KERNEL);
+
+ if (clk_mgr == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ dcn315_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
+ return &clk_mgr->base.base;
+ }
+ break;
+ case AMDGPU_FAMILY_GC_10_3_7: {
+ struct clk_mgr_dcn316 *clk_mgr = kzalloc(sizeof(*clk_mgr), GFP_KERNEL);
+
+ if (clk_mgr == NULL) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ dcn316_clk_mgr_construct(ctx, clk_mgr, pp_smu, dccg);
+ return &clk_mgr->base.base;
+ }
+ break;
#endif
default:
@@ -322,7 +349,15 @@ void dc_destroy_clk_mgr(struct clk_mgr *clk_mgr_base)
break;
case FAMILY_YELLOW_CARP:
- dcn31_clk_mgr_destroy(clk_mgr);
+ dcn31_clk_mgr_destroy(clk_mgr);
+ break;
+
+ case AMDGPU_FAMILY_GC_10_3_6:
+ dcn315_clk_mgr_destroy(clk_mgr);
+ break;
+
+ case AMDGPU_FAMILY_GC_10_3_7:
+ dcn316_clk_mgr_destroy(clk_mgr);
break;
default:
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c
index b210f8e9d592..26feefbb8990 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce100/dce_clk_mgr.c
@@ -374,6 +374,8 @@ void dce_clock_read_ss_info(struct clk_mgr_internal *clk_mgr_dce)
clk_mgr_dce->dprefclk_ss_percentage =
info.spread_spectrum_percentage;
}
+ if (clk_mgr_dce->base.ctx->dc->config.ignore_dpref_ss)
+ clk_mgr_dce->dprefclk_ss_percentage = 0;
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c
index 06bab24d8e27..450eaead4f20 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn10/rv1_clk_mgr_vbios_smu.c
@@ -101,7 +101,8 @@ static uint32_t rv1_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsi
return res_val;
}
-int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr, unsigned int msg_id, unsigned int param)
+static int rv1_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
+ unsigned int msg_id, unsigned int param)
{
uint32_t result;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
index fbdd0a92d146..451e8d6cd8bd 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn201/dcn201_clk_mgr.c
@@ -157,8 +157,7 @@ static void dcn201_update_clocks(struct clk_mgr *clk_mgr_base,
} else {
if (update_dppclk || update_dispclk)
dcn20_update_clocks_update_dentist(clk_mgr, context);
- if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz)
- dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
+ dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
index f4dee0e48a67..cf1b5f354ae9 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr.c
@@ -88,11 +88,22 @@ static int rn_get_active_display_cnt_wa(struct dc *dc, struct dc_state *context)
static void rn_set_low_power_state(struct clk_mgr *clk_mgr_base)
{
+ int display_count;
struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct dc *dc = clk_mgr_base->ctx->dc;
+ struct dc_state *context = dc->current_state;
+
+ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
+
+ display_count = rn_get_active_display_cnt_wa(dc, context);
- rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
- /* update power state */
- clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
+ /* if we can go lower, go lower */
+ if (display_count == 0) {
+ rn_vbios_smu_set_dcn_low_power_state(clk_mgr, DCN_PWR_STATE_LOW_POWER);
+ /* update power state */
+ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
+ }
+ }
}
static void rn_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr,
@@ -111,7 +122,7 @@ static void rn_update_clocks_update_dpp_dto(struct clk_mgr_internal *clk_mgr,
dpp_inst = clk_mgr->base.ctx->dc->res_pool->dpps[i]->inst;
dppclk_khz = context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz;
- prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[i];
+ prev_dppclk_khz = clk_mgr->dccg->pipe_dppclk_khz[dpp_inst];
if (safe_to_lower || prev_dppclk_khz < dppclk_khz)
clk_mgr->dccg->funcs->update_dpp_dto(
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c
index 8161a6ae410d..30c6f9cd717f 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn21/rn_clk_mgr_vbios_smu.c
@@ -94,6 +94,9 @@ static int rn_vbios_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
{
uint32_t result;
+ result = rn_smu_wait_for_response(clk_mgr, 10, 200000);
+ ASSERT(result == VBIOSSMC_Result_OK);
+
/* First clear response register */
REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
index 10c7be40dfb0..5ed6a93d1708 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr.c
@@ -25,30 +25,23 @@
#include "dccg.h"
#include "clk_mgr_internal.h"
-
#include "dcn30_clk_mgr_smu_msg.h"
#include "dcn20/dcn20_clk_mgr.h"
#include "dce100/dce_clk_mgr.h"
+#include "dcn30/dcn30_clk_mgr.h"
#include "reg_helper.h"
#include "core_types.h"
#include "dm_helpers.h"
-
#include "atomfirmware.h"
-
-
#include "sienna_cichlid_ip_offset.h"
#include "dcn/dcn_3_0_0_offset.h"
#include "dcn/dcn_3_0_0_sh_mask.h"
-
#include "nbio/nbio_7_4_offset.h"
-
-#include "dcn/dpcs_3_0_0_offset.h"
-#include "dcn/dpcs_3_0_0_sh_mask.h"
-
+#include "dpcs/dpcs_3_0_0_offset.h"
+#include "dpcs/dpcs_3_0_0_sh_mask.h"
#include "mmhub/mmhub_2_0_0_offset.h"
#include "mmhub/mmhub_2_0_0_sh_mask.h"
-/*we don't have clk folder yet*/
-#include "dcn30/dcn30_clk_mgr.h"
+#include "dcn30_smu11_driver_if.h"
#undef FN
#define FN(reg_name, field_name) \
@@ -83,7 +76,7 @@ static const struct clk_mgr_mask clk_mgr_mask = {
/* Query SMU for all clock states for a particular clock */
-static void dcn3_init_single_clock(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, unsigned int *entry_0, unsigned int *num_levels)
+static void dcn3_init_single_clock(struct clk_mgr_internal *clk_mgr, uint32_t clk, unsigned int *entry_0, unsigned int *num_levels)
{
unsigned int i;
char *entry_i = (char *)entry_0;
@@ -184,6 +177,7 @@ void dcn3_init_clocks(struct clk_mgr *clk_mgr_base)
dcn3_init_single_clock(clk_mgr, PPCLK_DCEFCLK,
&clk_mgr_base->bw_params->clk_table.entries[0].dcfclk_mhz,
&num_levels);
+ dcn30_smu_set_min_deep_sleep_dcef_clk(clk_mgr, 0);
/* DTBCLK */
dcn3_init_single_clock(clk_mgr, PPCLK_DTBCLK,
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c
index 8ecc708bcd9e..bfc960579760 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.c
@@ -29,6 +29,7 @@
#include "clk_mgr_internal.h"
#include "reg_helper.h"
#include "dalsmc.h"
+#include "dcn30_smu11_driver_if.h"
#define mmDAL_MSG_REG 0x1628A
#define mmDAL_ARG_REG 0x16273
@@ -197,7 +198,7 @@ void dcn30_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
}
/* Returns the actual frequency that was set in MHz, 0 on failure */
-unsigned int dcn30_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, uint16_t freq_mhz)
+unsigned int dcn30_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz)
{
uint32_t response = 0;
@@ -215,7 +216,7 @@ unsigned int dcn30_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, PP
}
/* Returns the actual frequency that was set in MHz, 0 on failure */
-unsigned int dcn30_smu_set_hard_max_by_freq(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, uint16_t freq_mhz)
+unsigned int dcn30_smu_set_hard_max_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz)
{
uint32_t response = 0;
@@ -246,7 +247,7 @@ unsigned int dcn30_smu_set_hard_max_by_freq(struct clk_mgr_internal *clk_mgr, PP
*
* Returns 0 on failure
*/
-unsigned int dcn30_smu_get_dpm_freq_by_index(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, uint8_t dpm_level)
+unsigned int dcn30_smu_get_dpm_freq_by_index(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint8_t dpm_level)
{
uint32_t response = 0;
@@ -264,7 +265,7 @@ unsigned int dcn30_smu_get_dpm_freq_by_index(struct clk_mgr_internal *clk_mgr, P
}
/* Returns the max DPM frequency in DC mode in MHz, 0 on failure */
-unsigned int dcn30_smu_get_dc_mode_max_dpm_freq(struct clk_mgr_internal *clk_mgr, PPCLK_e clk)
+unsigned int dcn30_smu_get_dc_mode_max_dpm_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk)
{
uint32_t response = 0;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.h
index dd2640a3ce5d..ca9f5296be94 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_clk_mgr_smu_msg.h
@@ -28,65 +28,6 @@
#include "core_types.h"
-#define SMU11_DRIVER_IF_VERSION 0x1F
-
-typedef enum {
- PPCLK_GFXCLK = 0,
- PPCLK_SOCCLK,
- PPCLK_UCLK,
- PPCLK_FCLK,
- PPCLK_DCLK_0,
- PPCLK_VCLK_0,
- PPCLK_DCLK_1,
- PPCLK_VCLK_1,
- PPCLK_DCEFCLK,
- PPCLK_DISPCLK,
- PPCLK_PIXCLK,
- PPCLK_PHYCLK,
- PPCLK_DTBCLK,
- PPCLK_COUNT,
-} PPCLK_e;
-
-typedef struct {
- uint16_t MinClock; // This is either DCEFCLK or SOCCLK (in MHz)
- uint16_t MaxClock; // This is either DCEFCLK or SOCCLK (in MHz)
- uint16_t MinUclk;
- uint16_t MaxUclk;
-
- uint8_t WmSetting;
- uint8_t Flags;
- uint8_t Padding[2];
-
-} WatermarkRowGeneric_t;
-
-#define NUM_WM_RANGES 4
-
-typedef enum {
- WM_SOCCLK = 0,
- WM_DCEFCLK,
- WM_COUNT,
-} WM_CLOCK_e;
-
-typedef enum {
- WATERMARKS_CLOCK_RANGE = 0,
- WATERMARKS_DUMMY_PSTATE,
- WATERMARKS_MALL,
- WATERMARKS_COUNT,
-} WATERMARKS_FLAGS_e;
-
-typedef struct {
- // Watermarks
- WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES];
-} Watermarks_t;
-
-typedef struct {
- Watermarks_t Watermarks;
-
- uint32_t MmHubPadding[8]; // SMU internal use
-} WatermarksExternal_t;
-
-#define TABLE_WATERMARKS 1
-
struct clk_mgr_internal;
bool dcn30_smu_test_message(struct clk_mgr_internal *clk_mgr, uint32_t input);
@@ -97,10 +38,10 @@ void dcn30_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint
void dcn30_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low);
void dcn30_smu_transfer_wm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr);
void dcn30_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr);
-unsigned int dcn30_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, uint16_t freq_mhz);
-unsigned int dcn30_smu_set_hard_max_by_freq(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, uint16_t freq_mhz);
-unsigned int dcn30_smu_get_dpm_freq_by_index(struct clk_mgr_internal *clk_mgr, PPCLK_e clk, uint8_t dpm_level);
-unsigned int dcn30_smu_get_dc_mode_max_dpm_freq(struct clk_mgr_internal *clk_mgr, PPCLK_e clk);
+unsigned int dcn30_smu_set_hard_min_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz);
+unsigned int dcn30_smu_set_hard_max_by_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint16_t freq_mhz);
+unsigned int dcn30_smu_get_dpm_freq_by_index(struct clk_mgr_internal *clk_mgr, uint32_t clk, uint8_t dpm_level);
+unsigned int dcn30_smu_get_dc_mode_max_dpm_freq(struct clk_mgr_internal *clk_mgr, uint32_t clk);
void dcn30_smu_set_min_deep_sleep_dcef_clk(struct clk_mgr_internal *clk_mgr, uint32_t freq_mhz);
void dcn30_smu_set_num_of_displays(struct clk_mgr_internal *clk_mgr, uint32_t num_displays);
void dcn30_smu_set_display_refresh_from_mall(struct clk_mgr_internal *clk_mgr, bool enable, uint8_t cache_timer_delay, uint8_t cache_timer_scale);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h
new file mode 100644
index 000000000000..8ea8ee57b39f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn30/dcn30_smu11_driver_if.h
@@ -0,0 +1,74 @@
+// This is a stripped-down version of the smu11_driver_if.h file for the relevant DAL interfaces.
+
+#define SMU11_DRIVER_IF_VERSION 0x40
+
+//Only Clks that have DPM descriptors are listed here
+typedef enum {
+ PPCLK_GFXCLK = 0,
+ PPCLK_SOCCLK,
+ PPCLK_UCLK,
+ PPCLK_FCLK,
+ PPCLK_DCLK_0,
+ PPCLK_VCLK_0,
+ PPCLK_DCLK_1,
+ PPCLK_VCLK_1,
+ PPCLK_DCEFCLK,
+ PPCLK_DISPCLK,
+ PPCLK_PIXCLK,
+ PPCLK_PHYCLK,
+ PPCLK_DTBCLK,
+ PPCLK_COUNT,
+} PPCLK_e;
+
+typedef struct {
+ uint16_t MinClock; // This is either DCEFCLK or SOCCLK (in MHz)
+ uint16_t MaxClock; // This is either DCEFCLK or SOCCLK (in MHz)
+ uint16_t MinUclk;
+ uint16_t MaxUclk;
+
+ uint8_t WmSetting;
+ uint8_t Flags;
+ uint8_t Padding[2];
+
+} WatermarkRowGeneric_t;
+
+#define NUM_WM_RANGES 4
+
+typedef enum {
+ WM_SOCCLK = 0,
+ WM_DCEFCLK,
+ WM_COUNT,
+} WM_CLOCK_e;
+
+typedef enum {
+ WATERMARKS_CLOCK_RANGE = 0,
+ WATERMARKS_DUMMY_PSTATE,
+ WATERMARKS_MALL,
+ WATERMARKS_COUNT,
+} WATERMARKS_FLAGS_e;
+
+typedef struct {
+ // Watermarks
+ WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES];
+} Watermarks_t;
+
+typedef struct {
+ Watermarks_t Watermarks;
+
+ uint32_t MmHubPadding[8]; // SMU internal use
+} WatermarksExternal_t;
+
+// Table types
+#define TABLE_PPTABLE 0
+#define TABLE_WATERMARKS 1
+#define TABLE_AVFS_PSM_DEBUG 2
+#define TABLE_AVFS_FUSE_OVERRIDE 3
+#define TABLE_PMSTATUSLOG 4
+#define TABLE_SMU_METRICS 5
+#define TABLE_DRIVER_SMU_CONFIG 6
+#define TABLE_ACTIVITY_MONITOR_COEFF 7
+#define TABLE_OVERDRIVE 8
+#define TABLE_I2C_COMMANDS 9
+#define TABLE_PACE 10
+#define TABLE_ECCINFO 11
+#define TABLE_COUNT 12
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c
index d9920d91838d..1cae01a91a69 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/dcn301_smu.c
@@ -94,6 +94,8 @@ static int dcn301_smu_send_msg_with_param(struct clk_mgr_internal *clk_mgr,
{
uint32_t result;
+ result = dcn301_smu_wait_for_response(clk_mgr, 10, 200000);
+
/* First clear response register */
REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
index bc4ddc36fe58..f310b0d25a07 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn301/vg_clk_mgr.c
@@ -176,8 +176,7 @@ static void vg_update_clocks(struct clk_mgr *clk_mgr_base,
if (update_dppclk || update_dispclk)
dcn301_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
// always update dtos unless clock is lowered and not safe to lower
- if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz)
- dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
+ dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
index 9d17c5a5ae01..bca5f01da763 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.c
@@ -139,9 +139,9 @@ void dcn31_update_clocks(struct clk_mgr *clk_mgr_base,
* also if safe to lower is false, we just go in the higher state
*/
if (safe_to_lower) {
- if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_ALLOW &&
+ if (new_clocks->zstate_support != DCN_ZSTATE_SUPPORT_DISALLOW &&
new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
- dcn31_smu_set_Z9_support(clk_mgr, true);
+ dcn31_smu_set_zstate_support(clk_mgr, new_clocks->zstate_support);
dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, true);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
@@ -167,7 +167,7 @@ void dcn31_update_clocks(struct clk_mgr *clk_mgr_base,
} else {
if (new_clocks->zstate_support == DCN_ZSTATE_SUPPORT_DISALLOW &&
new_clocks->zstate_support != clk_mgr_base->clks.zstate_support) {
- dcn31_smu_set_Z9_support(clk_mgr, false);
+ dcn31_smu_set_zstate_support(clk_mgr, DCN_ZSTATE_SUPPORT_DISALLOW);
dm_helpers_enable_periodic_detection(clk_mgr_base->ctx, false);
clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
}
@@ -287,8 +287,11 @@ static void dcn31_enable_pme_wa(struct clk_mgr *clk_mgr_base)
void dcn31_init_clocks(struct clk_mgr *clk_mgr)
{
+ uint32_t ref_dtbclk = clk_mgr->clks.ref_dtbclk_khz;
+
memset(&(clk_mgr->clks), 0, sizeof(struct dc_clocks));
// Assumption is that boot state always supports pstate
+ clk_mgr->clks.ref_dtbclk_khz = ref_dtbclk; // restore ref_dtbclk
clk_mgr->clks.p_state_change_support = true;
clk_mgr->clks.prev_p_state_change_support = true;
clk_mgr->clks.pwr_state = DCN_PWR_STATE_UNKNOWN;
@@ -615,13 +618,43 @@ static void dcn31_clk_mgr_helper_populate_bw_params(struct clk_mgr_internal *clk
}
}
+static void dcn31_set_low_power_state(struct clk_mgr *clk_mgr_base)
+{
+ int display_count;
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct dc *dc = clk_mgr_base->ctx->dc;
+ struct dc_state *context = dc->current_state;
+
+ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
+ display_count = dcn31_get_active_display_cnt_wa(dc, context);
+ /* if we can go lower, go lower */
+ if (display_count == 0) {
+ union display_idle_optimization_u idle_info = { 0 };
+
+ idle_info.idle_info.df_request_disabled = 1;
+ idle_info.idle_info.phy_ref_clk_off = 1;
+ idle_info.idle_info.s0i2_rdy = 1;
+ dcn31_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
+ /* update power state */
+ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
+ }
+ }
+}
+
+int dcn31_get_dtb_ref_freq_khz(struct clk_mgr *clk_mgr_base)
+{
+ return clk_mgr_base->clks.ref_dtbclk_khz;
+}
+
static struct clk_mgr_funcs dcn31_funcs = {
.get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
.update_clocks = dcn31_update_clocks,
.init_clocks = dcn31_init_clocks,
.enable_pme_wa = dcn31_enable_pme_wa,
.are_clock_states_equal = dcn31_are_clock_states_equal,
- .notify_wm_ranges = dcn31_notify_wm_ranges
+ .notify_wm_ranges = dcn31_notify_wm_ranges,
+ .set_low_power_state = dcn31_set_low_power_state
};
extern struct clk_mgr_funcs dcn3_fpga_funcs;
@@ -695,8 +728,10 @@ void dcn31_clk_mgr_construct(
}
clk_mgr->base.base.dprefclk_khz = 600000;
- clk_mgr->base.dccg->ref_dtbclk_khz = 600000;
+ clk_mgr->base.base.clks.ref_dtbclk_khz = 600000;
dce_clock_read_ss_info(&clk_mgr->base);
+ /*if bios enabled SS, driver needs to adjust dtb clock, only enable with correct bios*/
+ //clk_mgr->base.dccg->ref_dtbclk_khz = dce_adjust_dp_ref_freq_for_ss(clk_mgr_internal, clk_mgr->base.base.dprefclk_khz);
clk_mgr->base.base.bw_params = &dcn31_bw_params;
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.h
index 961b10a49486..be06fdbd0c22 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_clk_mgr.h
@@ -51,6 +51,8 @@ void dcn31_clk_mgr_construct(struct dc_context *ctx,
struct pp_smu_funcs *pp_smu,
struct dccg *dccg);
+int dcn31_get_dtb_ref_freq_khz(struct clk_mgr *clk_mgr_base);
+
void dcn31_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int);
#endif //__DCN31_CLK_MGR_H__
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
index de3f4643eeef..c5d7d075026f 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.c
@@ -310,23 +310,32 @@ void dcn31_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
}
-void dcn31_smu_set_Z9_support(struct clk_mgr_internal *clk_mgr, bool support)
+void dcn31_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support)
{
- //TODO: Work with smu team to define optimization options.
- unsigned int msg_id;
+ unsigned int msg_id, param;
if (!clk_mgr->smu_present)
return;
- if (support)
- msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
+ if (!clk_mgr->base.ctx->dc->debug.enable_z9_disable_interface &&
+ (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY))
+ support = DCN_ZSTATE_SUPPORT_DISALLOW;
+
+
+ if (support == DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY)
+ param = 1;
else
+ param = 0;
+
+ if (support == DCN_ZSTATE_SUPPORT_DISALLOW)
msg_id = VBIOSSMC_MSG_DisallowZstatesEntry;
+ else
+ msg_id = VBIOSSMC_MSG_AllowZstatesEntry;
dcn31_smu_send_msg_with_param(
clk_mgr,
msg_id,
- 0);
+ param);
}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.h
index cd0b7e1e685f..dfa25a76a6d1 100644
--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.h
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn31/dcn31_smu.h
@@ -265,7 +265,7 @@ void dcn31_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr
void dcn31_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr);
void dcn31_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr);
-void dcn31_smu_set_Z9_support(struct clk_mgr_internal *clk_mgr, bool support);
+void dcn31_smu_set_zstate_support(struct clk_mgr_internal *clk_mgr, enum dcn_zstate_support_state support);
void dcn31_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable);
#endif /* DAL_DC_31_SMU_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
new file mode 100644
index 000000000000..f4381725b210
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.c
@@ -0,0 +1,687 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "dccg.h"
+#include "clk_mgr_internal.h"
+
+// For dce12_get_dp_ref_freq_khz
+#include "dce100/dce_clk_mgr.h"
+// For dcn20_update_clocks_update_dpp_dto
+#include "dcn20/dcn20_clk_mgr.h"
+#include "dcn31/dcn31_clk_mgr.h"
+#include "dcn315_clk_mgr.h"
+
+#include "core_types.h"
+#include "dcn315_smu.h"
+#include "dm_helpers.h"
+
+#include "dc_dmub_srv.h"
+
+#include "dc_link_dp.h"
+
+#define TO_CLK_MGR_DCN315(clk_mgr)\
+ container_of(clk_mgr, struct clk_mgr_dcn315, base)
+
+static int dcn315_get_active_display_cnt_wa(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ int i, display_count;
+ bool tmds_present = false;
+
+ display_count = 0;
+ for (i = 0; i < context->stream_count; i++) {
+ const struct dc_stream_state *stream = context->streams[i];
+
+ if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+ stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
+ stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
+ tmds_present = true;
+ }
+
+ for (i = 0; i < dc->link_count; i++) {
+ const struct dc_link *link = dc->links[i];
+
+ /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
+ if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
+ link->link_enc->funcs->is_dig_enabled(link->link_enc))
+ display_count++;
+ }
+
+ /* WA for hang on HDMI after display off back back on*/
+ if (display_count == 0 && tmds_present)
+ display_count = 1;
+
+ return display_count;
+}
+
+static void dcn315_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
+{
+ struct dc *dc = clk_mgr_base->ctx->dc;
+ int i;
+
+ for (i = 0; i < dc->res_pool->pipe_count; ++i) {
+ struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+ if (pipe->top_pipe || pipe->prev_odm_pipe)
+ continue;
+ if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
+ dc_is_virtual_signal(pipe->stream->signal))) {
+ if (disable)
+ pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
+ else
+ pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
+ }
+ }
+}
+
+static void dcn315_update_clocks(struct clk_mgr *clk_mgr_base,
+ struct dc_state *context,
+ bool safe_to_lower)
+{
+ union dmub_rb_cmd cmd;
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
+ struct dc *dc = clk_mgr_base->ctx->dc;
+ int display_count;
+ bool update_dppclk = false;
+ bool update_dispclk = false;
+ bool dpp_clock_lowered = false;
+
+ if (dc->work_arounds.skip_clock_update)
+ return;
+
+ clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
+ /*
+ * if it is safe to lower, but we are already in the lower state, we don't have to do anything
+ * also if safe to lower is false, we just go in the higher state
+ */
+ clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
+ if (safe_to_lower) {
+ /* check that we're not already in lower */
+ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
+ display_count = dcn315_get_active_display_cnt_wa(dc, context);
+ /* if we can go lower, go lower */
+ if (display_count == 0) {
+ union display_idle_optimization_u idle_info = { 0 };
+ idle_info.idle_info.df_request_disabled = 1;
+ idle_info.idle_info.phy_ref_clk_off = 1;
+ idle_info.idle_info.s0i2_rdy = 1;
+ dcn315_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
+ /* update power state */
+ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
+ }
+ }
+ } else {
+ /* check that we're not already in D0 */
+ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) {
+ union display_idle_optimization_u idle_info = { 0 };
+ dcn315_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
+ /* update power state */
+ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE;
+ }
+ }
+
+ if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
+ clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
+ dcn315_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz);
+ }
+
+ if (should_set_clock(safe_to_lower,
+ new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
+ clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
+ dcn315_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
+ }
+
+ // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
+ if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
+ if (new_clocks->dppclk_khz < 100000)
+ new_clocks->dppclk_khz = 100000;
+ if (new_clocks->dispclk_khz < 100000)
+ new_clocks->dispclk_khz = 100000;
+ }
+
+ if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
+ if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
+ dpp_clock_lowered = true;
+ clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
+ update_dppclk = true;
+ }
+
+ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
+ dcn315_disable_otg_wa(clk_mgr_base, true);
+
+ clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
+ dcn315_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
+ dcn315_disable_otg_wa(clk_mgr_base, false);
+
+ update_dispclk = true;
+ }
+
+ if (dpp_clock_lowered) {
+ // increase per DPP DTO before lowering global dppclk
+ dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
+ dcn315_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
+ } else {
+ // increase global DPPCLK before lowering per DPP DTO
+ if (update_dppclk || update_dispclk)
+ dcn315_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
+ // always update dtos unless clock is lowered and not safe to lower
+ if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz)
+ dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
+ }
+
+ // notify DMCUB of latest clocks
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR;
+ cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS;
+ cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz;
+ cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz =
+ clk_mgr_base->clks.dcfclk_deep_sleep_khz;
+ cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz;
+ cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz;
+
+ dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
+ dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
+ dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
+}
+
+static void dcn315_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
+ struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
+{
+ return;
+}
+
+static struct clk_bw_params dcn315_bw_params = {
+ .vram_type = Ddr4MemType,
+ .num_channels = 2,
+ .clk_table = {
+ .entries = {
+ {
+ .voltage = 0,
+ .dispclk_mhz = 640,
+ .dppclk_mhz = 640,
+ .phyclk_mhz = 810,
+ .phyclk_d18_mhz = 667,
+ .dtbclk_mhz = 600,
+ },
+ {
+ .voltage = 1,
+ .dispclk_mhz = 739,
+ .dppclk_mhz = 739,
+ .phyclk_mhz = 810,
+ .phyclk_d18_mhz = 667,
+ .dtbclk_mhz = 600,
+ },
+ {
+ .voltage = 2,
+ .dispclk_mhz = 960,
+ .dppclk_mhz = 960,
+ .phyclk_mhz = 810,
+ .phyclk_d18_mhz = 667,
+ .dtbclk_mhz = 600,
+ },
+ {
+ .voltage = 3,
+ .dispclk_mhz = 1200,
+ .dppclk_mhz = 1200,
+ .phyclk_mhz = 810,
+ .phyclk_d18_mhz = 667,
+ .dtbclk_mhz = 600,
+ },
+ {
+ .voltage = 4,
+ .dispclk_mhz = 1372,
+ .dppclk_mhz = 1372,
+ .phyclk_mhz = 810,
+ .phyclk_d18_mhz = 667,
+ .dtbclk_mhz = 600,
+ },
+ },
+ .num_entries = 5,
+ },
+
+};
+
+static struct wm_table ddr5_wm_table = {
+ .entries = {
+ {
+ .wm_inst = WM_A,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 64.0,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_B,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 64.0,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_C,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 64.0,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_D,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 64.0,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ }
+};
+
+static struct wm_table lpddr5_wm_table = {
+ .entries = {
+ {
+ .wm_inst = WM_A,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.65333,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_B,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.65333,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_C,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.65333,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_D,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.65333,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ }
+};
+
+/* Temporary Place holder until we can get them from fuse */
+static DpmClocks_315_t dummy_clocks = { 0 };
+static struct dcn315_watermarks dummy_wms = { 0 };
+
+static void dcn315_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn315_watermarks *table)
+{
+ int i, num_valid_sets;
+
+ num_valid_sets = 0;
+
+ for (i = 0; i < WM_SET_COUNT; i++) {
+ /* skip empty entries, the smu array has no holes*/
+ if (!bw_params->wm_table.entries[i].valid)
+ continue;
+
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type;
+ /* We will not select WM based on fclk, so leave it as unconstrained */
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
+
+ if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) {
+ if (i == 0)
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0;
+ else {
+ /* add 1 to make it non-overlapping with next lvl */
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk =
+ bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1;
+ }
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk =
+ bw_params->clk_table.entries[i].dcfclk_mhz;
+
+ } else {
+ /* unconstrained for memory retraining */
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
+
+ /* Modify previous watermark range to cover up to max */
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
+ }
+ num_valid_sets++;
+ }
+
+ ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */
+
+ /* modify the min and max to make sure we cover the whole range*/
+ table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0;
+ table->WatermarkRow[WM_DCFCLK][0].MinClock = 0;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
+
+ /* This is for writeback only, does not matter currently as no writeback support*/
+ table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A;
+ table->WatermarkRow[WM_SOCCLK][0].MinClock = 0;
+ table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF;
+ table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0;
+ table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF;
+}
+
+static void dcn315_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
+{
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct clk_mgr_dcn315 *clk_mgr_dcn315 = TO_CLK_MGR_DCN315(clk_mgr);
+ struct dcn315_watermarks *table = clk_mgr_dcn315->smu_wm_set.wm_set;
+
+ if (!clk_mgr->smu_ver)
+ return;
+
+ if (!table || clk_mgr_dcn315->smu_wm_set.mc_address.quad_part == 0)
+ return;
+
+ memset(table, 0, sizeof(*table));
+
+ dcn315_build_watermark_ranges(clk_mgr_base->bw_params, table);
+
+ dcn315_smu_set_dram_addr_high(clk_mgr,
+ clk_mgr_dcn315->smu_wm_set.mc_address.high_part);
+ dcn315_smu_set_dram_addr_low(clk_mgr,
+ clk_mgr_dcn315->smu_wm_set.mc_address.low_part);
+ dcn315_smu_transfer_wm_table_dram_2_smu(clk_mgr);
+}
+
+static void dcn315_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
+ struct dcn315_smu_dpm_clks *smu_dpm_clks)
+{
+ DpmClocks_315_t *table = smu_dpm_clks->dpm_clks;
+
+ if (!clk_mgr->smu_ver)
+ return;
+
+ if (!table || smu_dpm_clks->mc_address.quad_part == 0)
+ return;
+
+ memset(table, 0, sizeof(*table));
+
+ dcn315_smu_set_dram_addr_high(clk_mgr,
+ smu_dpm_clks->mc_address.high_part);
+ dcn315_smu_set_dram_addr_low(clk_mgr,
+ smu_dpm_clks->mc_address.low_part);
+ dcn315_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
+}
+
+static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks)
+{
+ uint32_t max = 0;
+ int i;
+
+ for (i = 0; i < num_clocks; ++i) {
+ if (clocks[i] > max)
+ max = clocks[i];
+ }
+
+ return max;
+}
+
+static void dcn315_clk_mgr_helper_populate_bw_params(
+ struct clk_mgr_internal *clk_mgr,
+ struct integrated_info *bios_info,
+ const DpmClocks_315_t *clock_table)
+{
+ int i;
+ struct clk_bw_params *bw_params = clk_mgr->base.bw_params;
+ uint32_t max_pstate = 0, max_fclk = 0, min_pstate = 0;
+ struct clk_limit_table_entry def_max = bw_params->clk_table.entries[bw_params->clk_table.num_entries - 1];
+
+ /* Find highest fclk pstate */
+ for (i = 0; i < clock_table->NumDfPstatesEnabled; i++) {
+ if (clock_table->DfPstateTable[i].FClk > max_fclk) {
+ max_fclk = clock_table->DfPstateTable[i].FClk;
+ max_pstate = i;
+ }
+ }
+
+ /* For 315 we want to base clock table on dcfclk, need at least one entry regardless of pmfw table */
+ for (i = 0; i < clock_table->NumDcfClkLevelsEnabled; i++) {
+ int j;
+ uint32_t min_fclk = clock_table->DfPstateTable[0].FClk;
+
+ for (j = 1; j < clock_table->NumDfPstatesEnabled; j++) {
+ if (clock_table->DfPstateTable[j].Voltage <= clock_table->SocVoltage[i]
+ && clock_table->DfPstateTable[j].FClk < min_fclk) {
+ min_fclk = clock_table->DfPstateTable[j].FClk;
+ min_pstate = j;
+ }
+ }
+
+ /* First search defaults for the clocks we don't read using closest lower or equal default dcfclk */
+ for (j = bw_params->clk_table.num_entries - 1; j > 0; j--)
+ if (bw_params->clk_table.entries[j].dcfclk_mhz <= clock_table->DcfClocks[i])
+ break;
+ bw_params->clk_table.entries[i].phyclk_mhz = bw_params->clk_table.entries[j].phyclk_mhz;
+ bw_params->clk_table.entries[i].phyclk_d18_mhz = bw_params->clk_table.entries[j].phyclk_d18_mhz;
+ bw_params->clk_table.entries[i].dtbclk_mhz = bw_params->clk_table.entries[j].dtbclk_mhz;
+
+ /* Now update clocks we do read */
+ bw_params->clk_table.entries[i].fclk_mhz = min_fclk;
+ bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[min_pstate].MemClk;
+ bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[min_pstate].Voltage;
+ bw_params->clk_table.entries[i].dcfclk_mhz = clock_table->DcfClocks[i];
+ bw_params->clk_table.entries[i].socclk_mhz = clock_table->SocClocks[i];
+ bw_params->clk_table.entries[i].dispclk_mhz = clock_table->DispClocks[i];
+ bw_params->clk_table.entries[i].dppclk_mhz = clock_table->DppClocks[i];
+ bw_params->clk_table.entries[i].wck_ratio = 1;
+ };
+
+ /* Make sure to include at least one entry and highest pstate */
+ if (max_pstate != min_pstate || i == 0) {
+ bw_params->clk_table.entries[i].fclk_mhz = max_fclk;
+ bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[max_pstate].MemClk;
+ bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[max_pstate].Voltage;
+ bw_params->clk_table.entries[i].dcfclk_mhz = find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS);
+ bw_params->clk_table.entries[i].wck_ratio = 1;
+ i++;
+ }
+ bw_params->clk_table.num_entries = i--;
+
+ /* Make sure all highest clocks are included*/
+ bw_params->clk_table.entries[i].socclk_mhz = find_max_clk_value(clock_table->SocClocks, NUM_SOCCLK_DPM_LEVELS);
+ bw_params->clk_table.entries[i].dispclk_mhz = find_max_clk_value(clock_table->DispClocks, NUM_DISPCLK_DPM_LEVELS);
+ bw_params->clk_table.entries[i].dppclk_mhz = find_max_clk_value(clock_table->DppClocks, NUM_DPPCLK_DPM_LEVELS);
+ ASSERT(clock_table->DcfClocks[i] == find_max_clk_value(clock_table->DcfClocks, NUM_DCFCLK_DPM_LEVELS));
+ bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
+ bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
+ bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
+
+ /* Set any 0 clocks to max default setting. Not an issue for
+ * power since we aren't doing switching in such case anyway
+ */
+ for (i = 0; i < bw_params->clk_table.num_entries; i++) {
+ if (!bw_params->clk_table.entries[i].fclk_mhz) {
+ bw_params->clk_table.entries[i].fclk_mhz = def_max.fclk_mhz;
+ bw_params->clk_table.entries[i].memclk_mhz = def_max.memclk_mhz;
+ bw_params->clk_table.entries[i].voltage = def_max.voltage;
+ }
+ if (!bw_params->clk_table.entries[i].dcfclk_mhz)
+ bw_params->clk_table.entries[i].dcfclk_mhz = def_max.dcfclk_mhz;
+ if (!bw_params->clk_table.entries[i].socclk_mhz)
+ bw_params->clk_table.entries[i].socclk_mhz = def_max.socclk_mhz;
+ if (!bw_params->clk_table.entries[i].dispclk_mhz)
+ bw_params->clk_table.entries[i].dispclk_mhz = def_max.dispclk_mhz;
+ if (!bw_params->clk_table.entries[i].dppclk_mhz)
+ bw_params->clk_table.entries[i].dppclk_mhz = def_max.dppclk_mhz;
+ if (!bw_params->clk_table.entries[i].phyclk_mhz)
+ bw_params->clk_table.entries[i].phyclk_mhz = def_max.phyclk_mhz;
+ if (!bw_params->clk_table.entries[i].phyclk_d18_mhz)
+ bw_params->clk_table.entries[i].phyclk_d18_mhz = def_max.phyclk_d18_mhz;
+ if (!bw_params->clk_table.entries[i].dtbclk_mhz)
+ bw_params->clk_table.entries[i].dtbclk_mhz = def_max.dtbclk_mhz;
+ }
+ ASSERT(bw_params->clk_table.entries[i-1].dcfclk_mhz);
+ bw_params->vram_type = bios_info->memory_type;
+ bw_params->num_channels = bios_info->ma_channel_number;
+ if (!bw_params->num_channels)
+ bw_params->num_channels = 2;
+
+ for (i = 0; i < WM_SET_COUNT; i++) {
+ bw_params->wm_table.entries[i].wm_inst = i;
+
+ if (i >= bw_params->clk_table.num_entries) {
+ bw_params->wm_table.entries[i].valid = false;
+ continue;
+ }
+
+ bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG;
+ bw_params->wm_table.entries[i].valid = true;
+ }
+}
+
+static void dcn315_enable_pme_wa(struct clk_mgr *clk_mgr_base)
+{
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+
+ dcn315_smu_enable_pme_wa(clk_mgr);
+}
+
+static struct clk_mgr_funcs dcn315_funcs = {
+ .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
+ .update_clocks = dcn315_update_clocks,
+ .init_clocks = dcn31_init_clocks,
+ .enable_pme_wa = dcn315_enable_pme_wa,
+ .are_clock_states_equal = dcn31_are_clock_states_equal,
+ .notify_wm_ranges = dcn315_notify_wm_ranges
+};
+extern struct clk_mgr_funcs dcn3_fpga_funcs;
+
+void dcn315_clk_mgr_construct(
+ struct dc_context *ctx,
+ struct clk_mgr_dcn315 *clk_mgr,
+ struct pp_smu_funcs *pp_smu,
+ struct dccg *dccg)
+{
+ struct dcn315_smu_dpm_clks smu_dpm_clks = { 0 };
+
+ clk_mgr->base.base.ctx = ctx;
+ clk_mgr->base.base.funcs = &dcn315_funcs;
+
+ clk_mgr->base.pp_smu = pp_smu;
+
+ clk_mgr->base.dccg = dccg;
+ clk_mgr->base.dfs_bypass_disp_clk = 0;
+
+ clk_mgr->base.dprefclk_ss_percentage = 0;
+ clk_mgr->base.dprefclk_ss_divider = 1000;
+ clk_mgr->base.ss_on_dprefclk = false;
+ clk_mgr->base.dfs_ref_freq_khz = 48000;
+
+ clk_mgr->smu_wm_set.wm_set = (struct dcn315_watermarks *)dm_helpers_allocate_gpu_mem(
+ clk_mgr->base.base.ctx,
+ DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
+ sizeof(struct dcn315_watermarks),
+ &clk_mgr->smu_wm_set.mc_address.quad_part);
+
+ if (!clk_mgr->smu_wm_set.wm_set) {
+ clk_mgr->smu_wm_set.wm_set = &dummy_wms;
+ clk_mgr->smu_wm_set.mc_address.quad_part = 0;
+ }
+ ASSERT(clk_mgr->smu_wm_set.wm_set);
+
+ smu_dpm_clks.dpm_clks = (DpmClocks_315_t *)dm_helpers_allocate_gpu_mem(
+ clk_mgr->base.base.ctx,
+ DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
+ sizeof(DpmClocks_315_t),
+ &smu_dpm_clks.mc_address.quad_part);
+
+ if (smu_dpm_clks.dpm_clks == NULL) {
+ smu_dpm_clks.dpm_clks = &dummy_clocks;
+ smu_dpm_clks.mc_address.quad_part = 0;
+ }
+
+ ASSERT(smu_dpm_clks.dpm_clks);
+
+ if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) {
+ clk_mgr->base.base.funcs = &dcn3_fpga_funcs;
+ } else {
+ struct clk_log_info log_info = {0};
+
+ clk_mgr->base.smu_ver = dcn315_smu_get_smu_version(&clk_mgr->base);
+
+ if (clk_mgr->base.smu_ver > 0)
+ clk_mgr->base.smu_present = true;
+
+ if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
+ dcn315_bw_params.wm_table = lpddr5_wm_table;
+ } else {
+ dcn315_bw_params.wm_table = ddr5_wm_table;
+ }
+ /* Saved clocks configured at boot for debug purposes */
+ dcn315_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);
+
+ }
+
+ clk_mgr->base.base.dprefclk_khz = 600000;
+ clk_mgr->base.base.dprefclk_khz = dcn315_smu_get_dpref_clk(&clk_mgr->base);
+ clk_mgr->base.base.clks.ref_dtbclk_khz = clk_mgr->base.base.dprefclk_khz;
+ dce_clock_read_ss_info(&clk_mgr->base);
+ clk_mgr->base.base.clks.ref_dtbclk_khz = dce_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz);
+
+ clk_mgr->base.base.bw_params = &dcn315_bw_params;
+
+ if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
+ dcn315_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks);
+
+ if (ctx->dc_bios && ctx->dc_bios->integrated_info) {
+ dcn315_clk_mgr_helper_populate_bw_params(
+ &clk_mgr->base,
+ ctx->dc_bios->integrated_info,
+ smu_dpm_clks.dpm_clks);
+ }
+ }
+
+ if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0)
+ dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
+ smu_dpm_clks.dpm_clks);
+}
+
+void dcn315_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int)
+{
+ struct clk_mgr_dcn315 *clk_mgr = TO_CLK_MGR_DCN315(clk_mgr_int);
+
+ if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0)
+ dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
+ clk_mgr->smu_wm_set.wm_set);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.h
new file mode 100644
index 000000000000..ac36ddf5dd1a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_clk_mgr.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN315_CLK_MGR_H__
+#define __DCN315_CLK_MGR_H__
+#include "clk_mgr_internal.h"
+
+struct dcn315_watermarks;
+
+struct dcn315_smu_watermark_set {
+ struct dcn315_watermarks *wm_set;
+ union large_integer mc_address;
+};
+
+struct clk_mgr_dcn315 {
+ struct clk_mgr_internal base;
+ struct dcn315_smu_watermark_set smu_wm_set;
+};
+
+void dcn315_clk_mgr_construct(struct dc_context *ctx,
+ struct clk_mgr_dcn315 *clk_mgr,
+ struct pp_smu_funcs *pp_smu,
+ struct dccg *dccg);
+
+void dcn315_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int);
+
+#endif //__DCN315_CLK_MGR_H__
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c
new file mode 100644
index 000000000000..2600313fea57
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.c
@@ -0,0 +1,349 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "core_types.h"
+#include "clk_mgr_internal.h"
+#include "reg_helper.h"
+#include "dm_helpers.h"
+#include "dcn315_smu.h"
+#include "mp/mp_13_0_5_offset.h"
+
+#define MAX_INSTANCE 6
+#define MAX_SEGMENT 6
+
+struct IP_BASE_INSTANCE
+{
+ unsigned int segment[MAX_SEGMENT];
+};
+
+struct IP_BASE
+{
+ struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
+};
+
+static const struct IP_BASE MP0_BASE = { { { { 0x00016000, 0x00DC0000, 0x00E00000, 0x00E40000, 0x0243FC00, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } } } };
+static const struct IP_BASE NBIO_BASE = { { { { 0x00000000, 0x00000014, 0x00000D20, 0x00010400, 0x0241B000, 0x04040000 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } } } };
+
+#define regBIF_BX_PF2_RSMU_INDEX 0x0000
+#define regBIF_BX_PF2_RSMU_INDEX_BASE_IDX 1
+#define regBIF_BX_PF2_RSMU_DATA 0x0001
+#define regBIF_BX_PF2_RSMU_DATA_BASE_IDX 1
+
+#define REG(reg_name) \
+ (MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
+
+#define FN(reg_name, field) \
+ FD(reg_name##__##field)
+
+#define REG_NBIO(reg_name) \
+ (NBIO_BASE.instance[0].segment[regBIF_BX_PF2_ ## reg_name ## _BASE_IDX] + regBIF_BX_PF2_ ## reg_name)
+
+#define mmMP1_C2PMSG_3 0x3B1050C
+
+#define VBIOSSMC_MSG_TestMessage 0x01 ///< To check if PMFW is alive and responding. Requirement specified by PMFW team
+#define VBIOSSMC_MSG_GetPmfwVersion 0x02 ///< Get PMFW version
+#define VBIOSSMC_MSG_Spare0 0x03 ///< Spare0
+#define VBIOSSMC_MSG_SetDispclkFreq 0x04 ///< Set display clock frequency in MHZ
+#define VBIOSSMC_MSG_Spare1 0x05 ///< Spare1
+#define VBIOSSMC_MSG_SetDppclkFreq 0x06 ///< Set DPP clock frequency in MHZ
+#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x07 ///< Set DCF clock frequency hard min in MHZ
+#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x08 ///< Set DCF clock minimum frequency in deep sleep in MHZ
+#define VBIOSSMC_MSG_GetDtbclkFreq 0x09 ///< Get display dtb clock frequency in MHZ in case VMIN does not support phy frequency
+#define VBIOSSMC_MSG_SetDtbClk 0x0A ///< Set dtb clock frequency, return frequemcy in MHZ
+#define VBIOSSMC_MSG_SetDisplayCount 0x0B ///< Inform PMFW of number of display connected
+#define VBIOSSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0x0C ///< To ask PMFW turn off TMDP 48MHz refclk during display off to save power
+#define VBIOSSMC_MSG_UpdatePmeRestore 0x0D ///< To ask PMFW to write into Azalia for PME wake up event
+#define VBIOSSMC_MSG_SetVbiosDramAddrHigh 0x0E ///< Set DRAM address high 32 bits for WM table transfer
+#define VBIOSSMC_MSG_SetVbiosDramAddrLow 0x0F ///< Set DRAM address low 32 bits for WM table transfer
+#define VBIOSSMC_MSG_TransferTableSmu2Dram 0x10 ///< Transfer table from PMFW SRAM to system DRAM
+#define VBIOSSMC_MSG_TransferTableDram2Smu 0x11 ///< Transfer table from system DRAM to PMFW
+#define VBIOSSMC_MSG_SetDisplayIdleOptimizations 0x12 ///< Set Idle state optimization for display off
+#define VBIOSSMC_MSG_GetDprefclkFreq 0x13 ///< Get DPREF clock frequency. Return in MHZ
+#define VBIOSSMC_Message_Count 0x14 ///< Total number of VBIS and DAL messages
+
+#define VBIOSSMC_Status_BUSY 0x0
+#define VBIOSSMC_Result_OK 0x01 ///< Message Response OK
+#define VBIOSSMC_Result_Failed 0xFF ///< Message Response Failed
+#define VBIOSSMC_Result_UnknownCmd 0xFE ///< Message Response Unknown Command
+#define VBIOSSMC_Result_CmdRejectedPrereq 0xFD ///< Message Response Command Failed Prerequisite
+#define VBIOSSMC_Result_CmdRejectedBusy 0xFC ///< Message Response Command Rejected due to PMFW is busy. Sender should retry sending this message
+
+/*
+ * Function to be used instead of REG_WAIT macro because the wait ends when
+ * the register is NOT EQUAL to zero, and because the translation in msg_if.h
+ * won't work with REG_WAIT.
+ */
+static uint32_t dcn315_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
+{
+ uint32_t res_val = VBIOSSMC_Status_BUSY;
+
+ do {
+ res_val = REG_READ(MP1_SMN_C2PMSG_38);
+ if (res_val != VBIOSSMC_Status_BUSY)
+ break;
+
+ if (delay_us >= 1000)
+ msleep(delay_us/1000);
+ else if (delay_us > 0)
+ udelay(delay_us);
+ } while (max_retries--);
+
+ return res_val;
+}
+
+static int dcn315_smu_send_msg_with_param(
+ struct clk_mgr_internal *clk_mgr,
+ unsigned int msg_id, unsigned int param)
+{
+ uint32_t result;
+
+ result = dcn315_smu_wait_for_response(clk_mgr, 10, 200000);
+ ASSERT(result == VBIOSSMC_Result_OK);
+
+ if (result == VBIOSSMC_Status_BUSY) {
+ return -1;
+ }
+
+ /* First clear response register */
+ REG_WRITE(MP1_SMN_C2PMSG_38, VBIOSSMC_Status_BUSY);
+
+ /* Set the parameter register for the SMU message, unit is Mhz */
+ REG_WRITE(MP1_SMN_C2PMSG_37, param);
+
+ /* Trigger the message transaction by writing the message ID */
+ generic_write_indirect_reg(CTX,
+ REG_NBIO(RSMU_INDEX), REG_NBIO(RSMU_DATA),
+ mmMP1_C2PMSG_3, msg_id);
+
+ result = dcn315_smu_wait_for_response(clk_mgr, 10, 200000);
+
+ if (result == VBIOSSMC_Status_BUSY) {
+ ASSERT(0);
+ dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
+ }
+
+ return REG_READ(MP1_SMN_C2PMSG_37);
+}
+
+int dcn315_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
+{
+ return dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_GetPmfwVersion,
+ 0);
+}
+
+
+int dcn315_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
+{
+ int actual_dispclk_set_mhz = -1;
+
+ if (!clk_mgr->smu_present)
+ return requested_dispclk_khz;
+
+ /* Unit of SMU msg parameter is Mhz */
+ actual_dispclk_set_mhz = dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDispclkFreq,
+ khz_to_mhz_ceil(requested_dispclk_khz));
+
+ return actual_dispclk_set_mhz * 1000;
+}
+
+int dcn315_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
+{
+ int actual_dcfclk_set_mhz = -1;
+
+ if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
+ return -1;
+
+ if (!clk_mgr->smu_present)
+ return requested_dcfclk_khz;
+
+ actual_dcfclk_set_mhz = dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
+ khz_to_mhz_ceil(requested_dcfclk_khz));
+
+ return actual_dcfclk_set_mhz * 1000;
+}
+
+int dcn315_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
+{
+ int actual_min_ds_dcfclk_mhz = -1;
+
+ if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
+ return -1;
+
+ if (!clk_mgr->smu_present)
+ return requested_min_ds_dcfclk_khz;
+
+ actual_min_ds_dcfclk_mhz = dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
+ khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
+
+ return actual_min_ds_dcfclk_mhz * 1000;
+}
+
+int dcn315_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
+{
+ int actual_dppclk_set_mhz = -1;
+
+ if (!clk_mgr->smu_present)
+ return requested_dpp_khz;
+
+ actual_dppclk_set_mhz = dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDppclkFreq,
+ khz_to_mhz_ceil(requested_dpp_khz));
+
+ return actual_dppclk_set_mhz * 1000;
+}
+
+void dcn315_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
+{
+ if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
+ return;
+
+ if (!clk_mgr->smu_present)
+ return;
+
+ //TODO: Work with smu team to define optimization options.
+ dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDisplayIdleOptimizations,
+ idle_info);
+}
+
+void dcn315_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
+{
+ union display_idle_optimization_u idle_info = { 0 };
+
+ if (!clk_mgr->smu_present)
+ return;
+
+ if (enable) {
+ idle_info.idle_info.df_request_disabled = 1;
+ idle_info.idle_info.phy_ref_clk_off = 1;
+ }
+
+ dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDisplayIdleOptimizations,
+ idle_info.data);
+}
+
+void dcn315_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_UpdatePmeRestore,
+ 0);
+}
+void dcn315_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn315_smu_send_msg_with_param(clk_mgr,
+ VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
+}
+
+void dcn315_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn315_smu_send_msg_with_param(clk_mgr,
+ VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
+}
+
+void dcn315_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn315_smu_send_msg_with_param(clk_mgr,
+ VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
+}
+
+void dcn315_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn315_smu_send_msg_with_param(clk_mgr,
+ VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
+}
+
+int dcn315_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr)
+{
+ int dprefclk_get_mhz = -1;
+ if (clk_mgr->smu_present) {
+ dprefclk_get_mhz = dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_GetDprefclkFreq,
+ 0);
+ }
+ return (dprefclk_get_mhz * 1000);
+}
+
+int dcn315_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr)
+{
+ int fclk_get_mhz = -1;
+
+ if (clk_mgr->smu_present) {
+ fclk_get_mhz = dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_GetDtbclkFreq,
+ 0);
+ }
+ return (fclk_get_mhz * 1000);
+}
+
+void dcn315_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn315_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDtbClk,
+ enable);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.h
new file mode 100644
index 000000000000..5aa3275ac7d8
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn315/dcn315_smu.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef DAL_DC_315_SMU_H_
+#define DAL_DC_315_SMU_H_
+#include "os_types.h"
+
+#define PMFW_DRIVER_IF_VERSION 4
+
+#define NUM_DCFCLK_DPM_LEVELS 4
+#define NUM_DISPCLK_DPM_LEVELS 4
+#define NUM_DPPCLK_DPM_LEVELS 4
+#define NUM_SOCCLK_DPM_LEVELS 4
+#define NUM_VCN_DPM_LEVELS 4
+#define NUM_SOC_VOLTAGE_LEVELS 4
+#define NUM_DF_PSTATE_LEVELS 4
+
+
+typedef struct {
+ uint16_t MinClock; // This is either DCFCLK or SOCCLK (in MHz)
+ uint16_t MaxClock; // This is either DCFCLK or SOCCLK (in MHz)
+ uint16_t MinMclk;
+ uint16_t MaxMclk;
+ uint8_t WmSetting;
+ uint8_t WmType; // Used for normal pstate change or memory retraining
+ uint8_t Padding[2];
+} WatermarkRowGeneric_t;
+
+#define NUM_WM_RANGES 4
+#define WM_PSTATE_CHG 0
+#define WM_RETRAINING 1
+
+typedef enum {
+ WM_SOCCLK = 0,
+ WM_DCFCLK,
+ WM_COUNT,
+} WM_CLOCK_e;
+
+typedef struct {
+ uint32_t FClk;
+ uint32_t MemClk;
+ uint32_t Voltage;
+} DfPstateTable_t;
+
+//Freq in MHz
+//Voltage in milli volts with 2 fractional bits
+typedef struct {
+ uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS];
+ uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS];
+ uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS];
+ uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS];
+ uint32_t VClocks[NUM_VCN_DPM_LEVELS];
+ uint32_t DClocks[NUM_VCN_DPM_LEVELS];
+ uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS];
+ DfPstateTable_t DfPstateTable[NUM_DF_PSTATE_LEVELS];
+ uint8_t NumDcfClkLevelsEnabled;
+ uint8_t NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk
+ uint8_t NumSocClkLevelsEnabled;
+ uint8_t VcnClkLevelsEnabled; //Applies to both Vclk and Dclk
+ uint8_t NumDfPstatesEnabled;
+ uint8_t spare[3];
+ uint32_t MinGfxClk;
+ uint32_t MaxGfxClk;
+} DpmClocks_315_t;
+
+struct dcn315_watermarks {
+ // Watermarks
+ WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES];
+ uint32_t MmHubPadding[7]; // SMU internal use
+};
+
+struct dcn315_smu_dpm_clks {
+ DpmClocks_315_t *dpm_clks;
+ union large_integer mc_address;
+};
+
+#define TABLE_WATERMARKS 1 // Called by DAL through VBIOS
+#define TABLE_DPMCLOCKS 4 // Called by Driver and VBIOS
+
+struct display_idle_optimization {
+ unsigned int df_request_disabled : 1;
+ unsigned int phy_ref_clk_off : 1;
+ unsigned int s0i2_rdy : 1;
+ unsigned int reserved : 29;
+};
+
+union display_idle_optimization_u {
+ struct display_idle_optimization idle_info;
+ uint32_t data;
+};
+
+int dcn315_smu_get_smu_version(struct clk_mgr_internal *clk_mgr);
+int dcn315_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz);
+int dcn315_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz);
+int dcn315_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz);
+int dcn315_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz);
+void dcn315_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info);
+void dcn315_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable);
+void dcn315_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high);
+void dcn315_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low);
+void dcn315_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr);
+void dcn315_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr);
+void dcn315_smu_request_voltage_via_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz);
+void dcn315_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr);
+int dcn315_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr);
+int dcn315_smu_get_dtbclk(struct clk_mgr_internal *clk_mgr);
+void dcn315_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable);
+#endif /* DAL_DC_315_SMU_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
new file mode 100644
index 000000000000..e4bb9c6193b5
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.c
@@ -0,0 +1,719 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "dccg.h"
+#include "clk_mgr_internal.h"
+
+// For dce12_get_dp_ref_freq_khz
+#include "dce100/dce_clk_mgr.h"
+// For dcn20_update_clocks_update_dpp_dto
+#include "dcn20/dcn20_clk_mgr.h"
+#include "dcn31/dcn31_clk_mgr.h"
+#include "dcn316_clk_mgr.h"
+#include "reg_helper.h"
+#include "core_types.h"
+#include "dcn316_smu.h"
+#include "dm_helpers.h"
+#include "dc_dmub_srv.h"
+#include "dc_link_dp.h"
+
+// DCN316 this is CLK1 instance
+#define MAX_INSTANCE 7
+#define MAX_SEGMENT 6
+
+struct IP_BASE_INSTANCE
+{
+ unsigned int segment[MAX_SEGMENT];
+};
+
+struct IP_BASE
+{
+ struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
+};
+
+static const struct IP_BASE CLK_BASE = { { { { 0x00016C00, 0x02401800, 0, 0, 0, 0 } },
+ { { 0x00016E00, 0x02401C00, 0, 0, 0, 0 } },
+ { { 0x00017000, 0x02402000, 0, 0, 0, 0 } },
+ { { 0x00017200, 0x02402400, 0, 0, 0, 0 } },
+ { { 0x0001B000, 0x0242D800, 0, 0, 0, 0 } },
+ { { 0x0001B200, 0x0242DC00, 0, 0, 0, 0 } },
+ { { 0x0001B400, 0x0242E000, 0, 0, 0, 0 } } } };
+
+#define regCLK1_CLK_PLL_REQ 0x0237
+#define regCLK1_CLK_PLL_REQ_BASE_IDX 0
+
+#define CLK1_CLK_PLL_REQ__FbMult_int__SHIFT 0x0
+#define CLK1_CLK_PLL_REQ__PllSpineDiv__SHIFT 0xc
+#define CLK1_CLK_PLL_REQ__FbMult_frac__SHIFT 0x10
+#define CLK1_CLK_PLL_REQ__FbMult_int_MASK 0x000001FFL
+#define CLK1_CLK_PLL_REQ__PllSpineDiv_MASK 0x0000F000L
+#define CLK1_CLK_PLL_REQ__FbMult_frac_MASK 0xFFFF0000L
+
+#define REG(reg_name) \
+ (CLK_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
+
+#define TO_CLK_MGR_DCN316(clk_mgr)\
+ container_of(clk_mgr, struct clk_mgr_dcn316, base)
+
+static int dcn316_get_active_display_cnt_wa(
+ struct dc *dc,
+ struct dc_state *context)
+{
+ int i, display_count;
+ bool tmds_present = false;
+
+ display_count = 0;
+ for (i = 0; i < context->stream_count; i++) {
+ const struct dc_stream_state *stream = context->streams[i];
+
+ if (stream->signal == SIGNAL_TYPE_HDMI_TYPE_A ||
+ stream->signal == SIGNAL_TYPE_DVI_SINGLE_LINK ||
+ stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK)
+ tmds_present = true;
+ }
+
+ for (i = 0; i < dc->link_count; i++) {
+ const struct dc_link *link = dc->links[i];
+
+ /* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
+ if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
+ link->link_enc->funcs->is_dig_enabled(link->link_enc))
+ display_count++;
+ }
+
+ /* WA for hang on HDMI after display off back back on*/
+ if (display_count == 0 && tmds_present)
+ display_count = 1;
+
+ return display_count;
+}
+
+static void dcn316_disable_otg_wa(struct clk_mgr *clk_mgr_base, bool disable)
+{
+ struct dc *dc = clk_mgr_base->ctx->dc;
+ int i;
+
+ for (i = 0; i < dc->res_pool->pipe_count; ++i) {
+ struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+ if (pipe->top_pipe || pipe->prev_odm_pipe)
+ continue;
+ if (pipe->stream && (pipe->stream->dpms_off || pipe->plane_state == NULL ||
+ dc_is_virtual_signal(pipe->stream->signal))) {
+ if (disable)
+ pipe->stream_res.tg->funcs->immediate_disable_crtc(pipe->stream_res.tg);
+ else
+ pipe->stream_res.tg->funcs->enable_crtc(pipe->stream_res.tg);
+ }
+ }
+}
+
+static void dcn316_enable_pme_wa(struct clk_mgr *clk_mgr_base)
+{
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+
+ dcn316_smu_enable_pme_wa(clk_mgr);
+}
+
+static void dcn316_update_clocks(struct clk_mgr *clk_mgr_base,
+ struct dc_state *context,
+ bool safe_to_lower)
+{
+ union dmub_rb_cmd cmd;
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct dc_clocks *new_clocks = &context->bw_ctx.bw.dcn.clk;
+ struct dc *dc = clk_mgr_base->ctx->dc;
+ int display_count;
+ bool update_dppclk = false;
+ bool update_dispclk = false;
+ bool dpp_clock_lowered = false;
+
+ if (dc->work_arounds.skip_clock_update)
+ return;
+
+ /*
+ * if it is safe to lower, but we are already in the lower state, we don't have to do anything
+ * also if safe to lower is false, we just go in the higher state
+ */
+ clk_mgr_base->clks.zstate_support = new_clocks->zstate_support;
+ if (safe_to_lower) {
+ if (clk_mgr_base->clks.dtbclk_en && !new_clocks->dtbclk_en) {
+ dcn316_smu_set_dtbclk(clk_mgr, false);
+ clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
+ }
+ /* check that we're not already in lower */
+ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_LOW_POWER) {
+ display_count = dcn316_get_active_display_cnt_wa(dc, context);
+ /* if we can go lower, go lower */
+ if (display_count == 0) {
+ union display_idle_optimization_u idle_info = { 0 };
+ idle_info.idle_info.df_request_disabled = 1;
+ idle_info.idle_info.phy_ref_clk_off = 1;
+ idle_info.idle_info.s0i2_rdy = 1;
+ dcn316_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
+ /* update power state */
+ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_LOW_POWER;
+ }
+ }
+ } else {
+ if (!clk_mgr_base->clks.dtbclk_en && new_clocks->dtbclk_en) {
+ dcn316_smu_set_dtbclk(clk_mgr, true);
+ clk_mgr_base->clks.dtbclk_en = new_clocks->dtbclk_en;
+ }
+
+ /* check that we're not already in D0 */
+ if (clk_mgr_base->clks.pwr_state != DCN_PWR_STATE_MISSION_MODE) {
+ union display_idle_optimization_u idle_info = { 0 };
+ dcn316_smu_set_display_idle_optimization(clk_mgr, idle_info.data);
+ /* update power state */
+ clk_mgr_base->clks.pwr_state = DCN_PWR_STATE_MISSION_MODE;
+ }
+ }
+
+ if (should_set_clock(safe_to_lower, new_clocks->dcfclk_khz, clk_mgr_base->clks.dcfclk_khz)) {
+ clk_mgr_base->clks.dcfclk_khz = new_clocks->dcfclk_khz;
+ dcn316_smu_set_hard_min_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_khz);
+ }
+
+ if (should_set_clock(safe_to_lower,
+ new_clocks->dcfclk_deep_sleep_khz, clk_mgr_base->clks.dcfclk_deep_sleep_khz)) {
+ clk_mgr_base->clks.dcfclk_deep_sleep_khz = new_clocks->dcfclk_deep_sleep_khz;
+ dcn316_smu_set_min_deep_sleep_dcfclk(clk_mgr, clk_mgr_base->clks.dcfclk_deep_sleep_khz);
+ }
+
+ // workaround: Limit dppclk to 100Mhz to avoid lower eDP panel switch to plus 4K monitor underflow.
+ if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
+ if (new_clocks->dppclk_khz < 100000)
+ new_clocks->dppclk_khz = 100000;
+ if (new_clocks->dispclk_khz < 100000)
+ new_clocks->dispclk_khz = 100000;
+ }
+
+ if (should_set_clock(safe_to_lower, new_clocks->dppclk_khz, clk_mgr->base.clks.dppclk_khz)) {
+ if (clk_mgr->base.clks.dppclk_khz > new_clocks->dppclk_khz)
+ dpp_clock_lowered = true;
+ clk_mgr_base->clks.dppclk_khz = new_clocks->dppclk_khz;
+ update_dppclk = true;
+ }
+
+ if (should_set_clock(safe_to_lower, new_clocks->dispclk_khz, clk_mgr_base->clks.dispclk_khz)) {
+ dcn316_disable_otg_wa(clk_mgr_base, true);
+
+ clk_mgr_base->clks.dispclk_khz = new_clocks->dispclk_khz;
+ dcn316_smu_set_dispclk(clk_mgr, clk_mgr_base->clks.dispclk_khz);
+ dcn316_disable_otg_wa(clk_mgr_base, false);
+
+ update_dispclk = true;
+ }
+
+ if (dpp_clock_lowered) {
+ // increase per DPP DTO before lowering global dppclk
+ dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
+ dcn316_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
+ } else {
+ // increase global DPPCLK before lowering per DPP DTO
+ if (update_dppclk || update_dispclk)
+ dcn316_smu_set_dppclk(clk_mgr, clk_mgr_base->clks.dppclk_khz);
+ // always update dtos unless clock is lowered and not safe to lower
+ if (new_clocks->dppclk_khz >= dc->current_state->bw_ctx.bw.dcn.clk.dppclk_khz)
+ dcn20_update_clocks_update_dpp_dto(clk_mgr, context, safe_to_lower);
+ }
+
+ // notify DMCUB of latest clocks
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.notify_clocks.header.type = DMUB_CMD__CLK_MGR;
+ cmd.notify_clocks.header.sub_type = DMUB_CMD__CLK_MGR_NOTIFY_CLOCKS;
+ cmd.notify_clocks.clocks.dcfclk_khz = clk_mgr_base->clks.dcfclk_khz;
+ cmd.notify_clocks.clocks.dcfclk_deep_sleep_khz =
+ clk_mgr_base->clks.dcfclk_deep_sleep_khz;
+ cmd.notify_clocks.clocks.dispclk_khz = clk_mgr_base->clks.dispclk_khz;
+ cmd.notify_clocks.clocks.dppclk_khz = clk_mgr_base->clks.dppclk_khz;
+
+ dc_dmub_srv_cmd_queue(dc->ctx->dmub_srv, &cmd);
+ dc_dmub_srv_cmd_execute(dc->ctx->dmub_srv);
+ dc_dmub_srv_wait_idle(dc->ctx->dmub_srv);
+}
+
+static void dcn316_dump_clk_registers(struct clk_state_registers_and_bypass *regs_and_bypass,
+ struct clk_mgr *clk_mgr_base, struct clk_log_info *log_info)
+{
+ return;
+}
+
+static struct clk_bw_params dcn316_bw_params = {
+ .vram_type = Ddr4MemType,
+ .num_channels = 1,
+ .clk_table = {
+ .num_entries = 5,
+ },
+
+};
+
+static struct wm_table ddr4_wm_table = {
+ .entries = {
+ {
+ .wm_inst = WM_A,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.72,
+ .sr_exit_time_us = 6.09,
+ .sr_enter_plus_exit_time_us = 7.14,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_B,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.72,
+ .sr_exit_time_us = 10.12,
+ .sr_enter_plus_exit_time_us = 11.48,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_C,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.72,
+ .sr_exit_time_us = 10.12,
+ .sr_enter_plus_exit_time_us = 11.48,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_D,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.72,
+ .sr_exit_time_us = 10.12,
+ .sr_enter_plus_exit_time_us = 11.48,
+ .valid = true,
+ },
+ }
+};
+
+static struct wm_table lpddr5_wm_table = {
+ .entries = {
+ {
+ .wm_inst = WM_A,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.65333,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_B,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.65333,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_C,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.65333,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ {
+ .wm_inst = WM_D,
+ .wm_type = WM_TYPE_PSTATE_CHG,
+ .pstate_latency_us = 11.65333,
+ .sr_exit_time_us = 11.5,
+ .sr_enter_plus_exit_time_us = 14.5,
+ .valid = true,
+ },
+ }
+};
+
+static DpmClocks_316_t dummy_clocks;
+
+static struct dcn316_watermarks dummy_wms = { 0 };
+
+static void dcn316_build_watermark_ranges(struct clk_bw_params *bw_params, struct dcn316_watermarks *table)
+{
+ int i, num_valid_sets;
+
+ num_valid_sets = 0;
+
+ for (i = 0; i < WM_SET_COUNT; i++) {
+ /* skip empty entries, the smu array has no holes*/
+ if (!bw_params->wm_table.entries[i].valid)
+ continue;
+
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmSetting = bw_params->wm_table.entries[i].wm_inst;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType = bw_params->wm_table.entries[i].wm_type;
+ /* We will not select WM based on fclk, so leave it as unconstrained */
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
+
+ if (table->WatermarkRow[WM_DCFCLK][num_valid_sets].WmType == WM_TYPE_PSTATE_CHG) {
+ if (i == 0)
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk = 0;
+ else {
+ /* add 1 to make it non-overlapping with next lvl */
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinMclk =
+ bw_params->clk_table.entries[i - 1].dcfclk_mhz + 1;
+ }
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxMclk =
+ bw_params->clk_table.entries[i].dcfclk_mhz;
+
+ } else {
+ /* unconstrained for memory retraining */
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MinClock = 0;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets].MaxClock = 0xFFFF;
+
+ /* Modify previous watermark range to cover up to max */
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
+ }
+ num_valid_sets++;
+ }
+
+ ASSERT(num_valid_sets != 0); /* Must have at least one set of valid watermarks */
+
+ /* modify the min and max to make sure we cover the whole range*/
+ table->WatermarkRow[WM_DCFCLK][0].MinMclk = 0;
+ table->WatermarkRow[WM_DCFCLK][0].MinClock = 0;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxMclk = 0xFFFF;
+ table->WatermarkRow[WM_DCFCLK][num_valid_sets - 1].MaxClock = 0xFFFF;
+
+ /* This is for writeback only, does not matter currently as no writeback support*/
+ table->WatermarkRow[WM_SOCCLK][0].WmSetting = WM_A;
+ table->WatermarkRow[WM_SOCCLK][0].MinClock = 0;
+ table->WatermarkRow[WM_SOCCLK][0].MaxClock = 0xFFFF;
+ table->WatermarkRow[WM_SOCCLK][0].MinMclk = 0;
+ table->WatermarkRow[WM_SOCCLK][0].MaxMclk = 0xFFFF;
+}
+
+static void dcn316_notify_wm_ranges(struct clk_mgr *clk_mgr_base)
+{
+ struct clk_mgr_internal *clk_mgr = TO_CLK_MGR_INTERNAL(clk_mgr_base);
+ struct clk_mgr_dcn316 *clk_mgr_dcn316 = TO_CLK_MGR_DCN316(clk_mgr);
+ struct dcn316_watermarks *table = clk_mgr_dcn316->smu_wm_set.wm_set;
+
+ if (!clk_mgr->smu_ver)
+ return;
+
+ if (!table || clk_mgr_dcn316->smu_wm_set.mc_address.quad_part == 0)
+ return;
+
+ memset(table, 0, sizeof(*table));
+
+ dcn316_build_watermark_ranges(clk_mgr_base->bw_params, table);
+
+ dcn316_smu_set_dram_addr_high(clk_mgr,
+ clk_mgr_dcn316->smu_wm_set.mc_address.high_part);
+ dcn316_smu_set_dram_addr_low(clk_mgr,
+ clk_mgr_dcn316->smu_wm_set.mc_address.low_part);
+ dcn316_smu_transfer_wm_table_dram_2_smu(clk_mgr);
+}
+
+static void dcn316_get_dpm_table_from_smu(struct clk_mgr_internal *clk_mgr,
+ struct dcn316_smu_dpm_clks *smu_dpm_clks)
+{
+ DpmClocks_316_t *table = smu_dpm_clks->dpm_clks;
+
+ if (!clk_mgr->smu_ver)
+ return;
+
+ if (!table || smu_dpm_clks->mc_address.quad_part == 0)
+ return;
+
+ memset(table, 0, sizeof(*table));
+
+ dcn316_smu_set_dram_addr_high(clk_mgr,
+ smu_dpm_clks->mc_address.high_part);
+ dcn316_smu_set_dram_addr_low(clk_mgr,
+ smu_dpm_clks->mc_address.low_part);
+ dcn316_smu_transfer_dpm_table_smu_2_dram(clk_mgr);
+}
+
+static uint32_t find_max_clk_value(const uint32_t clocks[], uint32_t num_clocks)
+{
+ uint32_t max = 0;
+ int i;
+
+ for (i = 0; i < num_clocks; ++i) {
+ if (clocks[i] > max)
+ max = clocks[i];
+ }
+
+ return max;
+}
+
+static unsigned int find_clk_for_voltage(
+ const DpmClocks_316_t *clock_table,
+ const uint32_t clocks[],
+ unsigned int voltage)
+{
+ int i;
+ int max_voltage = 0;
+ int clock = 0;
+
+ for (i = 0; i < NUM_SOC_VOLTAGE_LEVELS; i++) {
+ if (clock_table->SocVoltage[i] == voltage) {
+ return clocks[i];
+ } else if (clock_table->SocVoltage[i] >= max_voltage &&
+ clock_table->SocVoltage[i] < voltage) {
+ max_voltage = clock_table->SocVoltage[i];
+ clock = clocks[i];
+ }
+ }
+
+ ASSERT(clock);
+ return clock;
+}
+
+static void dcn316_clk_mgr_helper_populate_bw_params(
+ struct clk_mgr_internal *clk_mgr,
+ struct integrated_info *bios_info,
+ const DpmClocks_316_t *clock_table)
+{
+ int i, j;
+ struct clk_bw_params *bw_params = clk_mgr->base.bw_params;
+ uint32_t max_dispclk = 0, max_dppclk = 0;
+
+ j = -1;
+
+ ASSERT(NUM_DF_PSTATE_LEVELS <= MAX_NUM_DPM_LVL);
+
+ /* Find lowest DPM, FCLK is filled in reverse order*/
+
+ for (i = NUM_DF_PSTATE_LEVELS - 1; i >= 0; i--) {
+ if (clock_table->DfPstateTable[i].FClk != 0) {
+ j = i;
+ break;
+ }
+ }
+
+ if (j == -1) {
+ /* clock table is all 0s, just use our own hardcode */
+ ASSERT(0);
+ return;
+ }
+
+ bw_params->clk_table.num_entries = j + 1;
+
+ /* dispclk and dppclk can be max at any voltage, same number of levels for both */
+ if (clock_table->NumDispClkLevelsEnabled <= NUM_DISPCLK_DPM_LEVELS &&
+ clock_table->NumDispClkLevelsEnabled <= NUM_DPPCLK_DPM_LEVELS) {
+ max_dispclk = find_max_clk_value(clock_table->DispClocks, clock_table->NumDispClkLevelsEnabled);
+ max_dppclk = find_max_clk_value(clock_table->DppClocks, clock_table->NumDispClkLevelsEnabled);
+ } else {
+ ASSERT(0);
+ }
+
+ for (i = 0; i < bw_params->clk_table.num_entries; i++, j--) {
+ int temp;
+
+ bw_params->clk_table.entries[i].fclk_mhz = clock_table->DfPstateTable[j].FClk;
+ bw_params->clk_table.entries[i].memclk_mhz = clock_table->DfPstateTable[j].MemClk;
+ bw_params->clk_table.entries[i].voltage = clock_table->DfPstateTable[j].Voltage;
+ switch (clock_table->DfPstateTable[j].WckRatio) {
+ case WCK_RATIO_1_2:
+ bw_params->clk_table.entries[i].wck_ratio = 2;
+ break;
+ case WCK_RATIO_1_4:
+ bw_params->clk_table.entries[i].wck_ratio = 4;
+ break;
+ default:
+ bw_params->clk_table.entries[i].wck_ratio = 1;
+ }
+ temp = find_clk_for_voltage(clock_table, clock_table->DcfClocks, clock_table->DfPstateTable[j].Voltage);
+ if (temp)
+ bw_params->clk_table.entries[i].dcfclk_mhz = temp;
+ temp = find_clk_for_voltage(clock_table, clock_table->SocClocks, clock_table->DfPstateTable[j].Voltage);
+ if (temp)
+ bw_params->clk_table.entries[i].socclk_mhz = temp;
+ bw_params->clk_table.entries[i].dispclk_mhz = max_dispclk;
+ bw_params->clk_table.entries[i].dppclk_mhz = max_dppclk;
+ }
+
+ bw_params->vram_type = bios_info->memory_type;
+ bw_params->num_channels = bios_info->ma_channel_number;
+
+ for (i = 0; i < WM_SET_COUNT; i++) {
+ bw_params->wm_table.entries[i].wm_inst = i;
+
+ if (i >= bw_params->clk_table.num_entries) {
+ bw_params->wm_table.entries[i].valid = false;
+ continue;
+ }
+
+ bw_params->wm_table.entries[i].wm_type = WM_TYPE_PSTATE_CHG;
+ bw_params->wm_table.entries[i].valid = true;
+ }
+}
+
+
+
+static struct clk_mgr_funcs dcn316_funcs = {
+ .enable_pme_wa = dcn316_enable_pme_wa,
+ .get_dp_ref_clk_frequency = dce12_get_dp_ref_freq_khz,
+ .get_dtb_ref_clk_frequency = dcn31_get_dtb_ref_freq_khz,
+ .update_clocks = dcn316_update_clocks,
+ .init_clocks = dcn31_init_clocks,
+ .are_clock_states_equal = dcn31_are_clock_states_equal,
+ .notify_wm_ranges = dcn316_notify_wm_ranges
+};
+extern struct clk_mgr_funcs dcn3_fpga_funcs;
+
+static int get_vco_frequency_from_reg(struct clk_mgr_internal *clk_mgr)
+{
+ /* get FbMult value */
+ struct fixed31_32 pll_req;
+ unsigned int fbmult_frac_val = 0;
+ unsigned int fbmult_int_val = 0;
+
+ /*
+ * Register value of fbmult is in 8.16 format, we are converting to 31.32
+ * to leverage the fix point operations available in driver
+ */
+
+ REG_GET(CLK1_CLK_PLL_REQ, FbMult_frac, &fbmult_frac_val); /* 16 bit fractional part*/
+ REG_GET(CLK1_CLK_PLL_REQ, FbMult_int, &fbmult_int_val); /* 8 bit integer part */
+
+ pll_req = dc_fixpt_from_int(fbmult_int_val);
+
+ /*
+ * since fractional part is only 16 bit in register definition but is 32 bit
+ * in our fix point definiton, need to shift left by 16 to obtain correct value
+ */
+ pll_req.value |= fbmult_frac_val << 16;
+
+ /* multiply by REFCLK period */
+ pll_req = dc_fixpt_mul_int(pll_req, clk_mgr->dfs_ref_freq_khz);
+
+ /* integer part is now VCO frequency in kHz */
+ return dc_fixpt_floor(pll_req);
+}
+
+void dcn316_clk_mgr_construct(
+ struct dc_context *ctx,
+ struct clk_mgr_dcn316 *clk_mgr,
+ struct pp_smu_funcs *pp_smu,
+ struct dccg *dccg)
+{
+ struct dcn316_smu_dpm_clks smu_dpm_clks = { 0 };
+
+ clk_mgr->base.base.ctx = ctx;
+ clk_mgr->base.base.funcs = &dcn316_funcs;
+
+ clk_mgr->base.pp_smu = pp_smu;
+
+ clk_mgr->base.dccg = dccg;
+ clk_mgr->base.dfs_bypass_disp_clk = 0;
+
+ clk_mgr->base.dprefclk_ss_percentage = 0;
+ clk_mgr->base.dprefclk_ss_divider = 1000;
+ clk_mgr->base.ss_on_dprefclk = false;
+ clk_mgr->base.dfs_ref_freq_khz = 48000;
+
+ clk_mgr->smu_wm_set.wm_set = (struct dcn316_watermarks *)dm_helpers_allocate_gpu_mem(
+ clk_mgr->base.base.ctx,
+ DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
+ sizeof(struct dcn316_watermarks),
+ &clk_mgr->smu_wm_set.mc_address.quad_part);
+
+ if (!clk_mgr->smu_wm_set.wm_set) {
+ clk_mgr->smu_wm_set.wm_set = &dummy_wms;
+ clk_mgr->smu_wm_set.mc_address.quad_part = 0;
+ }
+ ASSERT(clk_mgr->smu_wm_set.wm_set);
+
+ smu_dpm_clks.dpm_clks = (DpmClocks_316_t *)dm_helpers_allocate_gpu_mem(
+ clk_mgr->base.base.ctx,
+ DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
+ sizeof(DpmClocks_316_t),
+ &smu_dpm_clks.mc_address.quad_part);
+
+ if (smu_dpm_clks.dpm_clks == NULL) {
+ smu_dpm_clks.dpm_clks = &dummy_clocks;
+ smu_dpm_clks.mc_address.quad_part = 0;
+ }
+
+ ASSERT(smu_dpm_clks.dpm_clks);
+
+ if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment)) {
+ clk_mgr->base.base.funcs = &dcn3_fpga_funcs;
+ clk_mgr->base.base.dentist_vco_freq_khz = 2500000;
+ } else {
+ struct clk_log_info log_info = {0};
+
+ clk_mgr->base.smu_ver = dcn316_smu_get_smu_version(&clk_mgr->base);
+
+ if (clk_mgr->base.smu_ver > 0)
+ clk_mgr->base.smu_present = true;
+
+ // Skip this for now as it did not work on DCN315, renable during bring up
+ clk_mgr->base.base.dentist_vco_freq_khz = get_vco_frequency_from_reg(&clk_mgr->base);
+
+ /* in case we don't get a value from the register, use default */
+ if (clk_mgr->base.base.dentist_vco_freq_khz == 0)
+ clk_mgr->base.base.dentist_vco_freq_khz = 2500000; /* 2400MHz */
+
+
+ if (ctx->dc_bios->integrated_info->memory_type == LpDdr5MemType) {
+ dcn316_bw_params.wm_table = lpddr5_wm_table;
+ } else {
+ dcn316_bw_params.wm_table = ddr4_wm_table;
+ }
+ /* Saved clocks configured at boot for debug purposes */
+ dcn316_dump_clk_registers(&clk_mgr->base.base.boot_snapshot, &clk_mgr->base.base, &log_info);
+
+ }
+
+ clk_mgr->base.base.dprefclk_khz = 600000;
+ clk_mgr->base.base.dprefclk_khz = dcn316_smu_get_dpref_clk(&clk_mgr->base);
+ clk_mgr->base.base.clks.ref_dtbclk_khz = clk_mgr->base.base.dprefclk_khz;
+ dce_clock_read_ss_info(&clk_mgr->base);
+ /*clk_mgr->base.dccg->ref_dtbclk_khz =
+ dce_adjust_dp_ref_freq_for_ss(&clk_mgr->base, clk_mgr->base.base.dprefclk_khz);*/
+
+ clk_mgr->base.base.bw_params = &dcn316_bw_params;
+
+ if (clk_mgr->base.base.ctx->dc->debug.pstate_enabled) {
+ dcn316_get_dpm_table_from_smu(&clk_mgr->base, &smu_dpm_clks);
+
+ if (ctx->dc_bios && ctx->dc_bios->integrated_info) {
+ dcn316_clk_mgr_helper_populate_bw_params(
+ &clk_mgr->base,
+ ctx->dc_bios->integrated_info,
+ smu_dpm_clks.dpm_clks);
+ }
+ }
+
+ if (smu_dpm_clks.dpm_clks && smu_dpm_clks.mc_address.quad_part != 0)
+ dm_helpers_free_gpu_mem(clk_mgr->base.base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
+ smu_dpm_clks.dpm_clks);
+}
+
+void dcn316_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int)
+{
+ struct clk_mgr_dcn316 *clk_mgr = TO_CLK_MGR_DCN316(clk_mgr_int);
+
+ if (clk_mgr->smu_wm_set.wm_set && clk_mgr->smu_wm_set.mc_address.quad_part != 0)
+ dm_helpers_free_gpu_mem(clk_mgr_int->base.ctx, DC_MEM_ALLOC_TYPE_FRAME_BUFFER,
+ clk_mgr->smu_wm_set.wm_set);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.h
new file mode 100644
index 000000000000..864d1f6cef26
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_clk_mgr.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN316_CLK_MGR_H__
+#define __DCN316_CLK_MGR_H__
+#include "clk_mgr_internal.h"
+
+struct dcn316_watermarks;
+
+struct dcn316_smu_watermark_set {
+ struct dcn316_watermarks *wm_set;
+ union large_integer mc_address;
+};
+
+struct clk_mgr_dcn316 {
+ struct clk_mgr_internal base;
+ struct dcn316_smu_watermark_set smu_wm_set;
+};
+
+void dcn316_clk_mgr_construct(struct dc_context *ctx,
+ struct clk_mgr_dcn316 *clk_mgr,
+ struct pp_smu_funcs *pp_smu,
+ struct dccg *dccg);
+
+void dcn316_clk_mgr_destroy(struct clk_mgr_internal *clk_mgr_int);
+
+#endif //__DCN316_CLK_MGR_H__
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.c b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.c
new file mode 100644
index 000000000000..dceec4b96052
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "core_types.h"
+#include "clk_mgr_internal.h"
+#include "reg_helper.h"
+#include "dm_helpers.h"
+#include "dcn316_smu.h"
+#include "mp/mp_13_0_8_offset.h"
+#include "mp/mp_13_0_8_sh_mask.h"
+
+#define MAX_INSTANCE 7
+#define MAX_SEGMENT 6
+
+struct IP_BASE_INSTANCE
+{
+ unsigned int segment[MAX_SEGMENT];
+};
+
+struct IP_BASE
+{
+ struct IP_BASE_INSTANCE instance[MAX_INSTANCE];
+};
+
+static const struct IP_BASE MP0_BASE = { { { { 0x00016000, 0x00DC0000, 0x00E00000, 0x00E40000, 0x0243FC00, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } },
+ { { 0, 0, 0, 0, 0, 0 } } } };
+
+#define REG(reg_name) \
+ (MP0_BASE.instance[0].segment[reg ## reg_name ## _BASE_IDX] + reg ## reg_name)
+
+#define FN(reg_name, field) \
+ FD(reg_name##__##field)
+
+#define VBIOSSMC_MSG_TestMessage 0x01 ///< To check if PMFW is alive and responding. Requirement specified by PMFW team
+#define VBIOSSMC_MSG_GetPmfwVersion 0x02 ///< Get PMFW version
+#define VBIOSSMC_MSG_Spare0 0x03 ///< Spare0
+#define VBIOSSMC_MSG_SetDispclkFreq 0x04 ///< Set display clock frequency in MHZ
+#define VBIOSSMC_MSG_Spare1 0x05 ///< Spare1
+#define VBIOSSMC_MSG_SetDppclkFreq 0x06 ///< Set DPP clock frequency in MHZ
+#define VBIOSSMC_MSG_SetHardMinDcfclkByFreq 0x07 ///< Set DCF clock frequency hard min in MHZ
+#define VBIOSSMC_MSG_SetMinDeepSleepDcfclk 0x08 ///< Set DCF clock minimum frequency in deep sleep in MHZ
+#define VBIOSSMC_MSG_SetPhyclkVoltageByFreq 0x09 ///< Set display phy clock frequency in MHZ in case VMIN does not support phy frequency
+#define VBIOSSMC_MSG_GetFclkFrequency 0x0A ///< Get FCLK frequency, return frequemcy in MHZ
+#define VBIOSSMC_MSG_SetDisplayCount 0x0B ///< Inform PMFW of number of display connected
+#define VBIOSSMC_MSG_SPARE 0x0C ///< SPARE
+#define VBIOSSMC_MSG_UpdatePmeRestore 0x0D ///< To ask PMFW to write into Azalia for PME wake up event
+#define VBIOSSMC_MSG_SetVbiosDramAddrHigh 0x0E ///< Set DRAM address high 32 bits for WM table transfer
+#define VBIOSSMC_MSG_SetVbiosDramAddrLow 0x0F ///< Set DRAM address low 32 bits for WM table transfer
+#define VBIOSSMC_MSG_TransferTableSmu2Dram 0x10 ///< Transfer table from PMFW SRAM to system DRAM
+#define VBIOSSMC_MSG_TransferTableDram2Smu 0x11 ///< Transfer table from system DRAM to PMFW
+#define VBIOSSMC_MSG_SetDisplayIdleOptimizations 0x12 ///< Set Idle state optimization for display off
+#define VBIOSSMC_MSG_GetDprefclkFreq 0x13 ///< Get DPREF clock frequency. Return in MHZ
+#define VBIOSSMC_MSG_GetDtbclkFreq 0x14 ///< Get DPREF clock frequency. Return in MHZ
+#define VBIOSSMC_MSG_SetDtbclkFreq 0x15 ///< Inform PMFW to turn on/off DTB clock arg = 1, turn DTB clock on 600MHz/ arg = 0 turn DTB clock off
+#define VBIOSSMC_Message_Count 0x16 ///< Total number of VBIS and DAL messages
+
+#define VBIOSSMC_Status_BUSY 0x0
+#define VBIOSSMC_Result_OK 0x01 ///< Message Response OK
+#define VBIOSSMC_Result_Failed 0xFF ///< Message Response Failed
+#define VBIOSSMC_Result_UnknownCmd 0xFE ///< Message Response Unknown Command
+#define VBIOSSMC_Result_CmdRejectedPrereq 0xFD ///< Message Response Command Failed Prerequisite
+#define VBIOSSMC_Result_CmdRejectedBusy 0xFC ///< Message Response Command Rejected due to PMFW is busy. Sender should retry sending this message
+
+/*
+ * Function to be used instead of REG_WAIT macro because the wait ends when
+ * the register is NOT EQUAL to zero, and because the translation in msg_if.h
+ * won't work with REG_WAIT.
+ */
+static uint32_t dcn316_smu_wait_for_response(struct clk_mgr_internal *clk_mgr, unsigned int delay_us, unsigned int max_retries)
+{
+ uint32_t res_val = VBIOSSMC_Status_BUSY;
+
+ do {
+ res_val = REG_READ(MP1_SMN_C2PMSG_91);
+ if (res_val != VBIOSSMC_Status_BUSY)
+ break;
+
+ if (delay_us >= 1000)
+ msleep(delay_us/1000);
+ else if (delay_us > 0)
+ udelay(delay_us);
+ } while (max_retries--);
+
+ return res_val;
+}
+
+static int dcn316_smu_send_msg_with_param(
+ struct clk_mgr_internal *clk_mgr,
+ unsigned int msg_id, unsigned int param)
+{
+ uint32_t result;
+
+ result = dcn316_smu_wait_for_response(clk_mgr, 10, 200000);
+ ASSERT(result == VBIOSSMC_Result_OK);
+
+ if (result == VBIOSSMC_Status_BUSY) {
+ return -1;
+ }
+
+ /* First clear response register */
+ REG_WRITE(MP1_SMN_C2PMSG_91, VBIOSSMC_Status_BUSY);
+
+ /* Set the parameter register for the SMU message, unit is Mhz */
+ REG_WRITE(MP1_SMN_C2PMSG_83, param);
+
+ /* Trigger the message transaction by writing the message ID */
+ REG_WRITE(MP1_SMN_C2PMSG_67, msg_id);
+
+ result = dcn316_smu_wait_for_response(clk_mgr, 10, 200000);
+
+ if (result == VBIOSSMC_Status_BUSY) {
+ ASSERT(0);
+ dm_helpers_smu_timeout(CTX, msg_id, param, 10 * 200000);
+ }
+
+ return REG_READ(MP1_SMN_C2PMSG_83);
+}
+
+int dcn316_smu_get_smu_version(struct clk_mgr_internal *clk_mgr)
+{
+ return dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_GetPmfwVersion,
+ 0);
+}
+
+
+int dcn316_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz)
+{
+ int actual_dispclk_set_mhz = -1;
+
+ if (!clk_mgr->smu_present)
+ return requested_dispclk_khz;
+
+ /* Unit of SMU msg parameter is Mhz */
+ actual_dispclk_set_mhz = dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDispclkFreq,
+ khz_to_mhz_ceil(requested_dispclk_khz));
+
+ return actual_dispclk_set_mhz * 1000;
+}
+
+int dcn316_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz)
+{
+ int actual_dcfclk_set_mhz = -1;
+
+ if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
+ return -1;
+
+ if (!clk_mgr->smu_present)
+ return requested_dcfclk_khz;
+
+ actual_dcfclk_set_mhz = dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetHardMinDcfclkByFreq,
+ khz_to_mhz_ceil(requested_dcfclk_khz));
+
+ return actual_dcfclk_set_mhz * 1000;
+}
+
+int dcn316_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz)
+{
+ int actual_min_ds_dcfclk_mhz = -1;
+
+ if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
+ return -1;
+
+ if (!clk_mgr->smu_present)
+ return requested_min_ds_dcfclk_khz;
+
+ actual_min_ds_dcfclk_mhz = dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetMinDeepSleepDcfclk,
+ khz_to_mhz_ceil(requested_min_ds_dcfclk_khz));
+
+ return actual_min_ds_dcfclk_mhz * 1000;
+}
+
+int dcn316_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz)
+{
+ int actual_dppclk_set_mhz = -1;
+
+ if (!clk_mgr->smu_present)
+ return requested_dpp_khz;
+
+ actual_dppclk_set_mhz = dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDppclkFreq,
+ khz_to_mhz_ceil(requested_dpp_khz));
+
+ return actual_dppclk_set_mhz * 1000;
+}
+
+void dcn316_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info)
+{
+ if (!clk_mgr->base.ctx->dc->debug.pstate_enabled)
+ return;
+
+ if (!clk_mgr->smu_present)
+ return;
+
+ //TODO: Work with smu team to define optimization options.
+ dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDisplayIdleOptimizations,
+ idle_info);
+}
+
+void dcn316_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable)
+{
+ union display_idle_optimization_u idle_info = { 0 };
+
+ if (!clk_mgr->smu_present)
+ return;
+
+ if (enable) {
+ idle_info.idle_info.df_request_disabled = 1;
+ idle_info.idle_info.phy_ref_clk_off = 1;
+ }
+
+ dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDisplayIdleOptimizations,
+ idle_info.data);
+}
+
+void dcn316_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn316_smu_send_msg_with_param(clk_mgr,
+ VBIOSSMC_MSG_SetVbiosDramAddrHigh, addr_high);
+}
+
+void dcn316_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn316_smu_send_msg_with_param(clk_mgr,
+ VBIOSSMC_MSG_SetVbiosDramAddrLow, addr_low);
+}
+
+void dcn316_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn316_smu_send_msg_with_param(clk_mgr,
+ VBIOSSMC_MSG_TransferTableSmu2Dram, TABLE_DPMCLOCKS);
+}
+
+void dcn316_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn316_smu_send_msg_with_param(clk_mgr,
+ VBIOSSMC_MSG_TransferTableDram2Smu, TABLE_WATERMARKS);
+}
+
+void dcn316_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_UpdatePmeRestore,
+ 0);
+}
+
+/* Arg = 1: Turn DTB on; 0: Turn DTB CLK OFF. when it is on, it is 600MHZ */
+void dcn316_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable)
+{
+ if (!clk_mgr->smu_present)
+ return;
+
+ dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_SetDtbclkFreq,
+ enable);
+}
+
+int dcn316_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr)
+{
+ int dprefclk_get_mhz = -1;
+
+ if (clk_mgr->smu_present) {
+ dprefclk_get_mhz = dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_GetDprefclkFreq,
+ 0);
+ }
+ return (dprefclk_get_mhz * 1000);
+}
+
+int dcn316_smu_get_smu_fclk(struct clk_mgr_internal *clk_mgr)
+{
+ int fclk_get_mhz = -1;
+
+ if (clk_mgr->smu_present) {
+ fclk_get_mhz = dcn316_smu_send_msg_with_param(
+ clk_mgr,
+ VBIOSSMC_MSG_GetFclkFrequency,
+ 0);
+ }
+ return (fclk_get_mhz * 1000);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.h b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.h
new file mode 100644
index 000000000000..2a7293f66515
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dcn316/dcn316_smu.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef DAL_DC_316_SMU_H_
+#define DAL_DC_316_SMU_H_
+#include "os_types.h"
+
+#define PMFW_DRIVER_IF_VERSION 4
+
+#define NUM_DCFCLK_DPM_LEVELS 8
+#define NUM_DISPCLK_DPM_LEVELS 8
+#define NUM_DPPCLK_DPM_LEVELS 8
+#define NUM_SOCCLK_DPM_LEVELS 8
+#define NUM_VCN_DPM_LEVELS 8
+#define NUM_SOC_VOLTAGE_LEVELS 8
+#define NUM_DF_PSTATE_LEVELS 4
+
+typedef struct {
+ uint16_t MinClock; // This is either DCFCLK or SOCCLK (in MHz)
+ uint16_t MaxClock; // This is either DCFCLK or SOCCLK (in MHz)
+ uint16_t MinMclk;
+ uint16_t MaxMclk;
+ uint8_t WmSetting;
+ uint8_t WmType; // Used for normal pstate change or memory retraining
+ uint8_t Padding[2];
+} WatermarkRowGeneric_t;
+
+#define NUM_WM_RANGES 4
+#define WM_PSTATE_CHG 0
+#define WM_RETRAINING 1
+
+typedef enum {
+ WM_SOCCLK = 0,
+ WM_DCFCLK,
+ WM_COUNT,
+} WM_CLOCK_e;
+
+typedef enum{
+ WCK_RATIO_1_1 = 0, // DDR5, Wck:ck is always 1:1;
+ WCK_RATIO_1_2,
+ WCK_RATIO_1_4,
+ WCK_RATIO_MAX
+} WCK_RATIO_e;
+
+typedef struct {
+ uint32_t FClk;
+ uint32_t MemClk;
+ uint32_t Voltage;
+ uint8_t WckRatio;
+ uint8_t Spare[3];
+} DfPstateTable_t;
+
+//Freq in MHz
+//Voltage in milli volts with 2 fractional bits
+typedef struct {
+ uint32_t DcfClocks[NUM_DCFCLK_DPM_LEVELS];
+ uint32_t DispClocks[NUM_DISPCLK_DPM_LEVELS];
+ uint32_t DppClocks[NUM_DPPCLK_DPM_LEVELS];
+ uint32_t SocClocks[NUM_SOCCLK_DPM_LEVELS];
+ uint32_t VClocks[NUM_VCN_DPM_LEVELS];
+ uint32_t DClocks[NUM_VCN_DPM_LEVELS];
+ uint32_t SocVoltage[NUM_SOC_VOLTAGE_LEVELS];
+ DfPstateTable_t DfPstateTable[NUM_DF_PSTATE_LEVELS];
+ uint8_t NumDcfClkLevelsEnabled;
+ uint8_t NumDispClkLevelsEnabled; //Applies to both Dispclk and Dppclk
+ uint8_t NumSocClkLevelsEnabled;
+ uint8_t VcnClkLevelsEnabled; //Applies to both Vclk and Dclk
+ uint8_t NumDfPstatesEnabled;
+ uint8_t spare[3];
+ uint32_t MinGfxClk;
+ uint32_t MaxGfxClk;
+} DpmClocks_316_t;
+
+struct dcn316_watermarks {
+ // Watermarks
+ WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES];
+ uint32_t MmHubPadding[7]; // SMU internal use
+};
+
+struct dcn316_smu_dpm_clks {
+ DpmClocks_316_t *dpm_clks;
+ union large_integer mc_address;
+};
+
+#define TABLE_WATERMARKS 1 // Called by DAL through VBIOS
+#define TABLE_DPMCLOCKS 4 // Called by Driver and VBIOS
+
+struct display_idle_optimization {
+ unsigned int df_request_disabled : 1;
+ unsigned int phy_ref_clk_off : 1;
+ unsigned int s0i2_rdy : 1;
+ unsigned int reserved : 29;
+};
+
+union display_idle_optimization_u {
+ struct display_idle_optimization idle_info;
+ uint32_t data;
+};
+
+int dcn316_smu_get_smu_version(struct clk_mgr_internal *clk_mgr);
+int dcn316_smu_set_dispclk(struct clk_mgr_internal *clk_mgr, int requested_dispclk_khz);
+int dcn316_smu_set_hard_min_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_dcfclk_khz);
+int dcn316_smu_set_min_deep_sleep_dcfclk(struct clk_mgr_internal *clk_mgr, int requested_min_ds_dcfclk_khz);
+int dcn316_smu_set_dppclk(struct clk_mgr_internal *clk_mgr, int requested_dpp_khz);
+void dcn316_smu_set_display_idle_optimization(struct clk_mgr_internal *clk_mgr, uint32_t idle_info);
+void dcn316_smu_enable_phy_refclk_pwrdwn(struct clk_mgr_internal *clk_mgr, bool enable);
+void dcn316_smu_set_dram_addr_high(struct clk_mgr_internal *clk_mgr, uint32_t addr_high);
+void dcn316_smu_set_dram_addr_low(struct clk_mgr_internal *clk_mgr, uint32_t addr_low);
+void dcn316_smu_transfer_dpm_table_smu_2_dram(struct clk_mgr_internal *clk_mgr);
+void dcn316_smu_transfer_wm_table_dram_2_smu(struct clk_mgr_internal *clk_mgr);
+void dcn316_smu_request_voltage_via_phyclk(struct clk_mgr_internal *clk_mgr, int requested_phyclk_khz);
+void dcn316_smu_enable_pme_wa(struct clk_mgr_internal *clk_mgr);
+void dcn316_smu_set_dtbclk(struct clk_mgr_internal *clk_mgr, bool enable);
+int dcn316_smu_get_dpref_clk(struct clk_mgr_internal *clk_mgr);
+int dcn316_smu_get_smu_fclk(struct clk_mgr_internal *clk_mgr);
+
+#endif /* DAL_DC_316_SMU_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c
index ba1aa994db4b..f14449401188 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc.c
@@ -76,6 +76,8 @@
#include "dc_trace.h"
+#include "dce/dmub_outbox.h"
+
#define CTX \
dc->ctx
@@ -827,14 +829,12 @@ static void dc_destruct(struct dc *dc)
kfree(dc->bw_dceip);
dc->bw_dceip = NULL;
-#ifdef CONFIG_DRM_AMD_DC_DCN
kfree(dc->dcn_soc);
dc->dcn_soc = NULL;
kfree(dc->dcn_ip);
dc->dcn_ip = NULL;
-#endif
kfree(dc->vm_helper);
dc->vm_helper = NULL;
@@ -880,10 +880,8 @@ static bool dc_construct(struct dc *dc,
struct dc_context *dc_ctx;
struct bw_calcs_dceip *dc_dceip;
struct bw_calcs_vbios *dc_vbios;
-#ifdef CONFIG_DRM_AMD_DC_DCN
struct dcn_soc_bounding_box *dcn_soc;
struct dcn_ip_params *dcn_ip;
-#endif
dc->config = init_params->flags;
@@ -911,7 +909,6 @@ static bool dc_construct(struct dc *dc,
}
dc->bw_vbios = dc_vbios;
-#ifdef CONFIG_DRM_AMD_DC_DCN
dcn_soc = kzalloc(sizeof(*dcn_soc), GFP_KERNEL);
if (!dcn_soc) {
dm_error("%s: failed to create dcn_soc\n", __func__);
@@ -927,7 +924,6 @@ static bool dc_construct(struct dc *dc,
}
dc->dcn_ip = dcn_ip;
-#endif
if (!dc_construct_ctx(dc, init_params)) {
dm_error("%s: failed to create ctx\n", __func__);
@@ -1080,7 +1076,8 @@ static void disable_dangling_plane(struct dc *dc, struct dc_state *context)
break;
}
}
- if (!should_disable && pipe_split_change)
+ if (!should_disable && pipe_split_change &&
+ dc->current_state->stream_count != context->stream_count)
should_disable = true;
if (should_disable && old_stream) {
@@ -1472,7 +1469,7 @@ static bool context_changed(
return false;
}
-bool dc_validate_seamless_boot_timing(const struct dc *dc,
+bool dc_validate_boot_timing(const struct dc *dc,
const struct dc_sink *sink,
struct dc_crtc_timing *crtc_timing)
{
@@ -1566,11 +1563,24 @@ bool dc_validate_seamless_boot_timing(const struct dc *dc,
if (dc_is_dp_signal(link->connector_signal)) {
unsigned int pix_clk_100hz;
+ uint32_t numOdmPipes = 1;
+ uint32_t id_src[4] = {0};
dc->res_pool->dp_clock_source->funcs->get_pixel_clk_frequency_100hz(
dc->res_pool->dp_clock_source,
tg_inst, &pix_clk_100hz);
+ if (tg->funcs->get_optc_source)
+ tg->funcs->get_optc_source(tg,
+ &numOdmPipes, &id_src[0], &id_src[1]);
+
+ if (numOdmPipes == 2)
+ pix_clk_100hz *= 2;
+ if (numOdmPipes == 4)
+ pix_clk_100hz *= 4;
+
+ // Note: In rare cases, HW pixclk may differ from crtc's pixclk
+ // slightly due to rounding issues in 10 kHz units.
if (crtc_timing->pix_clk_100hz != pix_clk_100hz)
return false;
@@ -1664,7 +1674,6 @@ static uint8_t get_stream_mask(struct dc *dc, struct dc_state *context)
return stream_mask;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
void dc_z10_restore(const struct dc *dc)
{
if (dc->hwss.z10_restore)
@@ -1676,7 +1685,7 @@ void dc_z10_save_init(struct dc *dc)
if (dc->hwss.z10_save_init)
dc->hwss.z10_save_init(dc);
}
-#endif
+
/*
* Applies given context to HW and copy it into current context.
* It's up to the user to release the src context afterwards.
@@ -1688,11 +1697,10 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
struct pipe_ctx *pipe;
int i, k, l;
struct dc_stream_state *dc_streams[MAX_STREAMS] = {0};
+ struct dc_state *old_state;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
dc_z10_restore(dc);
dc_allow_idle_optimizations(dc, false);
-#endif
for (i = 0; i < context->stream_count; i++)
dc_streams[i] = context->streams[i];
@@ -1806,10 +1814,11 @@ static enum dc_status dc_commit_state_no_check(struct dc *dc, struct dc_state *c
for (i = 0; i < context->stream_count; i++)
context->streams[i]->mode_changed = false;
- dc_release_state(dc->current_state);
-
+ old_state = dc->current_state;
dc->current_state = context;
+ dc_release_state(old_state);
+
dc_retain_state(dc->current_state);
return result;
@@ -1850,7 +1859,6 @@ bool dc_commit_state(struct dc *dc, struct dc_state *context)
return (result == DC_OK);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool dc_acquire_release_mpc_3dlut(
struct dc *dc, bool acquire,
struct dc_stream_state *stream,
@@ -1886,7 +1894,7 @@ bool dc_acquire_release_mpc_3dlut(
}
return ret;
}
-#endif
+
static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context)
{
int i;
@@ -1907,7 +1915,6 @@ static bool is_flip_pending_in_pipes(struct dc *dc, struct dc_state *context)
return false;
}
-#ifdef CONFIG_DRM_AMD_DC_DCN
/* Perform updates here which need to be deferred until next vupdate
*
* i.e. blnd lut, 3dlut, and shaper lut bypass regs are double buffered
@@ -1926,7 +1933,6 @@ static void process_deferred_updates(struct dc *dc)
dc->res_pool->dpps[i]->funcs->dpp_deferred_update(dc->res_pool->dpps[i]);
}
}
-#endif /* CONFIG_DRM_AMD_DC_DCN */
void dc_post_update_surfaces_to_stream(struct dc *dc)
{
@@ -1953,9 +1959,7 @@ void dc_post_update_surfaces_to_stream(struct dc *dc)
dc->hwss.disable_plane(dc, &context->res_ctx.pipe_ctx[i]);
}
-#ifdef CONFIG_DRM_AMD_DC_DCN
process_deferred_updates(dc);
-#endif
dc->hwss.optimize_bandwidth(dc, context);
@@ -1969,9 +1973,7 @@ static void init_state(struct dc *dc, struct dc_state *context)
* initialize and obtain IP and SOC the base DML instance from DC is
* initially copied into every context
*/
-#ifdef CONFIG_DRM_AMD_DC_DCN
memcpy(&context->bw_ctx.dml, &dc->dml, sizeof(struct display_mode_lib));
-#endif
}
struct dc_state *dc_create_state(struct dc *dc)
@@ -2343,11 +2345,9 @@ static enum surface_update_type check_update_surfaces_for_stream(
int i;
enum surface_update_type overall_type = UPDATE_TYPE_FAST;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dc->idle_optimizations_allowed)
overall_type = UPDATE_TYPE_FULL;
-#endif
if (stream_status == NULL || stream_status->plane_count != surface_count)
overall_type = UPDATE_TYPE_FULL;
@@ -2382,10 +2382,10 @@ static enum surface_update_type check_update_surfaces_for_stream(
if (stream_update->dsc_config)
su_flags->bits.dsc_changed = 1;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (stream_update->mst_bw_update)
su_flags->bits.mst_bw = 1;
-#endif
+ if (stream_update->crtc_timing_adjust && dc_extended_blank_supported(dc))
+ su_flags->bits.crtc_timing_adjust = 1;
if (su_flags->raw != 0)
overall_type = UPDATE_TYPE_FULL;
@@ -2647,6 +2647,9 @@ static void copy_stream_update_to_stream(struct dc *dc,
if (update->vrr_infopacket)
stream->vrr_infopacket = *update->vrr_infopacket;
+ if (update->crtc_timing_adjust)
+ stream->adjust = *update->crtc_timing_adjust;
+
if (update->dpms_off)
stream->dpms_off = *update->dpms_off;
@@ -2727,6 +2730,9 @@ static void commit_planes_do_stream_update(struct dc *dc,
stream_update->vsp_infopacket) {
resource_build_info_frame(pipe_ctx);
dc->hwss.update_info_frame(pipe_ctx);
+
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ dp_source_sequence_trace(pipe_ctx->stream->link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
}
if (stream_update->hdr_static_metadata &&
@@ -2764,14 +2770,12 @@ static void commit_planes_do_stream_update(struct dc *dc,
if (stream_update->dsc_config)
dp_update_dsc_config(pipe_ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (stream_update->mst_bw_update) {
if (stream_update->mst_bw_update->is_increase)
dc_link_increase_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
else
dc_link_reduce_mst_payload(pipe_ctx, stream_update->mst_bw_update->mst_stream_bw);
}
-#endif
if (stream_update->pending_test_pattern) {
dc_link_dp_set_test_pattern(stream->link,
@@ -2832,9 +2836,7 @@ static void commit_planes_for_stream(struct dc *dc,
struct pipe_ctx *top_pipe_to_program = NULL;
bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
dc_z10_restore(dc);
-#endif
if (get_seamless_boot_stream_count(context) > 0 && surface_count > 0) {
/* Optimize seamless boot flag keeps clocks and watermarks high until
@@ -2852,10 +2854,8 @@ static void commit_planes_for_stream(struct dc *dc,
}
if (update_type == UPDATE_TYPE_FULL) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
dc_allow_idle_optimizations(dc, false);
-#endif
if (get_seamless_boot_stream_count(context) == 0)
dc->hwss.prepare_bandwidth(dc, context);
@@ -2873,7 +2873,6 @@ static void commit_planes_for_stream(struct dc *dc,
}
}
-#ifdef CONFIG_DRM_AMD_DC_DCN
if (stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) {
struct pipe_ctx *mpcc_pipe;
struct pipe_ctx *odm_pipe;
@@ -2882,7 +2881,6 @@ static void commit_planes_for_stream(struct dc *dc,
for (odm_pipe = mpcc_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
odm_pipe->ttu_regs.min_ttu_vblank = MAX_TTU;
}
-#endif
if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
if (top_pipe_to_program &&
@@ -2903,14 +2901,15 @@ static void commit_planes_for_stream(struct dc *dc,
top_pipe_to_program->stream_res.tg);
}
- if (should_lock_all_pipes && dc->hwss.interdependent_update_lock)
+ if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
dc->hwss.interdependent_update_lock(dc, context, true);
- else
+ } else {
/* Lock the top pipe while updating plane addrs, since freesync requires
* plane addr update event triggers to be synchronized.
* top_pipe_to_program is expected to never be NULL
*/
dc->hwss.pipe_control_lock(dc, top_pipe_to_program, true);
+ }
// Stream updates
if (stream_update)
@@ -2926,10 +2925,11 @@ static void commit_planes_for_stream(struct dc *dc,
if (dc->hwss.program_front_end_for_ctx)
dc->hwss.program_front_end_for_ctx(dc, context);
- if (should_lock_all_pipes && dc->hwss.interdependent_update_lock)
+ if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
dc->hwss.interdependent_update_lock(dc, context, false);
- else
+ } else {
dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
+ }
dc->hwss.post_unlock_program_front_end(dc, context);
return;
}
@@ -2992,7 +2992,6 @@ static void commit_planes_for_stream(struct dc *dc,
}
if (dc->hwss.program_front_end_for_ctx && update_type != UPDATE_TYPE_FAST) {
dc->hwss.program_front_end_for_ctx(dc, context);
-#ifdef CONFIG_DRM_AMD_DC_DCN
if (dc->debug.validate_dml_output) {
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *cur_pipe = &context->res_ctx.pipe_ctx[i];
@@ -3006,7 +3005,6 @@ static void commit_planes_for_stream(struct dc *dc,
&context->res_ctx.pipe_ctx[i].ttu_regs);
}
}
-#endif
}
// Update Type FAST, Surface updates
@@ -3056,10 +3054,11 @@ static void commit_planes_for_stream(struct dc *dc,
}
- if (should_lock_all_pipes && dc->hwss.interdependent_update_lock)
+ if (should_lock_all_pipes && dc->hwss.interdependent_update_lock) {
dc->hwss.interdependent_update_lock(dc, context, false);
- else
+ } else {
dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
+ }
if ((update_type != UPDATE_TYPE_FAST) && stream->update_flags.bits.dsc_changed)
if (top_pipe_to_program->stream_res.tg->funcs->lock_doublebuffer_enable) {
@@ -3297,9 +3296,8 @@ void dc_set_power_state(
case DC_ACPI_CM_POWER_STATE_D0:
dc_resource_state_construct(dc, dc->current_state);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
dc_z10_restore(dc);
-#endif
+
if (dc->ctx->dmub_srv)
dc_dmub_srv_wait_phy_init(dc->ctx->dmub_srv);
@@ -3359,6 +3357,19 @@ bool dc_is_dmcu_initialized(struct dc *dc)
return false;
}
+bool dc_is_oem_i2c_device_present(
+ struct dc *dc,
+ size_t slave_address)
+{
+ if (dc->res_pool->oem_device)
+ return dce_i2c_oem_device_present(
+ dc->res_pool,
+ dc->res_pool->oem_device,
+ slave_address);
+
+ return false;
+}
+
bool dc_submit_i2c(
struct dc *dc,
uint32_t link_index,
@@ -3548,8 +3559,6 @@ bool dc_set_psr_allow_active(struct dc *dc, bool enable)
return true;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-
void dc_allow_idle_optimizations(struct dc *dc, bool allow)
{
if (dc->debug.disable_idle_power_optimizations)
@@ -3705,27 +3714,77 @@ void dc_hardware_release(struct dc *dc)
if (dc->hwss.hardware_release)
dc->hwss.hardware_release(dc);
}
-#endif
-/**
- * dc_enable_dmub_notifications - Returns whether dmub notification can be enabled
- * @dc: dc structure
+/*
+ *****************************************************************************
+ * Function: dc_is_dmub_outbox_supported -
+ *
+ * @brief
+ * Checks whether DMUB FW supports outbox notifications, if supported
+ * DM should register outbox interrupt prior to actually enabling interrupts
+ * via dc_enable_dmub_outbox
*
- * Returns: True to enable dmub notifications, False otherwise
+ * @param
+ * [in] dc: dc structure
+ *
+ * @return
+ * True if DMUB FW supports outbox notifications, False otherwise
+ *****************************************************************************
*/
-bool dc_enable_dmub_notifications(struct dc *dc)
+bool dc_is_dmub_outbox_supported(struct dc *dc)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- /* YELLOW_CARP B0 USB4 DPIA needs dmub notifications for interrupts */
+ /* DCN31 B0 USB4 DPIA needs dmub notifications for interrupts */
if (dc->ctx->asic_id.chip_family == FAMILY_YELLOW_CARP &&
dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0 &&
!dc->debug.dpia_debug.bits.disable_dpia)
return true;
-#endif
+
/* dmub aux needs dmub notifications to be enabled */
return dc->debug.enable_dmub_aux_for_legacy_ddc;
}
+/*
+ *****************************************************************************
+ * Function: dc_enable_dmub_notifications
+ *
+ * @brief
+ * Calls dc_is_dmub_outbox_supported to check if dmub fw supports outbox
+ * notifications. All DMs shall switch to dc_is_dmub_outbox_supported.
+ * This API shall be removed after switching.
+ *
+ * @param
+ * [in] dc: dc structure
+ *
+ * @return
+ * True if DMUB FW supports outbox notifications, False otherwise
+ *****************************************************************************
+ */
+bool dc_enable_dmub_notifications(struct dc *dc)
+{
+ return dc_is_dmub_outbox_supported(dc);
+}
+
+/**
+ *****************************************************************************
+ * Function: dc_enable_dmub_outbox
+ *
+ * @brief
+ * Enables DMUB unsolicited notifications to x86 via outbox
+ *
+ * @param
+ * [in] dc: dc structure
+ *
+ * @return
+ * None
+ *****************************************************************************
+ */
+void dc_enable_dmub_outbox(struct dc *dc)
+{
+ struct dc_context *dc_ctx = dc->ctx;
+
+ dmub_enable_outbox_notification(dc_ctx->dmub_srv);
+}
+
/**
* dc_process_dmub_aux_transfer_async - Submits aux command to dmub via inbox message
* Sets port index appropriately for legacy DDC
@@ -3829,7 +3888,7 @@ uint8_t get_link_index_from_dpia_port_index(const struct dc *dc,
* [in] payload: aux payload
* [out] notify: set_config immediate reply
*
- * @return
+ * @return
* True if successful, False if failure
*****************************************************************************
*/
@@ -3982,3 +4041,17 @@ void dc_notify_vsync_int_state(struct dc *dc, struct dc_stream_state *stream, bo
if (pipe->stream_res.abm && pipe->stream_res.abm->funcs->set_abm_pause)
pipe->stream_res.abm->funcs->set_abm_pause(pipe->stream_res.abm, !enable, i, pipe->stream_res.tg->inst);
}
+/*
+ * dc_extended_blank_supported: Decide whether extended blank is supported
+ *
+ * Extended blank is a freesync optimization feature to be enabled in the future.
+ * During the extra vblank period gained from freesync, we have the ability to enter z9/z10.
+ *
+ * @param [in] dc: Current DC state
+ * @return: Indicate whether extended blank is supported (true or false)
+ */
+bool dc_extended_blank_supported(struct dc *dc)
+{
+ return dc->debug.extended_blank_optimization && !dc->debug.disable_z10
+ && dc->caps.zstate_support && dc->caps.is_apu;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
index 643762542e4d..72376075db0c 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_debug.c
@@ -345,7 +345,6 @@ void context_clock_trace(
struct dc *dc,
struct dc_state *context)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DC_LOGGER_INIT(dc->ctx->logger);
CLOCK_TRACE("Current: dispclk_khz:%d max_dppclk_khz:%d dcfclk_khz:%d\n"
"dcfclk_deep_sleep_khz:%d fclk_khz:%d socclk_khz:%d\n",
@@ -363,7 +362,6 @@ void context_clock_trace(
context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz,
context->bw_ctx.bw.dcn.clk.fclk_khz,
context->bw_ctx.bw.dcn.clk.socclk_khz);
-#endif
}
/**
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
index b5e570d33ca9..a789ea8af27f 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c
@@ -33,6 +33,7 @@
#include "gpio_service_interface.h"
#include "core_status.h"
#include "dc_link_dp.h"
+#include "dc_link_dpia.h"
#include "dc_link_ddc.h"
#include "link_hwss.h"
#include "opp.h"
@@ -50,6 +51,7 @@
#include "inc/hw/panel_cntl.h"
#include "inc/link_enc_cfg.h"
#include "inc/link_dpcd.h"
+#include "link/link_dp_trace.h"
#include "dc/dcn30/dcn30_vpg.h"
@@ -239,7 +241,7 @@ bool dc_link_detect_sink(struct dc_link *link, enum dc_connection_type *type)
/* Link may not have physical HPD pin. */
if (link->ep_type != DISPLAY_ENDPOINT_PHY) {
- if (link->is_hpd_pending || !link->hpd_status)
+ if (link->is_hpd_pending || !dc_link_dpia_query_hpd_status(link))
*type = dc_connection_none;
else
*type = dc_connection_single;
@@ -344,6 +346,7 @@ static enum signal_type get_basic_signal_type(struct graphics_object_id encoder,
case CONNECTOR_ID_LVDS:
return SIGNAL_TYPE_LVDS;
case CONNECTOR_ID_DISPLAY_PORT:
+ case CONNECTOR_ID_USBC:
return SIGNAL_TYPE_DISPLAY_PORT;
case CONNECTOR_ID_EDP:
return SIGNAL_TYPE_EDP;
@@ -379,7 +382,8 @@ bool dc_link_is_dp_sink_present(struct dc_link *link)
bool present =
((connector_id == CONNECTOR_ID_DISPLAY_PORT) ||
- (connector_id == CONNECTOR_ID_EDP));
+ (connector_id == CONNECTOR_ID_EDP) ||
+ (connector_id == CONNECTOR_ID_USBC));
ddc = dal_ddc_service_get_ddc_pin(link->ddc);
@@ -475,7 +479,8 @@ static enum signal_type link_detect_sink(struct dc_link *link,
result = SIGNAL_TYPE_DVI_SINGLE_LINK;
}
break;
- case CONNECTOR_ID_DISPLAY_PORT: {
+ case CONNECTOR_ID_DISPLAY_PORT:
+ case CONNECTOR_ID_USBC: {
/* DP HPD short pulse. Passive DP dongle will not
* have short pulse
*/
@@ -720,35 +725,8 @@ static bool detect_dp(struct dc_link *link,
sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT;
if (!detect_dp_sink_caps(link))
return false;
- if (is_mst_supported(link)) {
- sink_caps->signal = SIGNAL_TYPE_DISPLAY_PORT_MST;
- link->type = dc_connection_mst_branch;
-
- dal_ddc_service_set_transaction_type(link->ddc,
- sink_caps->transaction_type);
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- /* Apply work around for tunneled MST on certain USB4 docks. Always use DSC if dock
- * reports DSC support.
- */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
- link->type == dc_connection_mst_branch &&
- link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
- link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&
- !link->dc->debug.dpia_debug.bits.disable_mst_dsc_work_around)
- link->wa_flags.dpia_mst_dsc_always_on = true;
-#endif
-
-#if defined(CONFIG_DRM_AMD_DC_HDCP)
- /* In case of fallback to SST when topology discovery below fails
- * HDCP caps will be querried again later by the upper layer (caller
- * of this function). */
- query_hdcp_capability(SIGNAL_TYPE_DISPLAY_PORT_MST, link);
-#endif
- }
- if (link->type != dc_connection_mst_branch &&
- is_dp_branch_device(link))
+ if (is_dp_branch_device(link))
/* DP SST branch */
link->type = dc_connection_sst_branch;
} else {
@@ -757,6 +735,7 @@ static bool detect_dp(struct dc_link *link,
sink_caps,
audio_support);
link->dpcd_caps.dongle_type = sink_caps->dongle_type;
+ link->dpcd_caps.is_dongle_type_one = sink_caps->is_dongle_type_one;
link->dpcd_caps.dpcd_rev.raw = 0;
}
@@ -824,15 +803,209 @@ static bool wait_for_entering_dp_alt_mode(struct dc_link *link)
return false;
}
-/*
- * dc_link_detect() - Detect if a sink is attached to a given link
+static void apply_dpia_mst_dsc_always_on_wa(struct dc_link *link)
+{
+ /* Apply work around for tunneled MST on certain USB4 docks. Always use DSC if dock
+ * reports DSC support.
+ */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ link->type == dc_connection_mst_branch &&
+ link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
+ link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_20 &&
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT &&
+ !link->dc->debug.dpia_debug.bits.disable_mst_dsc_work_around)
+ link->wa_flags.dpia_mst_dsc_always_on = true;
+}
+
+static void revert_dpia_mst_dsc_always_on_wa(struct dc_link *link)
+{
+ /* Disable work around which keeps DSC on for tunneled MST on certain USB4 docks. */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ link->wa_flags.dpia_mst_dsc_always_on = false;
+}
+
+static bool discover_dp_mst_topology(struct dc_link *link, enum dc_detect_reason reason)
+{
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ LINK_INFO("link=%d, mst branch is now Connected\n",
+ link->link_index);
+
+ apply_dpia_mst_dsc_always_on_wa(link);
+ link->type = dc_connection_mst_branch;
+ dm_helpers_dp_update_branch_info(link->ctx, link);
+ if (dm_helpers_dp_mst_start_top_mgr(link->ctx,
+ link, (reason == DETECT_REASON_BOOT || reason == DETECT_REASON_RESUMEFROMS3S4))) {
+ link_disconnect_sink(link);
+ } else {
+ link->type = dc_connection_sst_branch;
+ }
+
+ return link->type == dc_connection_mst_branch;
+}
+
+static bool reset_cur_dp_mst_topology(struct dc_link *link)
+{
+ bool result = false;
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ LINK_INFO("link=%d, mst branch is now Disconnected\n",
+ link->link_index);
+
+ revert_dpia_mst_dsc_always_on_wa(link);
+ result = dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
+
+ link->mst_stream_alloc_table.stream_count = 0;
+ memset(link->mst_stream_alloc_table.stream_allocations,
+ 0,
+ sizeof(link->mst_stream_alloc_table.stream_allocations));
+ return result;
+}
+
+static bool should_prepare_phy_clocks_for_link_verification(const struct dc *dc,
+ enum dc_detect_reason reason)
+{
+ int i;
+ bool can_apply_seamless_boot = false;
+
+ for (i = 0; i < dc->current_state->stream_count; i++) {
+ if (dc->current_state->streams[i]->apply_seamless_boot_optimization) {
+ can_apply_seamless_boot = true;
+ break;
+ }
+ }
+
+ return !can_apply_seamless_boot && reason != DETECT_REASON_BOOT;
+}
+
+static void prepare_phy_clocks_for_destructive_link_verification(const struct dc *dc)
+{
+ dc_z10_restore(dc);
+ clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr);
+}
+
+static void restore_phy_clocks_for_destructive_link_verification(const struct dc *dc)
+{
+ clk_mgr_optimize_pwr_state(dc, dc->clk_mgr);
+}
+
+static void set_all_streams_dpms_off_for_link(struct dc_link *link)
+{
+ int i;
+ struct pipe_ctx *pipe_ctx;
+ struct dc_stream_update stream_update;
+ bool dpms_off = true;
+ struct link_resource link_res = {0};
+
+ memset(&stream_update, 0, sizeof(stream_update));
+ stream_update.dpms_off = &dpms_off;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
+ if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
+ pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) {
+ stream_update.stream = pipe_ctx->stream;
+ dc_commit_updates_for_stream(link->ctx->dc, NULL, 0,
+ pipe_ctx->stream, &stream_update,
+ link->ctx->dc->current_state);
+ }
+ }
+
+ /* link can be also enabled by vbios. In this case it is not recorded
+ * in pipe_ctx. Disable link phy here to make sure it is completely off
+ */
+ dp_disable_link_phy(link, &link_res, link->connector_signal);
+}
+
+static void verify_link_capability_destructive(struct dc_link *link,
+ struct dc_sink *sink,
+ enum dc_detect_reason reason)
+{
+ bool should_prepare_phy_clocks =
+ should_prepare_phy_clocks_for_link_verification(link->dc, reason);
+
+ if (should_prepare_phy_clocks)
+ prepare_phy_clocks_for_destructive_link_verification(link->dc);
+
+ if (dc_is_dp_signal(link->local_sink->sink_signal)) {
+ struct dc_link_settings known_limit_link_setting =
+ dp_get_max_link_cap(link);
+ set_all_streams_dpms_off_for_link(link);
+ dp_verify_link_cap_with_retries(
+ link, &known_limit_link_setting,
+ LINK_TRAINING_MAX_VERIFY_RETRY);
+ } else {
+ ASSERT(0);
+ }
+
+ if (should_prepare_phy_clocks)
+ restore_phy_clocks_for_destructive_link_verification(link->dc);
+}
+
+static void verify_link_capability_non_destructive(struct dc_link *link)
+{
+ if (dc_is_dp_signal(link->local_sink->sink_signal)) {
+ if (dc_is_embedded_signal(link->local_sink->sink_signal) ||
+ link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ /* TODO - should we check link encoder's max link caps here?
+ * How do we know which link encoder to check from?
+ */
+ link->verified_link_cap = link->reported_link_cap;
+ else
+ link->verified_link_cap = dp_get_max_link_cap(link);
+ }
+}
+
+static bool should_verify_link_capability_destructively(struct dc_link *link,
+ enum dc_detect_reason reason)
+{
+ bool destrictive = false;
+ struct dc_link_settings max_link_cap;
+ bool is_link_enc_unavailable = link->link_enc &&
+ link->dc->res_pool->funcs->link_encs_assign &&
+ !link_enc_cfg_is_link_enc_avail(
+ link->ctx->dc,
+ link->link_enc->preferred_engine,
+ link);
+
+ if (dc_is_dp_signal(link->local_sink->sink_signal)) {
+ max_link_cap = dp_get_max_link_cap(link);
+ destrictive = true;
+
+ if (link->dc->debug.skip_detection_link_training ||
+ dc_is_embedded_signal(link->local_sink->sink_signal) ||
+ link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
+ destrictive = false;
+ } else if (dp_get_link_encoding_format(&max_link_cap) ==
+ DP_8b_10b_ENCODING) {
+ if (link->dpcd_caps.is_mst_capable ||
+ is_link_enc_unavailable) {
+ destrictive = false;
+ }
+ }
+ }
+
+ return destrictive;
+}
+
+static void verify_link_capability(struct dc_link *link, struct dc_sink *sink,
+ enum dc_detect_reason reason)
+{
+ if (should_verify_link_capability_destructively(link, reason))
+ verify_link_capability_destructive(link, sink, reason);
+ else
+ verify_link_capability_non_destructive(link);
+}
+
+
+/**
+ * detect_link_and_local_sink() - Detect if a sink is attached to a given link
*
* link->local_sink is created or destroyed as needed.
*
- * This does not create remote sinks but will trigger DM
- * to start MST detection if a branch is detected.
+ * This does not create remote sinks.
*/
-static bool dc_link_detect_helper(struct dc_link *link,
+static bool detect_link_and_local_sink(struct dc_link *link,
enum dc_detect_reason reason)
{
struct dc_sink_init_data sink_init_data = { 0 };
@@ -848,9 +1021,7 @@ static bool dc_link_detect_helper(struct dc_link *link,
struct dpcd_caps prev_dpcd_caps;
enum dc_connection_type new_connection_type = dc_connection_none;
enum dc_connection_type pre_connection_type = dc_connection_none;
- bool perform_dp_seamless_boot = false;
const uint32_t post_oui_delay = 30; // 30ms
- struct link_resource link_res = { 0 };
DC_LOGGER_INIT(link->ctx->logger);
@@ -862,7 +1033,8 @@ static bool dc_link_detect_helper(struct dc_link *link,
(!link->dc->config.allow_edp_hotplug_detection)) &&
link->local_sink) {
// need to re-write OUI and brightness in resume case
- if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ if (link->connector_signal == SIGNAL_TYPE_EDP &&
+ (link->dpcd_sink_ext_caps.bits.oled == 1)) {
dpcd_set_source_specific_data(link);
msleep(post_oui_delay);
dc_link_set_default_brightness_aux(link);
@@ -943,61 +1115,6 @@ static bool dc_link_detect_helper(struct dc_link *link,
return false;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(&link->reported_link_cap) == DP_128b_132b_ENCODING)
- link_res.hpo_dp_link_enc = resource_get_hpo_dp_link_enc_for_det_lt(
- &link->dc->current_state->res_ctx,
- link->dc->res_pool,
- link);
-#endif
-
- if (link->type == dc_connection_mst_branch) {
- LINK_INFO("link=%d, mst branch is now Connected\n",
- link->link_index);
- /* Need to setup mst link_cap struct here
- * otherwise dc_link_detect() will leave mst link_cap
- * empty which leads to allocate_mst_payload() has "0"
- * pbn_per_slot value leading to exception on dc_fixpt_div()
- */
- dp_verify_mst_link_cap(link, &link_res);
-
- /*
- * This call will initiate MST topology discovery. Which
- * will detect MST ports and add new DRM connector DRM
- * framework. Then read EDID via remote i2c over aux. In
- * the end, will notify DRM detect result and save EDID
- * into DRM framework.
- *
- * .detect is called by .fill_modes.
- * .fill_modes is called by user mode ioctl
- * DRM_IOCTL_MODE_GETCONNECTOR.
- *
- * .get_modes is called by .fill_modes.
- *
- * call .get_modes, AMDGPU DM implementation will create
- * new dc_sink and add to dc_link. For long HPD plug
- * in/out, MST has its own handle.
- *
- * Therefore, just after dc_create, link->sink is not
- * created for MST until user mode app calls
- * DRM_IOCTL_MODE_GETCONNECTOR.
- *
- * Need check ->sink usages in case ->sink = NULL
- * TODO: s3 resume check
- */
-
- dm_helpers_dp_update_branch_info(link->ctx, link);
- if (dm_helpers_dp_mst_start_top_mgr(link->ctx,
- link, reason == DETECT_REASON_BOOT)) {
- if (prev_sink)
- dc_sink_release(prev_sink);
- return false;
- } else {
- link->type = dc_connection_sst_branch;
- sink_caps.signal = SIGNAL_TYPE_DISPLAY_PORT;
- }
- }
-
/* Active SST downstream branch device unplug*/
if (link->type == dc_connection_sst_branch &&
link->dpcd_caps.sink_count.bits.SINK_COUNT == 0) {
@@ -1018,19 +1135,6 @@ static bool dc_link_detect_helper(struct dc_link *link,
if (pre_connection_type == dc_connection_mst_branch &&
link->type != dc_connection_mst_branch)
dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
-
-
- // For seamless boot, to skip verify link cap, we read UEFI settings and set them as verified.
- if (reason == DETECT_REASON_BOOT &&
- !dc_ctx->dc->config.power_down_display_on_boot &&
- link->link_status.link_active)
- perform_dp_seamless_boot = true;
-
- if (perform_dp_seamless_boot) {
- read_current_link_settings_on_detect(link);
- link->verified_link_cap = link->reported_link_cap;
- }
-
break;
}
@@ -1078,6 +1182,9 @@ static bool dc_link_detect_helper(struct dc_link *link,
case EDID_BAD_CHECKSUM:
DC_LOG_ERROR("EDID checksum invalid.\n");
break;
+ case EDID_PARTIAL_VALID:
+ DC_LOG_ERROR("Partial EDID valid, abandon invalid blocks.\n");
+ break;
case EDID_NO_RESPONSE:
DC_LOG_ERROR("No EDID read.\n");
/*
@@ -1095,6 +1202,22 @@ static bool dc_link_detect_helper(struct dc_link *link,
return false;
}
+
+ if (link->type == dc_connection_sst_branch &&
+ link->dpcd_caps.dongle_type ==
+ DISPLAY_DONGLE_DP_VGA_CONVERTER &&
+ reason == DETECT_REASON_HPDRX) {
+ /* Abort detection for DP-VGA adapters when EDID
+ * can't be read and detection reason is VGA-side
+ * hotplug
+ */
+ if (prev_sink)
+ dc_sink_release(prev_sink);
+ link_disconnect_sink(link);
+
+ return true;
+ }
+
break;
default:
break;
@@ -1119,13 +1242,6 @@ static bool dc_link_detect_helper(struct dc_link *link,
#if defined(CONFIG_DRM_AMD_DC_HDCP)
query_hdcp_capability(sink->sink_signal, link);
#endif
-
- // verify link cap for SST non-seamless boot
- if (!perform_dp_seamless_boot)
- dp_verify_link_cap_with_retries(link,
- &link_res,
- &link->reported_link_cap,
- LINK_TRAINING_MAX_VERIFY_RETRY);
} else {
// If edid is the same, then discard new sink and revert back to original sink
if (same_edid) {
@@ -1143,6 +1259,9 @@ static bool dc_link_detect_helper(struct dc_link *link,
!sink->edid_caps.edid_hdmi)
sink->sink_signal = SIGNAL_TYPE_DVI_SINGLE_LINK;
+ if (link->local_sink && dc_is_dp_signal(sink_caps.signal))
+ dp_trace_init(link);
+
/* Connectivity log: detection */
for (i = 0; i < sink->dc_edid.length / DC_EDID_BLOCK_SIZE; i++) {
CONN_DATA_DETECT(link,
@@ -1185,27 +1304,6 @@ static bool dc_link_detect_helper(struct dc_link *link,
}
} else {
/* From Connected-to-Disconnected. */
- if (link->type == dc_connection_mst_branch) {
- LINK_INFO("link=%d, mst branch is now Disconnected\n",
- link->link_index);
-
- /* Disable work around which keeps DSC on for tunneled MST on certain USB4 docks. */
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
- link->wa_flags.dpia_mst_dsc_always_on = false;
-
- dm_helpers_dp_mst_stop_top_mgr(link->ctx, link);
-
- link->mst_stream_alloc_table.stream_count = 0;
- memset(link->mst_stream_alloc_table.stream_allocations,
- 0,
- sizeof(link->mst_stream_alloc_table.stream_allocations));
- }
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
- reset_dp_hpo_stream_encoders_for_link(link);
-#endif
-
link->type = dc_connection_none;
sink_caps.signal = SIGNAL_TYPE_NONE;
/* When we unplug a passive DP-HDMI dongle connection, dongle_max_pix_clk
@@ -1214,6 +1312,9 @@ static bool dc_link_detect_helper(struct dc_link *link,
* Clear dongle_max_pix_clk on disconnect to fix this
*/
link->dongle_max_pix_clk = 0;
+
+ dc_link_clear_dprx_states(link);
+ dp_trace_reset(link);
}
LINK_INFO("link=%d, dc_sink_in=%p is now %s prev_sink=%p edid same=%d\n",
@@ -1230,33 +1331,26 @@ static bool dc_link_detect_helper(struct dc_link *link,
bool dc_link_detect(struct dc_link *link, enum dc_detect_reason reason)
{
- const struct dc *dc = link->dc;
- bool ret;
- bool can_apply_seamless_boot = false;
- int i;
-
- for (i = 0; i < dc->current_state->stream_count; i++) {
- if (dc->current_state->streams[i]->apply_seamless_boot_optimization) {
- can_apply_seamless_boot = true;
- break;
- }
- }
+ bool is_local_sink_detect_success;
+ bool is_delegated_to_mst_top_mgr = false;
+ enum dc_connection_type pre_link_type = link->type;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- dc_z10_restore(dc);
-#endif
+ is_local_sink_detect_success = detect_link_and_local_sink(link, reason);
- /* get out of low power state */
- if (!can_apply_seamless_boot && reason != DETECT_REASON_BOOT)
- clk_mgr_exit_optimized_pwr_state(dc, dc->clk_mgr);
+ if (is_local_sink_detect_success && link->local_sink)
+ verify_link_capability(link, link->local_sink, reason);
- ret = dc_link_detect_helper(link, reason);
+ if (is_local_sink_detect_success && link->local_sink &&
+ dc_is_dp_signal(link->local_sink->sink_signal) &&
+ link->dpcd_caps.is_mst_capable)
+ is_delegated_to_mst_top_mgr = discover_dp_mst_topology(link, reason);
- /* Go back to power optimized state */
- if (!can_apply_seamless_boot && reason != DETECT_REASON_BOOT)
- clk_mgr_optimize_pwr_state(dc, dc->clk_mgr);
+ if (is_local_sink_detect_success &&
+ pre_link_type == dc_connection_mst_branch &&
+ link->type != dc_connection_mst_branch)
+ is_delegated_to_mst_top_mgr = reset_cur_dp_mst_topology(link);
- return ret;
+ return is_local_sink_detect_success && !is_delegated_to_mst_top_mgr;
}
bool dc_link_get_hpd_state(struct dc_link *dc_link)
@@ -1497,6 +1591,7 @@ static bool dc_link_construct_legacy(struct dc_link *link,
link->connector_signal = SIGNAL_TYPE_DVI_DUAL_LINK;
break;
case CONNECTOR_ID_DISPLAY_PORT:
+ case CONNECTOR_ID_USBC:
link->connector_signal = SIGNAL_TYPE_DISPLAY_PORT;
if (link->hpd_gpio)
@@ -1510,8 +1605,25 @@ static bool dc_link_construct_legacy(struct dc_link *link,
if (link->hpd_gpio) {
if (!link->dc->config.allow_edp_hotplug_detection)
link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
- link->irq_source_hpd_rx =
- dal_irq_get_rx_source(link->hpd_gpio);
+
+ switch (link->dc->config.allow_edp_hotplug_detection) {
+ case 1: // only the 1st eDP handles hotplug
+ if (link->link_index == 0)
+ link->irq_source_hpd_rx =
+ dal_irq_get_rx_source(link->hpd_gpio);
+ else
+ link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
+ break;
+ case 2: // only the 2nd eDP handles hotplug
+ if (link->link_index == 1)
+ link->irq_source_hpd_rx =
+ dal_irq_get_rx_source(link->hpd_gpio);
+ else
+ link->irq_source_hpd = DC_IRQ_SOURCE_INVALID;
+ break;
+ default:
+ break;
+ }
}
break;
@@ -1586,9 +1698,7 @@ static bool dc_link_construct_legacy(struct dc_link *link,
}
DC_LOG_DC("BIOS object table - DP_IS_USB_C: %d", link->link_enc->features.flags.bits.DP_IS_USB_C);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DC_LOG_DC("BIOS object table - IS_DP2_CAPABLE: %d", link->link_enc->features.flags.bits.IS_DP2_CAPABLE);
-#endif
/* Update link encoder tracking variables. These are used for the dynamic
* assignment of link encoders to streams.
@@ -1871,7 +1981,6 @@ static enum dc_status enable_link_dp(struct dc_state *state,
if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
do_fallback = true;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/*
* Temporary w/a to get DP2.0 link rates to work with SST.
* TODO DP2.0 - Workaround: Remove w/a if and when the issue is resolved.
@@ -1881,7 +1990,6 @@ static enum dc_status enable_link_dp(struct dc_state *state,
link->dc->debug.set_mst_en_for_sst) {
dp_enable_mst_on_sink(link, true);
}
-#endif
if (pipe_ctx->stream->signal == SIGNAL_TYPE_EDP) {
/*in case it is not on*/
@@ -1889,7 +1997,6 @@ static enum dc_status enable_link_dp(struct dc_state *state,
link->dc->hwss.edp_wait_for_hpd_ready(link, true);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(&link_settings) == DP_128b_132b_ENCODING) {
/* TODO - DP2.0 HW: calculate 32 symbol clock for HPO encoder */
} else {
@@ -1899,19 +2006,15 @@ static enum dc_status enable_link_dp(struct dc_state *state,
state->clk_mgr->funcs->update_clocks(state->clk_mgr,
state, false);
}
-#else
- pipe_ctx->stream_res.pix_clk_params.requested_sym_clk =
- link_settings.link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
- if (state->clk_mgr && !apply_seamless_boot_optimization)
- state->clk_mgr->funcs->update_clocks(state->clk_mgr,
- state, false);
-#endif
// during mode switch we do DP_SET_POWER off then on, and OUI is lost
dpcd_set_source_specific_data(link);
if (link->dpcd_sink_ext_caps.raw != 0)
msleep(post_oui_delay);
+ // similarly, mode switch can cause loss of cable ID
+ dpcd_write_cable_id_to_dprx(link);
+
skip_video_pattern = true;
if (link_settings.link_rate == LINK_RATE_LOW)
@@ -1934,12 +2037,8 @@ static enum dc_status enable_link_dp(struct dc_state *state,
else
fec_enable = true;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING)
dp_set_fec_enable(link, fec_enable);
-#else
- dp_set_fec_enable(link, fec_enable);
-#endif
// during mode set we do DP_SET_POWER off then on, aux writes are lost
if (link->dpcd_sink_ext_caps.bits.oled == 1 ||
@@ -2495,9 +2594,7 @@ static void disable_link(struct dc_link *link, const struct link_resource *link_
if (dc_is_dp_signal(signal)) {
/* SST DP, eDP */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_link_settings link_settings = link->cur_link_settings;
-#endif
if (dc_is_dp_sst_signal(signal))
dp_disable_link_phy(link, link_res, signal);
else
@@ -2505,15 +2602,10 @@ static void disable_link(struct dc_link *link, const struct link_resource *link_
if (dc_is_dp_sst_signal(signal) ||
link->mst_stream_alloc_table.stream_count == 0) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING) {
dp_set_fec_enable(link, false);
dp_set_fec_ready(link, link_res, false);
}
-#else
- dp_set_fec_enable(link, false);
- dp_set_fec_ready(link, link_res, false);
-#endif
}
} else {
if (signal != SIGNAL_TYPE_VIRTUAL)
@@ -2696,72 +2788,74 @@ static bool dp_active_dongle_validate_timing(
break;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dpcd_caps->dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER &&
dongle_caps->extendedCapValid == true) {
-#else
- if (dpcd_caps->dongle_type != DISPLAY_DONGLE_DP_HDMI_CONVERTER ||
- dongle_caps->extendedCapValid == false)
- return true;
-#endif
-
- /* Check Pixel Encoding */
- switch (timing->pixel_encoding) {
- case PIXEL_ENCODING_RGB:
- case PIXEL_ENCODING_YCBCR444:
- break;
- case PIXEL_ENCODING_YCBCR422:
- if (!dongle_caps->is_dp_hdmi_ycbcr422_pass_through)
- return false;
- break;
- case PIXEL_ENCODING_YCBCR420:
- if (!dongle_caps->is_dp_hdmi_ycbcr420_pass_through)
+ /* Check Pixel Encoding */
+ switch (timing->pixel_encoding) {
+ case PIXEL_ENCODING_RGB:
+ case PIXEL_ENCODING_YCBCR444:
+ break;
+ case PIXEL_ENCODING_YCBCR422:
+ if (!dongle_caps->is_dp_hdmi_ycbcr422_pass_through)
+ return false;
+ break;
+ case PIXEL_ENCODING_YCBCR420:
+ if (!dongle_caps->is_dp_hdmi_ycbcr420_pass_through)
+ return false;
+ break;
+ default:
+ /* Invalid Pixel Encoding*/
return false;
- break;
- default:
- /* Invalid Pixel Encoding*/
- return false;
- }
+ }
- switch (timing->display_color_depth) {
- case COLOR_DEPTH_666:
- case COLOR_DEPTH_888:
- /*888 and 666 should always be supported*/
- break;
- case COLOR_DEPTH_101010:
- if (dongle_caps->dp_hdmi_max_bpc < 10)
+ switch (timing->display_color_depth) {
+ case COLOR_DEPTH_666:
+ case COLOR_DEPTH_888:
+ /*888 and 666 should always be supported*/
+ break;
+ case COLOR_DEPTH_101010:
+ if (dongle_caps->dp_hdmi_max_bpc < 10)
+ return false;
+ break;
+ case COLOR_DEPTH_121212:
+ if (dongle_caps->dp_hdmi_max_bpc < 12)
+ return false;
+ break;
+ case COLOR_DEPTH_141414:
+ case COLOR_DEPTH_161616:
+ default:
+ /* These color depths are currently not supported */
return false;
- break;
- case COLOR_DEPTH_121212:
- if (dongle_caps->dp_hdmi_max_bpc < 12)
+ }
+
+ /* Check 3D format */
+ switch (timing->timing_3d_format) {
+ case TIMING_3D_FORMAT_NONE:
+ case TIMING_3D_FORMAT_FRAME_ALTERNATE:
+ /*Only frame alternate 3D is supported on active dongle*/
+ break;
+ default:
+ /*other 3D formats are not supported due to bad infoframe translation */
return false;
- break;
- case COLOR_DEPTH_141414:
- case COLOR_DEPTH_161616:
- default:
- /* These color depths are currently not supported */
- return false;
- }
+ }
#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter
- struct dc_crtc_timing outputTiming = *timing;
+ if (dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps > 0) { // DP to HDMI FRL converter
+ struct dc_crtc_timing outputTiming = *timing;
- if (timing->flags.DSC && !timing->dsc_cfg.is_frl)
- /* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */
- outputTiming.flags.DSC = 0;
- if (dc_bandwidth_in_kbps_from_timing(&outputTiming) > dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps)
- return false;
- } else { // DP to HDMI TMDS converter
+ if (timing->flags.DSC && !timing->dsc_cfg.is_frl)
+ /* DP input has DSC, HDMI FRL output doesn't have DSC, remove DSC from output timing */
+ outputTiming.flags.DSC = 0;
+ if (dc_bandwidth_in_kbps_from_timing(&outputTiming) > dongle_caps->dp_hdmi_frl_max_link_bw_in_kbps)
+ return false;
+ } else { // DP to HDMI TMDS converter
+ if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
+ return false;
+ }
+#else
if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
return false;
- }
-#else
- if (get_timing_pixel_clock_100hz(timing) > (dongle_caps->dp_hdmi_max_pixel_clk_in_khz * 10))
- return false;
#endif
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
}
if (dpcd_caps->channel_coding_cap.bits.DP_128b_132b_SUPPORTED == 0 &&
@@ -2842,7 +2936,6 @@ static bool dp_active_dongle_validate_timing(
return false;
}
}
-#endif
return true;
}
@@ -3000,6 +3093,11 @@ bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active
if (!dc_get_edp_link_panel_inst(dc, link, &panel_inst))
return false;
+ if (allow_active && link->type == dc_connection_none) {
+ // Don't enter PSR if panel is not connected
+ return false;
+ }
+
/* Set power optimization flag */
if (power_opts && link->psr_settings.psr_power_opt != *power_opts) {
link->psr_settings.psr_power_opt = *power_opts;
@@ -3008,18 +3106,18 @@ bool dc_link_set_psr_allow_active(struct dc_link *link, const bool *allow_active
psr->funcs->psr_set_power_opt(psr, link->psr_settings.psr_power_opt, panel_inst);
}
+ if (psr != NULL && link->psr_settings.psr_feature_enabled &&
+ force_static && psr->funcs->psr_force_static)
+ psr->funcs->psr_force_static(psr, panel_inst);
+
/* Enable or Disable PSR */
if (allow_active && link->psr_settings.psr_allow_active != *allow_active) {
link->psr_settings.psr_allow_active = *allow_active;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (!link->psr_settings.psr_allow_active)
dc_z10_restore(dc);
-#endif
if (psr != NULL && link->psr_settings.psr_feature_enabled) {
- if (force_static && psr->funcs->psr_force_static)
- psr->funcs->psr_force_static(psr, panel_inst);
psr->funcs->psr_enable(psr, link->psr_settings.psr_allow_active, wait, panel_inst);
} else if ((dmcu != NULL && dmcu->funcs->is_dmcu_initialized(dmcu)) &&
link->psr_settings.psr_feature_enabled)
@@ -3197,9 +3295,16 @@ bool dc_link_setup_psr(struct dc_link *link,
/*skip power down the single pipe since it blocks the cstate*/
#if defined(CONFIG_DRM_AMD_DC_DCN)
if (link->ctx->asic_id.chip_family >= FAMILY_RV) {
- psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
- if (link->ctx->asic_id.chip_family == FAMILY_YELLOW_CARP && !dc->debug.disable_z10)
- psr_context->psr_level.bits.SKIP_CRTC_DISABLE = false;
+ switch(link->ctx->asic_id.chip_family) {
+ case FAMILY_YELLOW_CARP:
+ case AMDGPU_FAMILY_GC_10_3_6:
+ if(!dc->debug.disable_z10)
+ psr_context->psr_level.bits.SKIP_CRTC_DISABLE = false;
+ break;
+ default:
+ psr_context->psr_level.bits.SKIP_CRTC_DISABLE = true;
+ break;
+ }
}
#else
if (link->ctx->asic_id.chip_family >= FAMILY_RV)
@@ -3224,9 +3329,12 @@ bool dc_link_setup_psr(struct dc_link *link,
*/
psr_context->frame_delay = 0;
- if (psr)
+ if (psr) {
link->psr_settings.psr_feature_enabled = psr->funcs->psr_copy_settings(psr,
link, psr_context, panel_inst);
+ link->psr_settings.psr_power_opt = 0;
+ link->psr_settings.psr_allow_active = 0;
+ }
else
link->psr_settings.psr_feature_enabled = dmcu->funcs->setup_psr(dmcu, link, psr_context);
@@ -3315,9 +3423,7 @@ static struct fixed31_32 get_pbn_from_timing(struct pipe_ctx *pipe_ctx)
static void update_mst_stream_alloc_table(
struct dc_link *link,
struct stream_encoder *stream_enc,
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct hpo_dp_stream_encoder *hpo_dp_stream_enc, // TODO: Rename stream_enc to dio_stream_enc?
-#endif
const struct dp_mst_stream_allocation_table *proposed_table)
{
struct link_mst_stream_allocation work_table[MAX_CONTROLLER_NUM] = { 0 };
@@ -3353,9 +3459,7 @@ static void update_mst_stream_alloc_table(
work_table[i].slot_count =
proposed_table->stream_allocations[i].slot_count;
work_table[i].stream_enc = stream_enc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
work_table[i].hpo_dp_stream_enc = hpo_dp_stream_enc;
-#endif
}
}
@@ -3366,7 +3470,7 @@ static void update_mst_stream_alloc_table(
link->mst_stream_alloc_table.stream_allocations[i] =
work_table[i];
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+
static void dc_log_vcp_x_y(const struct dc_link *link, struct fixed31_32 avg_time_slots_per_mtp)
{
const uint32_t VCP_Y_PRECISION = 1000;
@@ -3398,10 +3502,10 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx,
{
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link;
- struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc;
- struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc;
struct link_mst_stream_allocation_table proposed_table = {0};
struct fixed31_32 avg_time_slots_per_mtp;
+ const struct dc_link_settings empty_link_settings = {0};
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
DC_LOGGER_INIT(link->ctx->logger);
/* slot X.Y for SST payload deallocate */
@@ -3410,10 +3514,13 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx,
dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
- hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
- hpo_dp_link_encoder,
- hpo_dp_stream_encoder->inst,
- avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx,
+ avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &empty_link_settings,
+ avg_time_slots_per_mtp);
}
/* calculate VC payload and update branch with new payload allocation table*/
@@ -3428,7 +3535,7 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx,
pipe_ctx->pipe_idx);
}
- proposed_table.stream_allocations[0].hpo_dp_stream_enc = hpo_dp_stream_encoder;
+ proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
ASSERT(proposed_table.stream_count == 1);
@@ -3441,8 +3548,7 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx,
proposed_table.stream_allocations[0].slot_count);
/* program DP source TX for payload */
- hpo_dp_link_encoder->funcs->update_stream_allocation_table(
- hpo_dp_link_encoder,
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
&proposed_table);
/* poll for ACT handled */
@@ -3452,15 +3558,19 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx,
}
/* slot X.Y for SST payload allocate */
- if (allocate) {
+ if (allocate && dp_get_link_encoding_format(&link->cur_link_settings) ==
+ DP_128b_132b_ENCODING) {
avg_time_slots_per_mtp = calculate_sst_avg_time_slots_per_mtp(stream, link);
dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
- hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
- hpo_dp_link_encoder,
- hpo_dp_stream_encoder->inst,
- avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx,
+ avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &link->cur_link_settings,
+ avg_time_slots_per_mtp);
}
/* Always return DC_OK.
@@ -3468,7 +3578,6 @@ static enum dc_status dc_link_update_sst_payload(struct pipe_ctx *pipe_ctx,
*/
return DC_OK;
}
-#endif
/* convert link_mst_stream_alloc_table to dm dp_mst_stream_alloc_table
* because stream_encoder is not exposed to dm
@@ -3477,27 +3586,15 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
{
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link;
- struct link_encoder *link_encoder = NULL;
- struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc;
- struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc;
-#endif
struct dp_mst_stream_allocation_table proposed_table = {0};
struct fixed31_32 avg_time_slots_per_mtp;
struct fixed31_32 pbn;
struct fixed31_32 pbn_per_slot;
int i;
enum act_return_status ret;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
DC_LOGGER_INIT(link->ctx->logger);
- /* Link encoder may have been dynamically assigned to non-physical display endpoint. */
- if (link->ep_type == DISPLAY_ENDPOINT_PHY)
- link_encoder = link->link_enc;
- else if (link->dc->res_pool->funcs->link_encs_assign)
- link_encoder = link_enc_cfg_get_link_enc_used_by_stream(pipe_ctx->stream->ctx->dc, stream);
- ASSERT(link_encoder);
-
/* enable_link_dp_mst already check link->enabled_stream_count
* and stream is in link->stream[]. This is called during set mode,
* stream_enc is available.
@@ -3508,17 +3605,12 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
stream->ctx,
stream,
&proposed_table,
- true)) {
+ true))
update_mst_stream_alloc_table(
-#if defined(CONFIG_DRM_AMD_DC_DCN)
link,
pipe_ctx->stream_res.stream_enc,
pipe_ctx->stream_res.hpo_dp_stream_enc,
&proposed_table);
-#else
- link, pipe_ctx->stream_res.stream_enc, &proposed_table);
-#endif
- }
else
DC_LOG_WARNING("Failed to update"
"MST allocation table for"
@@ -3531,7 +3623,6 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
link->mst_stream_alloc_table.stream_count);
for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DC_LOG_MST("stream_enc[%d]: %p "
"stream[%d].hpo_dp_stream_enc: %p "
"stream[%d].vcp_id: %d "
@@ -3544,57 +3635,20 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
i,
link->mst_stream_alloc_table.stream_allocations[i].slot_count);
-#else
- DC_LOG_MST("stream_enc[%d]: %p "
- "stream[%d].vcp_id: %d "
- "stream[%d].slot_count: %d\n",
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].slot_count);
-#endif
}
ASSERT(proposed_table.stream_count > 0);
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
- static enum dc_status status;
- uint8_t mst_alloc_slots = 0, prev_mst_slots_in_use = 0xFF;
-
- for (i = 0; i < link->mst_stream_alloc_table.stream_count; i++)
- mst_alloc_slots += link->mst_stream_alloc_table.stream_allocations[i].slot_count;
-
- status = dc_process_dmub_set_mst_slots(link->dc, link->link_index,
- mst_alloc_slots, &prev_mst_slots_in_use);
- ASSERT(status == DC_OK);
- DC_LOG_MST("dpia : status[%d]: alloc_slots[%d]: used_slots[%d]\n",
- status, mst_alloc_slots, prev_mst_slots_in_use);
- }
-
/* program DP source TX for payload */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- switch (dp_get_link_encoding_format(&link->cur_link_settings)) {
- case DP_8b_10b_ENCODING:
- link_encoder->funcs->update_mst_stream_allocation_table(
- link_encoder,
- &link->mst_stream_alloc_table);
- break;
- case DP_128b_132b_ENCODING:
- hpo_dp_link_encoder->funcs->update_stream_allocation_table(
- hpo_dp_link_encoder,
- &link->mst_stream_alloc_table);
- break;
- case DP_UNKNOWN_ENCODING:
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
DC_LOG_ERROR("Failure: unknown encoding format\n");
return DC_ERROR_UNEXPECTED;
}
-#else
- link_encoder->funcs->update_mst_stream_allocation_table(
- link_encoder,
- &link->mst_stream_alloc_table);
-#endif
+
+ link_hwss->ext.update_stream_allocation_table(link,
+ &pipe_ctx->link_res,
+ &link->mst_stream_alloc_table);
/* send down message */
ret = dm_helpers_dp_mst_poll_for_allocation_change_trigger(
@@ -3617,34 +3671,19 @@ enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx)
pbn = get_pbn_from_timing(pipe_ctx);
avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- switch (dp_get_link_encoding_format(&link->cur_link_settings)) {
- case DP_8b_10b_ENCODING:
- stream_encoder->funcs->set_throttled_vcp_size(
- stream_encoder,
- avg_time_slots_per_mtp);
- break;
- case DP_128b_132b_ENCODING:
- hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
- hpo_dp_link_encoder,
- hpo_dp_stream_encoder->inst,
+ dc_log_vcp_x_y(link, avg_time_slots_per_mtp);
+
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &link->cur_link_settings,
avg_time_slots_per_mtp);
- break;
- case DP_UNKNOWN_ENCODING:
- DC_LOG_ERROR("Failure: unknown encoding format\n");
- return DC_ERROR_UNEXPECTED;
- }
-#else
- stream_encoder->funcs->set_throttled_vcp_size(
- stream_encoder,
- avg_time_slots_per_mtp);
-#endif
return DC_OK;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw_in_kbps)
{
struct dc_stream_state *stream = pipe_ctx->stream;
@@ -3652,11 +3691,10 @@ enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw
struct fixed31_32 avg_time_slots_per_mtp;
struct fixed31_32 pbn;
struct fixed31_32 pbn_per_slot;
- struct link_encoder *link_encoder = link->link_enc;
- struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
struct dp_mst_stream_allocation_table proposed_table = {0};
uint8_t i;
enum act_return_status ret;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
DC_LOGGER_INIT(link->ctx->logger);
/* decrease throttled vcp size */
@@ -3664,8 +3702,11 @@ enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw
pbn = get_pbn_from_bw_in_kbps(bw_in_kbps);
avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
- stream_encoder->funcs->set_throttled_vcp_size(
- stream_encoder,
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &link->cur_link_settings,
avg_time_slots_per_mtp);
/* send ALLOCATE_PAYLOAD sideband message with updated pbn */
@@ -3713,8 +3754,13 @@ enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t bw
ASSERT(proposed_table.stream_count > 0);
/* update mst stream allocation table hardware state */
- link_encoder->funcs->update_mst_stream_allocation_table(
- link_encoder,
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
+ DC_LOG_ERROR("Failure: unknown encoding format\n");
+ return DC_ERROR_UNEXPECTED;
+ }
+
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
&link->mst_stream_alloc_table);
/* poll for immediate branch device ACT handled */
@@ -3733,10 +3779,10 @@ enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t
struct fixed31_32 pbn;
struct fixed31_32 pbn_per_slot;
struct link_encoder *link_encoder = link->link_enc;
- struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
struct dp_mst_stream_allocation_table proposed_table = {0};
uint8_t i;
enum act_return_status ret;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
DC_LOGGER_INIT(link->ctx->logger);
/* notify immediate branch device table update */
@@ -3795,37 +3841,28 @@ enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t
pbn_per_slot = get_pbn_per_slot(stream);
avg_time_slots_per_mtp = dc_fixpt_div(pbn, pbn_per_slot);
- stream_encoder->funcs->set_throttled_vcp_size(
- stream_encoder,
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &link->cur_link_settings,
avg_time_slots_per_mtp);
return DC_OK;
}
-#endif
static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
{
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link;
- struct link_encoder *link_encoder = NULL;
- struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- struct hpo_dp_link_encoder *hpo_dp_link_encoder = pipe_ctx->link_res.hpo_dp_link_enc;
- struct hpo_dp_stream_encoder *hpo_dp_stream_encoder = pipe_ctx->stream_res.hpo_dp_stream_enc;
-#endif
struct dp_mst_stream_allocation_table proposed_table = {0};
struct fixed31_32 avg_time_slots_per_mtp = dc_fixpt_from_int(0);
int i;
bool mst_mode = (link->type == dc_connection_mst_branch);
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ const struct dc_link_settings empty_link_settings = {0};
DC_LOGGER_INIT(link->ctx->logger);
- /* Link encoder may have been dynamically assigned to non-physical display endpoint. */
- if (link->ep_type == DISPLAY_ENDPOINT_PHY)
- link_encoder = link->link_enc;
- else if (link->dc->res_pool->funcs->link_encs_assign)
- link_encoder = link_enc_cfg_get_link_enc_used_by_stream(pipe_ctx->stream->ctx->dc, stream);
- ASSERT(link_encoder);
-
/* deallocate_mst_payload is called before disable link. When mode or
* disable/enable monitor, new stream is created which is not in link
* stream[] yet. For this, payload is not allocated yet, so de-alloc
@@ -3834,28 +3871,12 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
*/
/* slot X.Y */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- switch (dp_get_link_encoding_format(&link->cur_link_settings)) {
- case DP_8b_10b_ENCODING:
- stream_encoder->funcs->set_throttled_vcp_size(
- stream_encoder,
- avg_time_slots_per_mtp);
- break;
- case DP_128b_132b_ENCODING:
- hpo_dp_link_encoder->funcs->set_throttled_vcp_size(
- hpo_dp_link_encoder,
- hpo_dp_stream_encoder->inst,
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
+ if (link_hwss->ext.set_hblank_min_symbol_width)
+ link_hwss->ext.set_hblank_min_symbol_width(pipe_ctx,
+ &empty_link_settings,
avg_time_slots_per_mtp);
- break;
- case DP_UNKNOWN_ENCODING:
- DC_LOG_ERROR("Failure: unknown encoding format\n");
- return DC_ERROR_UNEXPECTED;
- }
-#else
- stream_encoder->funcs->set_throttled_vcp_size(
- stream_encoder,
- avg_time_slots_per_mtp);
-#endif
/* TODO: which component is responsible for remove payload table? */
if (mst_mode) {
@@ -3865,16 +3886,11 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
&proposed_table,
false)) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
update_mst_stream_alloc_table(
link,
pipe_ctx->stream_res.stream_enc,
pipe_ctx->stream_res.hpo_dp_stream_enc,
&proposed_table);
-#else
- update_mst_stream_alloc_table(
- link, pipe_ctx->stream_res.stream_enc, &proposed_table);
-#endif
}
else {
DC_LOG_WARNING("Failed to update"
@@ -3890,7 +3906,6 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
link->mst_stream_alloc_table.stream_count);
for (i = 0; i < MAX_CONTROLLER_NUM; i++) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DC_LOG_MST("stream_enc[%d]: %p "
"stream[%d].hpo_dp_stream_enc: %p "
"stream[%d].vcp_id: %d "
@@ -3903,54 +3918,17 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
i,
link->mst_stream_alloc_table.stream_allocations[i].slot_count);
-#else
- DC_LOG_MST("stream_enc[%d]: %p "
- "stream[%d].vcp_id: %d "
- "stream[%d].slot_count: %d\n",
- i,
- (void *) link->mst_stream_alloc_table.stream_allocations[i].stream_enc,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].vcp_id,
- i,
- link->mst_stream_alloc_table.stream_allocations[i].slot_count);
-#endif
}
- if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
- enum dc_status status;
- uint8_t mst_alloc_slots = 0, prev_mst_slots_in_use = 0xFF;
-
- for (i = 0; i < link->mst_stream_alloc_table.stream_count; i++)
- mst_alloc_slots += link->mst_stream_alloc_table.stream_allocations[i].slot_count;
-
- status = dc_process_dmub_set_mst_slots(link->dc, link->link_index,
- mst_alloc_slots, &prev_mst_slots_in_use);
- ASSERT(status != DC_NOT_SUPPORTED);
- DC_LOG_MST("dpia : status[%d]: alloc_slots[%d]: used_slots[%d]\n",
- status, mst_alloc_slots, prev_mst_slots_in_use);
+ /* update mst stream allocation table hardware state */
+ if (link_hwss->ext.update_stream_allocation_table == NULL ||
+ dp_get_link_encoding_format(&link->cur_link_settings) == DP_UNKNOWN_ENCODING) {
+ DC_LOG_DEBUG("Unknown encoding format\n");
+ return DC_ERROR_UNEXPECTED;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- switch (dp_get_link_encoding_format(&link->cur_link_settings)) {
- case DP_8b_10b_ENCODING:
- link_encoder->funcs->update_mst_stream_allocation_table(
- link_encoder,
+ link_hwss->ext.update_stream_allocation_table(link, &pipe_ctx->link_res,
&link->mst_stream_alloc_table);
- break;
- case DP_128b_132b_ENCODING:
- hpo_dp_link_encoder->funcs->update_stream_allocation_table(
- hpo_dp_link_encoder,
- &link->mst_stream_alloc_table);
- break;
- case DP_UNKNOWN_ENCODING:
- DC_LOG_ERROR("Failure: unknown encoding format\n");
- return DC_ERROR_UNEXPECTED;
- }
-#else
- link_encoder->funcs->update_mst_stream_allocation_table(
- link_encoder,
- &link->mst_stream_alloc_table);
-#endif
if (mst_mode) {
dm_helpers_dp_mst_poll_for_allocation_change_trigger(
@@ -3979,13 +3957,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
if (cp_psp == NULL || cp_psp->funcs.update_stream_config == NULL)
return;
- if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY)
- link_enc = pipe_ctx->stream->link->link_enc;
- else if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
- pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_stream(
- pipe_ctx->stream->ctx->dc,
- pipe_ctx->stream);
+ link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
ASSERT(link_enc);
if (link_enc == NULL)
return;
@@ -3998,23 +3970,24 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
/* stream encoder index */
config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx))
config.stream_enc_idx =
pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0;
-#endif
/* dig back end */
config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst;
/* link encoder index */
config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx))
config.link_enc_idx = pipe_ctx->link_res.hpo_dp_link_enc->inst;
-#endif
- /* dio output index */
- config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
+
+ /* dio output index is dpia index for DPIA endpoint & dcio index by default */
+ if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA)
+ config.dio_output_idx = pipe_ctx->stream->link->link_id.enum_id - ENUM_ID_1;
+ else
+ config.dio_output_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
+
/* phy index */
config.phy_idx = resource_transmitter_to_phy_idx(
@@ -4027,9 +4000,7 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
config.assr_enabled = (panel_mode == DP_PANEL_MODE_EDP) ? 1 : 0;
config.mst_enabled = (pipe_ctx->stream->signal ==
SIGNAL_TYPE_DISPLAY_PORT_MST) ? 1 : 0;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
config.dp2_enabled = is_dp_128b_132b_signal(pipe_ctx) ? 1 : 0;
-#endif
config.usb4_enabled = (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) ?
1 : 0;
config.dpms_off = dpms_off;
@@ -4041,7 +4012,6 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
}
#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pipe_ctx *pipe_ctx)
{
struct dc *dc = pipe_ctx->stream->ctx->dc;
@@ -4050,15 +4020,17 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi
struct fixed31_32 avg_time_slots_per_mtp;
uint8_t req_slot_count = 0;
uint8_t vc_id = 1; /// VC ID always 1 for SST
-
struct dc_link_settings link_settings = {0};
+ const struct link_hwss *link_hwss = get_link_hwss(stream->link, &pipe_ctx->link_res);
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
decide_link_settings(stream, &link_settings);
stream->link->cur_link_settings = link_settings;
- /* Enable clock, Configure lane count, and Enable Link Encoder*/
- enable_dp_hpo_output(stream->link, &pipe_ctx->link_res, &stream->link->cur_link_settings);
+ if (link_hwss->ext.enable_dp_link_output)
+ link_hwss->ext.enable_dp_link_output(stream->link, &pipe_ctx->link_res,
+ stream->signal, pipe_ctx->clock_source->id,
+ &link_settings);
#ifdef DIAGS_BUILD
/* Workaround for FPGA HPO capture DP link data:
@@ -4108,20 +4080,15 @@ static void fpga_dp_hpo_enable_link_and_stream(struct dc_state *state, struct pi
proposed_table.stream_allocations[0].hpo_dp_stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
}
- pipe_ctx->link_res.hpo_dp_link_enc->funcs->update_stream_allocation_table(
- pipe_ctx->link_res.hpo_dp_link_enc,
+ link_hwss->ext.update_stream_allocation_table(stream->link,
+ &pipe_ctx->link_res,
&proposed_table);
- pipe_ctx->link_res.hpo_dp_link_enc->funcs->set_throttled_vcp_size(
- pipe_ctx->link_res.hpo_dp_link_enc,
- pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
- avg_time_slots_per_mtp);
-
-
+ if (link_hwss->ext.set_throttled_vcp_size)
+ link_hwss->ext.set_throttled_vcp_size(pipe_ctx, avg_time_slots_per_mtp);
dc->hwss.unblank_stream(pipe_ctx, &stream->link->cur_link_settings);
}
-#endif
void core_link_enable_stream(
struct dc_state *state,
@@ -4132,96 +4099,50 @@ void core_link_enable_stream(
struct dc_link *link = stream->sink->link;
enum dc_status status;
struct link_encoder *link_enc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum otg_out_mux_dest otg_out_dest = OUT_MUX_DIO;
struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
if (is_dp_128b_132b_signal(pipe_ctx))
vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
-#endif
+
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+ if (pipe_ctx->stream->sink) {
+ if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+ pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
+ DC_LOG_DC("%s pipe_ctx dispname=%s signal=%x\n", __func__,
+ pipe_ctx->stream->sink->edid_caps.display_name,
+ pipe_ctx->stream->signal);
+ }
+ }
+
if (!IS_DIAG_DC(dc->ctx->dce_environment) &&
dc_is_virtual_signal(pipe_ctx->stream->signal))
return;
- if (dc->res_pool->funcs->link_encs_assign && stream->link->ep_type != DISPLAY_ENDPOINT_PHY)
- link_enc = link_enc_cfg_get_link_enc_used_by_stream(dc, stream);
- else
- link_enc = stream->link->link_enc;
+ link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
&& !is_dp_128b_132b_signal(pipe_ctx)) {
-#else
- if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) {
-#endif
if (link_enc)
link_enc->funcs->setup(
link_enc,
pipe_ctx->stream->signal);
- pipe_ctx->stream_res.stream_enc->funcs->setup_stereo_sync(
- pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.tg->inst,
- stream->timing.timing_3d_format != TIMING_3D_FORMAT_NONE);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (is_dp_128b_132b_signal(pipe_ctx)) {
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->set_stream_attribute(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- &stream->timing,
- stream->output_color_space,
- stream->use_vsc_sdp_for_colorimetry,
- stream->timing.flags.DSC,
- false);
- otg_out_dest = OUT_MUX_HPO_DP;
- } else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(
- pipe_ctx->stream_res.stream_enc,
- &stream->timing,
- stream->output_color_space,
- stream->use_vsc_sdp_for_colorimetry,
- stream->link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
- }
-#else
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_stream_attribute(
- pipe_ctx->stream_res.stream_enc,
- &stream->timing,
- stream->output_color_space,
- stream->use_vsc_sdp_for_colorimetry,
- stream->link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
-#endif
-
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
-
- if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal))
- pipe_ctx->stream_res.stream_enc->funcs->hdmi_set_stream_attribute(
- pipe_ctx->stream_res.stream_enc,
- &stream->timing,
- stream->phy_pix_clk,
- pipe_ctx->stream_res.audio != NULL);
-
pipe_ctx->stream->link->link_state_valid = true;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (pipe_ctx->stream_res.tg->funcs->set_out_mux)
+ if (pipe_ctx->stream_res.tg->funcs->set_out_mux) {
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ otg_out_dest = OUT_MUX_HPO_DP;
+ else
+ otg_out_dest = OUT_MUX_DIO;
pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, otg_out_dest);
-#endif
-
- if (dc_is_dvi_signal(pipe_ctx->stream->signal))
- pipe_ctx->stream_res.stream_enc->funcs->dvi_set_stream_attribute(
- pipe_ctx->stream_res.stream_enc,
- &stream->timing,
- (pipe_ctx->stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
- true : false);
+ }
- if (dc_is_lvds_signal(pipe_ctx->stream->signal))
- pipe_ctx->stream_res.stream_enc->funcs->lvds_set_stream_attribute(
- pipe_ctx->stream_res.stream_enc,
- &stream->timing);
+ link_hwss->setup_stream_attribute(pipe_ctx);
if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
bool apply_edp_fast_boot_optimization =
@@ -4229,11 +4150,9 @@ void core_link_enable_stream(
pipe_ctx->stream->apply_edp_fast_boot_optimization = false;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
// Enable VPG before building infoframe
if (vpg && vpg->funcs->vpg_poweron)
vpg->funcs->vpg_poweron(vpg);
-#endif
resource_build_info_frame(pipe_ctx);
dc->hwss.update_info_frame(pipe_ctx);
@@ -4319,12 +4238,8 @@ void core_link_enable_stream(
* as a workaround for the incorrect value being applied
* from transmitter control.
*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (!(dc_is_virtual_signal(pipe_ctx->stream->signal) ||
is_dp_128b_132b_signal(pipe_ctx)))
-#else
- if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
-#endif
if (link_enc)
link_enc->funcs->setup(
link_enc,
@@ -4343,11 +4258,9 @@ void core_link_enable_stream(
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
dc_link_allocate_mst_payload(pipe_ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
is_dp_128b_132b_signal(pipe_ctx))
dc_link_update_sst_payload(pipe_ctx, true);
-#endif
dc->hwss.unblank_stream(pipe_ctx,
&pipe_ctx->stream->link->cur_link_settings);
@@ -4364,15 +4277,11 @@ void core_link_enable_stream(
dc->hwss.enable_audio_stream(pipe_ctx);
} else { // if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (is_dp_128b_132b_signal(pipe_ctx)) {
+ if (is_dp_128b_132b_signal(pipe_ctx))
fpga_dp_hpo_enable_link_and_stream(state, pipe_ctx);
- }
-#endif
if (dc_is_dp_signal(pipe_ctx->stream->signal) ||
dc_is_virtual_signal(pipe_ctx->stream->signal))
dp_set_dsc_enable(pipe_ctx, true);
-
}
if (pipe_ctx->stream->signal == SIGNAL_TYPE_HDMI_TYPE_A) {
@@ -4385,12 +4294,21 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
struct dc *dc = pipe_ctx->stream->ctx->dc;
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->sink->link;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct vpg *vpg = pipe_ctx->stream_res.stream_enc->vpg;
if (is_dp_128b_132b_signal(pipe_ctx))
vpg = pipe_ctx->stream_res.hpo_dp_stream_enc->vpg;
-#endif
+
+ DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+
+ if (pipe_ctx->stream->sink) {
+ if (pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+ pipe_ctx->stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
+ DC_LOG_DC("%s pipe_ctx dispname=%s signal=%x\n", __func__,
+ pipe_ctx->stream->sink->edid_caps.display_name,
+ pipe_ctx->stream->signal);
+ }
+ }
if (!IS_DIAG_DC(dc->ctx->dce_environment) &&
dc_is_virtual_signal(pipe_ctx->stream->signal))
@@ -4410,11 +4328,9 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT_MST)
deallocate_mst_payload(pipe_ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
else if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
is_dp_128b_132b_signal(pipe_ctx))
dc_link_update_sst_payload(pipe_ctx, false);
-#endif
if (dc_is_hdmi_signal(pipe_ctx->stream->signal)) {
struct ext_hdmi_settings settings = {0};
@@ -4441,7 +4357,6 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
}
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (pipe_ctx->stream->signal == SIGNAL_TYPE_DISPLAY_PORT &&
!is_dp_128b_132b_signal(pipe_ctx)) {
@@ -4458,27 +4373,18 @@ void core_link_disable_stream(struct pipe_ctx *pipe_ctx)
dc->hwss.disable_stream(pipe_ctx);
disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
}
-#else
- disable_link(pipe_ctx->stream->link, &pipe_ctx->link_res, pipe_ctx->stream->signal);
-
- dc->hwss.disable_stream(pipe_ctx);
-#endif
if (pipe_ctx->stream->timing.flags.DSC) {
if (dc_is_dp_signal(pipe_ctx->stream->signal))
dp_set_dsc_enable(pipe_ctx, false);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx)) {
if (pipe_ctx->stream_res.tg->funcs->set_out_mux)
pipe_ctx->stream_res.tg->funcs->set_out_mux(pipe_ctx->stream_res.tg, OUT_MUX_DIO);
}
-#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (vpg && vpg->funcs->vpg_powerdown)
vpg->funcs->vpg_powerdown(vpg);
-#endif
}
void core_link_set_avmute(struct pipe_ctx *pipe_ctx, bool enable)
@@ -4542,22 +4448,17 @@ void dc_link_set_drive_settings(struct dc *dc,
{
int i;
- struct pipe_ctx *pipe = NULL;
- const struct link_resource *link_res;
+ struct link_resource link_res;
- link_res = dc_link_get_cur_link_res(link);
+ for (i = 0; i < dc->link_count; i++)
+ if (dc->links[i] == link)
+ break;
- for (i = 0; i < MAX_PIPES; i++) {
- pipe = &dc->current_state->res_ctx.pipe_ctx[i];
- if (pipe->stream && pipe->stream->link) {
- if (pipe->stream->link == link)
- break;
- }
- }
- if (pipe && link_res)
- dc_link_dp_set_drive_settings(pipe->stream->link, link_res, lt_settings);
- else
+ if (i >= dc->link_count)
ASSERT_CRITICAL(false);
+
+ dc_link_get_cur_link_res(link, &link_res);
+ dc_link_dp_set_drive_settings(dc->links[i], &link_res, lt_settings);
}
void dc_link_set_preferred_link_settings(struct dc *dc,
@@ -4617,11 +4518,9 @@ void dc_link_set_preferred_training_settings(struct dc *dc,
if (link_setting != NULL) {
link->preferred_link_setting = *link_setting;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(link_setting) == DP_128b_132b_ENCODING)
/* TODO: add dc update for acquiring link res */
skip_immediate_retrain = true;
-#endif
} else {
link->preferred_link_setting.lane_count = LANE_COUNT_UNKNOWN;
link->preferred_link_setting.link_rate = LINK_RATE_UNKNOWN;
@@ -4663,7 +4562,6 @@ uint32_t dc_link_bandwidth_kbps(
const struct dc_link *link,
const struct dc_link_settings *link_setting)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint32_t total_data_bw_efficiency_x10000 = 0;
uint32_t link_rate_per_lane_kbps = 0;
@@ -4694,40 +4592,6 @@ uint32_t dc_link_bandwidth_kbps(
/* overall effective link bandwidth = link rate per lane * lane count * total data bandwidth efficiency */
return link_rate_per_lane_kbps * link_setting->lane_count / 10000 * total_data_bw_efficiency_x10000;
-#else
- uint32_t link_bw_kbps =
- link_setting->link_rate * LINK_RATE_REF_FREQ_IN_KHZ; /* bytes per sec */
-
- link_bw_kbps *= 8; /* 8 bits per byte*/
- link_bw_kbps *= link_setting->lane_count;
-
- if (dc_link_should_enable_fec(link)) {
- /* Account for FEC overhead.
- * We have to do it based on caps,
- * and not based on FEC being set ready,
- * because FEC is set ready too late in
- * the process to correctly be picked up
- * by mode enumeration.
- *
- * There's enough zeros at the end of 'kbps'
- * that make the below operation 100% precise
- * for our purposes.
- * 'long long' makes it work even for HDMI 2.1
- * max bandwidth (and much, much bigger bandwidths
- * than that, actually).
- *
- * NOTE: Reducing link BW by 3% may not be precise
- * because it may be a stream BT that increases by 3%, and so
- * 1/1.03 = 0.970873 factor should have been used instead,
- * but the difference is minimal and is in a safe direction,
- * which all works well around potential ambiguity of DP 1.4a spec.
- */
- long long fec_link_bw_kbps = link_bw_kbps * 970LL;
- link_bw_kbps = (uint32_t)(div64_s64(fec_link_bw_kbps, 1000LL));
- }
- return link_bw_kbps;
-
-#endif
}
const struct dc_link_settings *dc_link_get_link_cap(
@@ -4752,16 +4616,7 @@ bool dc_link_is_fec_supported(const struct dc_link *link)
*/
struct link_encoder *link_enc = NULL;
- /* Links supporting dynamically assigned link encoder will be assigned next
- * available encoder if one not already assigned.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign) {
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- if (link_enc == NULL)
- link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc);
- } else
- link_enc = link->link_enc;
+ link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
return (dc_is_dp_signal(link->connector_signal) && link_enc &&
@@ -4772,22 +4627,22 @@ bool dc_link_is_fec_supported(const struct dc_link *link)
bool dc_link_should_enable_fec(const struct dc_link *link)
{
- bool is_fec_disable = false;
- bool ret = false;
+ bool force_disable = false;
- if ((link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST &&
+ if (link->fec_state == dc_link_fec_enabled)
+ force_disable = false;
+ else if (link->connector_signal != SIGNAL_TYPE_DISPLAY_PORT_MST &&
link->local_sink &&
- link->local_sink->edid_caps.panel_patch.disable_fec) ||
- (link->connector_signal == SIGNAL_TYPE_EDP
- // enable FEC for EDP if DSC is supported
- && link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT == false
- ))
- is_fec_disable = true;
-
- if (dc_link_is_fec_supported(link) && !link->dc->debug.disable_fec && !is_fec_disable)
- ret = true;
-
- return ret;
+ link->local_sink->edid_caps.panel_patch.disable_fec)
+ force_disable = true;
+ else if (link->connector_signal == SIGNAL_TYPE_EDP
+ && (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.
+ dsc_support.DSC_SUPPORT == false
+ || link->dc->debug.disable_dsc_edp
+ || !link->dc->caps.edp_dsc_support))
+ force_disable = true;
+
+ return !force_disable && dc_link_is_fec_supported(link);
}
uint32_t dc_bandwidth_in_kbps_from_timing(
@@ -4845,23 +4700,24 @@ uint32_t dc_bandwidth_in_kbps_from_timing(
}
-const struct link_resource *dc_link_get_cur_link_res(const struct dc_link *link)
+void dc_link_get_cur_link_res(const struct dc_link *link,
+ struct link_resource *link_res)
{
int i;
struct pipe_ctx *pipe = NULL;
- const struct link_resource *link_res = NULL;
+
+ memset(link_res, 0, sizeof(*link_res));
for (i = 0; i < MAX_PIPES; i++) {
pipe = &link->dc->current_state->res_ctx.pipe_ctx[i];
if (pipe->stream && pipe->stream->link && pipe->top_pipe == NULL) {
if (pipe->stream->link == link) {
- link_res = &pipe->link_res;
+ *link_res = pipe->link_res;
break;
}
}
}
- return link_res;
}
/**
@@ -4883,9 +4739,8 @@ const struct link_resource *dc_link_get_cur_link_res(const struct dc_link *link)
*/
void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_link *link;
- uint8_t i;
+ uint32_t i;
uint32_t hpo_dp_recycle_map = 0;
*map = 0;
@@ -4903,7 +4758,6 @@ void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map)
}
*map |= (hpo_dp_recycle_map << LINK_RES_HPO_DP_REC_MAP__SHIFT);
}
-#endif
}
/**
@@ -4926,9 +4780,8 @@ void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map)
*/
void dc_restore_link_res_map(const struct dc *dc, uint32_t *map)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_link *link;
- uint8_t i;
+ uint32_t i;
unsigned int available_hpo_dp_count;
uint32_t hpo_dp_recycle_map = (*map & LINK_RES_HPO_DP_REC_MAP__MASK)
>> LINK_RES_HPO_DP_REC_MAP__SHIFT;
@@ -4964,5 +4817,4 @@ void dc_restore_link_res_map(const struct dc *dc, uint32_t *map)
}
}
}
-#endif
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
index 24dc662ec3e4..2b09310965bc 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_ddc.c
@@ -298,6 +298,9 @@ static uint32_t defer_delay_converter_wa(
if (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER &&
link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 &&
+ (link->dpcd_caps.branch_fw_revision[0] < 0x01 ||
+ (link->dpcd_caps.branch_fw_revision[0] == 0x01 &&
+ link->dpcd_caps.branch_fw_revision[1] < 0x40)) &&
!memcmp(link->dpcd_caps.branch_dev_name,
DP_VGA_DONGLE_BRANCH_DEV_NAME,
sizeof(link->dpcd_caps.branch_dev_name)))
@@ -490,6 +493,7 @@ void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
sink_cap->max_hdmi_pixel_clock =
max_tmds_clk * 1000;
}
+ sink_cap->is_dongle_type_one = false;
} else {
if (is_valid_hdmi_signature == true) {
@@ -507,6 +511,7 @@ void dal_ddc_service_i2c_query_dp_dual_mode_adaptor(
"Type 1 DP-HDMI passive dongle (no signature) %dMhz: ",
sink_cap->max_hdmi_pixel_clock / 1000);
}
+ sink_cap->is_dongle_type_one = true;
}
return;
@@ -538,15 +543,9 @@ bool dal_ddc_service_query_ddc_data(
uint32_t payloads_num = write_payloads + read_payloads;
-
- if (write_size > EDID_SEGMENT_SIZE || read_size > EDID_SEGMENT_SIZE)
- return false;
-
if (!payloads_num)
return false;
- /*TODO: len of payload data for i2c and aux is uint8!!!!,
- * but we want to read 256 over i2c!!!!*/
if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) {
struct aux_payload payload;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
index 61b8f29a0c30..d8eee89e63ce 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
@@ -27,6 +27,7 @@
#include "dm_helpers.h"
#include "opp.h"
#include "dsc.h"
+#include "clk_mgr.h"
#include "resource.h"
#include "inc/core_types.h"
@@ -38,6 +39,7 @@
#include "dce/dmub_hw_lock_mgr.h"
#include "inc/dc_link_dpia.h"
#include "inc/link_enc_cfg.h"
+#include "link/link_dp_trace.h"
/*Travis*/
static const uint8_t DP_VGA_LVDS_CONVERTER_ID_2[] = "sivarT";
@@ -50,6 +52,13 @@ static const uint8_t DP_VGA_LVDS_CONVERTER_ID_3[] = "dnomlA";
#include "link_dpcd.h"
+#ifndef MAX
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+#endif
+#ifndef MIN
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
/* maximum pre emphasis level allowed for each voltage swing level*/
static const enum dc_pre_emphasis
voltage_swing_to_pre_emphasis[] = { PRE_EMPHASIS_LEVEL3,
@@ -62,7 +71,6 @@ enum {
POST_LT_ADJ_REQ_TIMEOUT = 200
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dp_lt_fallback_entry {
enum dc_lane_count lane_count;
enum dc_link_rate link_rate;
@@ -97,16 +105,18 @@ static const struct dp_lt_fallback_entry dp_lt_fallbacks[] = {
{LANE_COUNT_ONE, LINK_RATE_HIGH},
{LANE_COUNT_ONE, LINK_RATE_LOW},
};
-#endif
+
+static const struct dc_link_settings fail_safe_link_settings = {
+ .lane_count = LANE_COUNT_ONE,
+ .link_rate = LINK_RATE_LOW,
+ .link_spread = LINK_SPREAD_DISABLED,
+};
static bool decide_fallback_link_setting(
struct dc_link *link,
- struct dc_link_settings initial_link_settings,
- struct dc_link_settings *current_link_setting,
+ struct dc_link_settings *max,
+ struct dc_link_settings *cur,
enum link_training_result training_result);
-static struct dc_link_settings get_common_supported_link_settings(
- struct dc_link_settings link_setting_a,
- struct dc_link_settings link_setting_b);
static void maximize_lane_settings(const struct link_training_settings *lt_settings,
struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
static void override_lane_settings(const struct link_training_settings *lt_settings,
@@ -117,7 +127,7 @@ static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link,
{
union training_aux_rd_interval training_rd_interval;
uint32_t wait_in_micro_secs = 100;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+
memset(&training_rd_interval, 0, sizeof(training_rd_interval));
if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING &&
link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
@@ -129,15 +139,7 @@ static uint32_t get_cr_training_aux_rd_interval(struct dc_link *link,
if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
}
-#else
- core_link_read_dpcd(
- link,
- DP_TRAINING_AUX_RD_INTERVAL,
- (uint8_t *)&training_rd_interval,
- sizeof(training_rd_interval));
- if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
- wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
-#endif
+
return wait_in_micro_secs;
}
@@ -145,7 +147,6 @@ static uint32_t get_eq_training_aux_rd_interval(
struct dc_link *link,
const struct dc_link_settings *link_settings)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union training_aux_rd_interval training_rd_interval;
memset(&training_rd_interval, 0, sizeof(training_rd_interval));
@@ -174,41 +175,16 @@ static uint32_t get_eq_training_aux_rd_interval(
case 6: return 64000;
default: return 400;
}
-#else
- union training_aux_rd_interval training_rd_interval;
- uint32_t wait_in_micro_secs = 400;
-
- memset(&training_rd_interval, 0, sizeof(training_rd_interval));
- /* overwrite the delay if rev > 1.1*/
- if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_12) {
- /* DP 1.2 or later - retrieve delay through
- * "DPCD_ADDR_TRAINING_AUX_RD_INTERVAL" register */
- core_link_read_dpcd(
- link,
- DP_TRAINING_AUX_RD_INTERVAL,
- (uint8_t *)&training_rd_interval,
- sizeof(training_rd_interval));
-
- if (training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL)
- wait_in_micro_secs = training_rd_interval.bits.TRAINIG_AUX_RD_INTERVAL * 4000;
- }
-
- return wait_in_micro_secs;
-#endif
}
void dp_wait_for_training_aux_rd_interval(
struct dc_link *link,
uint32_t wait_in_micro_secs)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (wait_in_micro_secs > 1000)
msleep(wait_in_micro_secs/1000);
else
udelay(wait_in_micro_secs);
-#else
- udelay(wait_in_micro_secs);
-#endif
DC_LOG_HW_LINK_TRAINING("%s:\n wait = %d\n",
__func__,
@@ -236,7 +212,6 @@ enum dpcd_training_patterns
case DP_TRAINING_PATTERN_SEQUENCE_4:
dpcd_tr_pattern = DPCD_TRAINING_PATTERN_4;
break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case DP_128b_132b_TPS1:
dpcd_tr_pattern = DPCD_128b_132b_TPS1;
break;
@@ -246,7 +221,6 @@ enum dpcd_training_patterns
case DP_128b_132b_TPS2_CDS:
dpcd_tr_pattern = DPCD_128b_132b_TPS2_CDS;
break;
-#endif
case DP_TRAINING_PATTERN_VIDEOIDLE:
dpcd_tr_pattern = DPCD_TRAINING_PATTERN_VIDEOIDLE;
break;
@@ -289,10 +263,8 @@ static enum dc_dp_training_pattern decide_cr_training_pattern(
case DP_8b_10b_ENCODING:
default:
return DP_TRAINING_PATTERN_SEQUENCE_1;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case DP_128b_132b_ENCODING:
return DP_128b_132b_TPS1;
-#endif
}
}
@@ -300,19 +272,11 @@ static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *li
const struct dc_link_settings *link_settings)
{
struct link_encoder *link_enc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct encoder_feature_support *enc_caps;
struct dpcd_caps *rx_caps = &link->dpcd_caps;
enum dc_dp_training_pattern pattern = DP_TRAINING_PATTERN_SEQUENCE_2;
- /* Access link encoder capability based on whether it is statically
- * or dynamically assigned to a link.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- else
- link_enc = link->link_enc;
+ link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
enc_caps = &link_enc->features;
@@ -335,41 +299,8 @@ static enum dc_dp_training_pattern decide_eq_training_pattern(struct dc_link *li
break;
}
return pattern;
-#else
- enum dc_dp_training_pattern highest_tp = DP_TRAINING_PATTERN_SEQUENCE_2;
- struct encoder_feature_support *features;
- struct dpcd_caps *dpcd_caps = &link->dpcd_caps;
-
- /* Access link encoder capability based on whether it is statically
- * or dynamically assigned to a link.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- else
- link_enc = link->link_enc;
- ASSERT(link_enc);
- features = &link_enc->features;
-
- if (features->flags.bits.IS_TPS3_CAPABLE)
- highest_tp = DP_TRAINING_PATTERN_SEQUENCE_3;
-
- if (features->flags.bits.IS_TPS4_CAPABLE)
- highest_tp = DP_TRAINING_PATTERN_SEQUENCE_4;
-
- if (dpcd_caps->max_down_spread.bits.TPS4_SUPPORTED &&
- highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_4)
- return DP_TRAINING_PATTERN_SEQUENCE_4;
-
- if (dpcd_caps->max_ln_count.bits.TPS3_SUPPORTED &&
- highest_tp >= DP_TRAINING_PATTERN_SEQUENCE_3)
- return DP_TRAINING_PATTERN_SEQUENCE_3;
-
- return DP_TRAINING_PATTERN_SEQUENCE_2;
-#endif
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
{
uint8_t link_rate = 0;
@@ -397,7 +328,6 @@ static uint8_t get_dpcd_link_rate(const struct dc_link_settings *link_settings)
return link_rate;
}
-#endif
static void vendor_specific_lttpr_wa_one_start(struct dc_link *link)
{
@@ -418,29 +348,6 @@ static void vendor_specific_lttpr_wa_one_start(struct dc_link *link)
sizeof(vendor_lttpr_write_data));
}
-static void vendor_specific_lttpr_wa_one_end(
- struct dc_link *link,
- uint8_t retry_count)
-{
- const uint8_t vendor_lttpr_write_data[4] = {0x1, 0x50, 0x63, 0x0};
- const uint8_t offset = dp_convert_to_count(
- link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
- uint32_t vendor_lttpr_write_address = 0xF004F;
-
- if (!retry_count) {
- if (offset != 0xFF)
- vendor_lttpr_write_address +=
- ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
-
- /* W/A for certain LTTPR to reset their lane settings, part two of two */
- core_link_write_dpcd(
- link,
- vendor_lttpr_write_address,
- &vendor_lttpr_write_data[0],
- sizeof(vendor_lttpr_write_data));
- }
-}
-
static void vendor_specific_lttpr_wa_one_two(
struct dc_link *link,
const uint8_t rate)
@@ -467,9 +374,9 @@ static void vendor_specific_lttpr_wa_one_two(
}
}
-static void vendor_specific_lttpr_wa_three(
+static void dp_fixed_vs_pe_read_lane_adjust(
struct dc_link *link,
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX])
+ union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
{
const uint8_t vendor_lttpr_write_data_vs[3] = {0x0, 0x53, 0x63};
const uint8_t vendor_lttpr_write_data_pe[3] = {0x0, 0x54, 0x63};
@@ -511,23 +418,8 @@ static void vendor_specific_lttpr_wa_three(
1);
for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_LANE = (dprx_vs >> (2 * lane)) & 0x3;
- dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_LANE = (dprx_pe >> (2 * lane)) & 0x3;
- }
-}
-
-static void vendor_specific_lttpr_wa_three_dpcd(
- struct dc_link *link,
- union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX])
-{
- union lane_adjust lane_adjust[LANE_COUNT_DP_MAX];
- uint8_t lane = 0;
-
- vendor_specific_lttpr_wa_three(link, lane_adjust);
-
- for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
- dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = lane_adjust[lane].bits.VOLTAGE_SWING_LANE;
- dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = lane_adjust[lane].bits.PRE_EMPHASIS_LANE;
+ dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET = (dprx_vs >> (2 * lane)) & 0x3;
+ dpcd_lane_adjust[lane].bits.PRE_EMPHASIS_SET = (dprx_pe >> (2 * lane)) & 0x3;
}
}
@@ -540,10 +432,8 @@ static void vendor_specific_lttpr_wa_four(
const uint8_t offset = dp_convert_to_count(
link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
uint32_t vendor_lttpr_write_address = 0xF004F;
-#if defined(CONFIG_DRM_AMD_DC_DP2_0)
uint8_t sink_status = 0;
uint8_t i;
-#endif
if (offset != 0xFF)
vendor_lttpr_write_address +=
@@ -569,7 +459,6 @@ static void vendor_specific_lttpr_wa_four(
sizeof(vendor_lttpr_write_data_two));
}
-#if defined(CONFIG_DRM_AMD_DC_DP2_0)
/* poll for intra-hop disable */
for (i = 0; i < 10; i++) {
if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
@@ -577,20 +466,26 @@ static void vendor_specific_lttpr_wa_four(
break;
udelay(1000);
}
-#endif
}
-static void vendor_specific_lttpr_wa_five(
+static void dp_fixed_vs_pe_set_retimer_lane_settings(
struct dc_link *link,
const union dpcd_training_lane dpcd_lane_adjust[LANE_COUNT_DP_MAX],
uint8_t lane_count)
{
- const uint32_t vendor_lttpr_write_address = 0xF004F;
+ const uint8_t offset = dp_convert_to_count(
+ link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
const uint8_t vendor_lttpr_write_data_reset[4] = {0x1, 0x50, 0x63, 0xFF};
+ uint32_t vendor_lttpr_write_address = 0xF004F;
uint8_t vendor_lttpr_write_data_vs[4] = {0x1, 0x51, 0x63, 0x0};
uint8_t vendor_lttpr_write_data_pe[4] = {0x1, 0x52, 0x63, 0x0};
uint8_t lane = 0;
+ if (offset != 0xFF) {
+ vendor_lttpr_write_address +=
+ ((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
+ }
+
for (lane = 0; lane < lane_count; lane++) {
vendor_lttpr_write_data_vs[3] |=
dpcd_lane_adjust[lane].bits.VOLTAGE_SWING_SET << (2 * lane);
@@ -665,11 +560,7 @@ enum dc_status dpcd_set_link_settings(
status = core_link_write_dpcd(link, DP_LINK_RATE_SET,
&lt_settings->link_settings.link_rate_set, 1);
} else {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
rate = get_dpcd_link_rate(&lt_settings->link_settings);
-#else
- rate = (uint8_t) (lt_settings->link_settings.link_rate);
-#endif
if (link->dc->debug.apply_vendor_specific_lttpr_wa &&
(link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
link->lttpr_mode == LTTPR_MODE_TRANSPARENT)
@@ -720,10 +611,8 @@ uint8_t dc_dp_initialize_scrambling_data_symbols(
disable_scrabled_data_symbols = 1;
break;
case DP_TRAINING_PATTERN_SEQUENCE_4:
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case DP_128b_132b_TPS1:
case DP_128b_132b_TPS2:
-#endif
disable_scrabled_data_symbols = 0;
break;
default:
@@ -794,7 +683,6 @@ static void dpcd_set_lt_pattern_and_lane_settings(
size_in_bytes);
if (is_repeater(link, offset)) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_128b_132b_ENCODING)
DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
@@ -805,7 +693,6 @@ static void dpcd_set_lt_pattern_and_lane_settings(
lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_8b_10b_ENCODING)
-#endif
DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
" 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
__func__,
@@ -816,7 +703,6 @@ static void dpcd_set_lt_pattern_and_lane_settings(
lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
} else {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_128b_132b_ENCODING)
DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
@@ -825,14 +711,13 @@ static void dpcd_set_lt_pattern_and_lane_settings(
lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_8b_10b_ENCODING)
-#endif
- DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
- __func__,
- dpcd_base_lt_offset,
- lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
- lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
- lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
- lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
+ DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
+ __func__,
+ dpcd_base_lt_offset,
+ lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET,
+ lt_settings->dpcd_lane_settings[0].bits.PRE_EMPHASIS_SET,
+ lt_settings->dpcd_lane_settings[0].bits.MAX_SWING_REACHED,
+ lt_settings->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
}
if (edp_workaround) {
/* for eDP write in 2 parts because the 5-byte burst is
@@ -850,7 +735,6 @@ static void dpcd_set_lt_pattern_and_lane_settings(
(uint8_t *)(lt_settings->dpcd_lane_settings),
size_in_bytes);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
} else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_128b_132b_ENCODING) {
core_link_write_dpcd(
@@ -858,10 +742,9 @@ static void dpcd_set_lt_pattern_and_lane_settings(
dpcd_base_lt_offset,
dpcd_lt_buffer,
sizeof(dpcd_lt_buffer));
-#endif
- } else
+ } else
/* write it all in (1 + number-of-lanes)-byte burst*/
- core_link_write_dpcd(
+ core_link_write_dpcd(
link,
dpcd_base_lt_offset,
dpcd_lt_buffer,
@@ -910,7 +793,7 @@ bool dp_is_interlane_aligned(union lane_align_status_updated align_status)
void dp_hw_to_dpcd_lane_settings(
const struct link_training_settings *lt_settings,
const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
- union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
+ union dpcd_training_lane dpcd_lane_settings[])
{
uint8_t lane = 0;
@@ -928,13 +811,11 @@ void dp_hw_to_dpcd_lane_settings(
(hw_lane_settings[lane].PRE_EMPHASIS ==
PRE_EMPHASIS_MAX_LEVEL ? 1 : 0);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_128b_132b_ENCODING) {
dpcd_lane_settings[lane].tx_ffe.PRESET_VALUE =
hw_lane_settings[lane].FFE_PRESET.settings.level;
}
-#endif
}
}
@@ -942,7 +823,7 @@ void dp_decide_lane_settings(
const struct link_training_settings *lt_settings,
const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
- union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX])
+ union dpcd_training_lane dpcd_lane_settings[])
{
uint32_t lane;
@@ -956,13 +837,11 @@ void dp_decide_lane_settings(
(enum dc_pre_emphasis)(ln_adjust[lane].bits.
PRE_EMPHASIS_LANE);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
else if (dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_128b_132b_ENCODING) {
hw_lane_settings[lane].FFE_PRESET.raw =
ln_adjust[lane].tx_ffe.PRESET_VALUE;
}
-#endif
}
dp_hw_to_dpcd_lane_settings(lt_settings, hw_lane_settings, dpcd_lane_settings);
@@ -1013,9 +892,7 @@ static void maximize_lane_settings(const struct link_training_settings *lt_setti
max_requested.VOLTAGE_SWING = lane_settings[0].VOLTAGE_SWING;
max_requested.PRE_EMPHASIS = lane_settings[0].PRE_EMPHASIS;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
max_requested.FFE_PRESET = lane_settings[0].FFE_PRESET;
-#endif
/* Determine what the maximum of the requested settings are*/
for (lane = 1; lane < lt_settings->link_settings.lane_count; lane++) {
@@ -1024,12 +901,10 @@ static void maximize_lane_settings(const struct link_training_settings *lt_setti
if (lane_settings[lane].PRE_EMPHASIS > max_requested.PRE_EMPHASIS)
max_requested.PRE_EMPHASIS = lane_settings[lane].PRE_EMPHASIS;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (lane_settings[lane].FFE_PRESET.settings.level >
max_requested.FFE_PRESET.settings.level)
max_requested.FFE_PRESET.settings.level =
lane_settings[lane].FFE_PRESET.settings.level;
-#endif
}
/* make sure the requested settings are
@@ -1039,10 +914,8 @@ static void maximize_lane_settings(const struct link_training_settings *lt_setti
if (max_requested.PRE_EMPHASIS > PRE_EMPHASIS_MAX_LEVEL)
max_requested.PRE_EMPHASIS = PRE_EMPHASIS_MAX_LEVEL;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (max_requested.FFE_PRESET.settings.level > DP_FFE_PRESET_MAX_LEVEL)
max_requested.FFE_PRESET.settings.level = DP_FFE_PRESET_MAX_LEVEL;
-#endif
/* make sure the pre-emphasis matches the voltage swing*/
if (max_requested.PRE_EMPHASIS >
@@ -1055,9 +928,7 @@ static void maximize_lane_settings(const struct link_training_settings *lt_setti
for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
lane_settings[lane].VOLTAGE_SWING = max_requested.VOLTAGE_SWING;
lane_settings[lane].PRE_EMPHASIS = max_requested.PRE_EMPHASIS;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
lane_settings[lane].FFE_PRESET = max_requested.FFE_PRESET;
-#endif
}
}
@@ -1068,24 +939,20 @@ static void override_lane_settings(const struct link_training_settings *lt_setti
if (lt_settings->voltage_swing == NULL &&
lt_settings->pre_emphasis == NULL &&
-#if defined(CONFIG_DRM_AMD_DC_DCN)
lt_settings->ffe_preset == NULL &&
-#endif
lt_settings->post_cursor2 == NULL)
return;
- for (lane = 1; lane < LANE_COUNT_DP_MAX; lane++) {
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
if (lt_settings->voltage_swing)
lane_settings[lane].VOLTAGE_SWING = *lt_settings->voltage_swing;
if (lt_settings->pre_emphasis)
lane_settings[lane].PRE_EMPHASIS = *lt_settings->pre_emphasis;
if (lt_settings->post_cursor2)
lane_settings[lane].POST_CURSOR2 = *lt_settings->post_cursor2;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (lt_settings->ffe_preset)
lane_settings[lane].FFE_PRESET = *lt_settings->ffe_preset;
-#endif
}
}
@@ -1117,6 +984,14 @@ enum dc_status dp_get_lane_status_and_lane_adjust(
(uint8_t *)(dpcd_buf),
sizeof(dpcd_buf));
+ if (status != DC_OK) {
+ DC_LOG_HW_LINK_TRAINING("%s:\n Failed to read from address 0x%X,"
+ " keep current lane status and lane adjust unchanged",
+ __func__,
+ lane01_status_address);
+ return status;
+ }
+
for (lane = 0; lane <
(uint32_t)(link_training_setting->link_settings.lane_count);
lane++) {
@@ -1189,7 +1064,6 @@ enum dc_status dpcd_set_lane_settings(
link_training_setting->link_settings.lane_count);
if (is_repeater(link, offset)) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
DP_128b_132b_ENCODING)
DC_LOG_HW_LINK_TRAINING("%s:\n LTTPR Repeater ID: %d\n"
@@ -1200,7 +1074,6 @@ enum dc_status dpcd_set_lane_settings(
link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
DP_8b_10b_ENCODING)
-#endif
DC_LOG_HW_LINK_TRAINING("%s\n LTTPR Repeater ID: %d\n"
" 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
__func__,
@@ -1212,7 +1085,6 @@ enum dc_status dpcd_set_lane_settings(
link_training_setting->dpcd_lane_settings[0].bits.MAX_PRE_EMPHASIS_REACHED);
} else {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
DP_128b_132b_ENCODING)
DC_LOG_HW_LINK_TRAINING("%s:\n 0x%X TX_FFE_PRESET_VALUE = %x\n",
@@ -1221,7 +1093,6 @@ enum dc_status dpcd_set_lane_settings(
link_training_setting->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE);
else if (dp_get_link_encoding_format(&link_training_setting->link_settings) ==
DP_8b_10b_ENCODING)
-#endif
DC_LOG_HW_LINK_TRAINING("%s\n 0x%X VS set = %x PE set = %x max VS Reached = %x max PE Reached = %x\n",
__func__,
lane0_set_address,
@@ -1261,6 +1132,9 @@ static bool perform_post_lt_adj_req_sequence(
uint32_t adj_req_timer;
bool req_drv_setting_changed;
uint32_t lane;
+ union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX] = {0};
+ union lane_align_status_updated dpcd_lane_status_updated = {0};
+ union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = {0};
req_drv_setting_changed = false;
for (adj_req_count = 0; adj_req_count < POST_LT_ADJ_REQ_LIMIT;
@@ -1272,11 +1146,6 @@ static bool perform_post_lt_adj_req_sequence(
adj_req_timer < POST_LT_ADJ_REQ_TIMEOUT;
adj_req_timer++) {
- union lane_status dpcd_lane_status[LANE_COUNT_DP_MAX];
- union lane_align_status_updated
- dpcd_lane_status_updated;
- union lane_adjust dpcd_lane_adjust[LANE_COUNT_DP_MAX] = { { {0} } };
-
dp_get_lane_status_and_lane_adjust(
link,
lt_settings,
@@ -1357,14 +1226,12 @@ uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval
case 0x04:
aux_rd_interval_us = 16000;
break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case 0x05:
aux_rd_interval_us = 32000;
break;
case 0x06:
aux_rd_interval_us = 64000;
break;
-#endif
default:
break;
}
@@ -1405,13 +1272,8 @@ static enum link_training_result perform_channel_equalization_sequence(
/* Note: also check that TPS4 is a supported feature*/
tr_pattern = lt_settings->pattern_for_eq;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_repeater(link, offset) && dp_get_link_encoding_format(&lt_settings->link_settings) == DP_8b_10b_ENCODING)
tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
-#else
- if (is_repeater(link, offset))
- tr_pattern = DP_TRAINING_PATTERN_SEQUENCE_4;
-#endif
dp_set_hw_training_pattern(link, link_res, tr_pattern, offset);
@@ -1510,6 +1372,10 @@ static enum link_training_result perform_clock_recovery_sequence(
retries_cr = 0;
retry_count = 0;
+ memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
+ memset(&dpcd_lane_status_updated, '\0',
+ sizeof(dpcd_lane_status_updated));
+
if (!link->ctx->dc->work_arounds.lt_early_cr_pattern)
dp_set_hw_training_pattern(link, link_res, lt_settings->pattern_for_cr, offset);
@@ -1521,9 +1387,6 @@ static enum link_training_result perform_clock_recovery_sequence(
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
- memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
- memset(&dpcd_lane_status_updated, '\0',
- sizeof(dpcd_lane_status_updated));
/* 1. call HWSS to set lane settings*/
dp_set_hw_lane_settings(
@@ -1570,27 +1433,15 @@ static enum link_training_result perform_clock_recovery_sequence(
dpcd_lane_adjust,
offset);
- if (link->dc->debug.apply_vendor_specific_lttpr_wa &&
- (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
- link->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
- vendor_specific_lttpr_wa_one_end(link, retry_count);
- vendor_specific_lttpr_wa_three(link, dpcd_lane_adjust);
- }
-
/* 5. check CR done*/
if (dp_is_cr_done(lane_count, dpcd_lane_status))
return LINK_TRAINING_SUCCESS;
/* 6. max VS reached*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if ((dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_8b_10b_ENCODING) &&
dp_is_max_vs_reached(lt_settings))
break;
-#else
- if (dp_is_max_vs_reached(lt_settings))
- break;
-#endif
/* 7. same lane settings*/
/* Note: settings are the same for all lanes,
@@ -1599,12 +1450,10 @@ static enum link_training_result perform_clock_recovery_sequence(
lt_settings->dpcd_lane_settings[0].bits.VOLTAGE_SWING_SET ==
dpcd_lane_adjust[0].bits.VOLTAGE_SWING_LANE)
retries_cr++;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
else if ((dp_get_link_encoding_format(&lt_settings->link_settings) == DP_128b_132b_ENCODING) &&
lt_settings->dpcd_lane_settings[0].tx_ffe.PRESET_VALUE ==
dpcd_lane_adjust[0].tx_ffe.PRESET_VALUE)
retries_cr++;
-#endif
else
retries_cr = 0;
@@ -1642,11 +1491,7 @@ static inline enum link_training_result dp_transition_to_video_idle(
* TPS4 must be used instead of POST_LT_ADJ_REQ.
*/
if (link->dpcd_caps.max_ln_count.bits.POST_LT_ADJ_REQ_SUPPORTED != 1 ||
-#if defined(CONFIG_DRM_AMD_DC_DCN)
lt_settings->pattern_for_eq >= DP_TRAINING_PATTERN_SEQUENCE_4) {
-#else
- lt_settings->pattern_for_eq == DP_TRAINING_PATTERN_SEQUENCE_4) {
-#endif
/* delay 5ms after Main Link output idle pattern and then check
* DPCD 0202h.
*/
@@ -1745,7 +1590,6 @@ static inline void decide_8b_10b_training_settings(
dp_hw_to_dpcd_lane_settings(lt_settings, lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static inline void decide_128b_132b_training_settings(struct dc_link *link,
const struct dc_link_settings *link_settings,
struct link_training_settings *lt_settings)
@@ -1772,7 +1616,6 @@ static inline void decide_128b_132b_training_settings(struct dc_link *link,
dp_hw_to_dpcd_lane_settings(lt_settings,
lt_settings->hw_lane_settings, lt_settings->dpcd_lane_settings);
}
-#endif
void dp_decide_training_settings(
struct dc_link *link,
@@ -1781,10 +1624,8 @@ void dp_decide_training_settings(
{
if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING)
decide_8b_10b_training_settings(link, link_settings, lt_settings);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
else if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING)
decide_128b_132b_training_settings(link, link_settings, lt_settings);
-#endif
}
static void override_training_settings(
@@ -1807,10 +1648,8 @@ static void override_training_settings(
lt_settings->pre_emphasis = overrides->pre_emphasis;
if (overrides->post_cursor2 != NULL)
lt_settings->post_cursor2 = overrides->post_cursor2;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (overrides->ffe_preset != NULL)
lt_settings->ffe_preset = overrides->ffe_preset;
-#endif
/* Override HW lane settings with BIOS forced values if present */
if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN &&
link->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
@@ -2014,7 +1853,6 @@ static void print_status_message(
case LINK_RATE_HIGH3:
link_rate = "HBR3";
break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case LINK_RATE_UHBR10:
link_rate = "UHBR10";
break;
@@ -2024,7 +1862,6 @@ static void print_status_message(
case LINK_RATE_UHBR20:
link_rate = "UHBR20";
break;
-#endif
default:
break;
}
@@ -2054,7 +1891,6 @@ static void print_status_message(
case LINK_TRAINING_LINK_LOSS:
lt_result = "Link loss";
break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case DP_128b_132b_LT_FAILED:
lt_result = "LT_FAILED received";
break;
@@ -2067,7 +1903,6 @@ static void print_status_message(
case DP_128b_132b_CDS_DONE_TIMEOUT:
lt_result = "CDS timeout";
break;
-#endif
default:
break;
}
@@ -2087,9 +1922,9 @@ static void print_status_message(
}
/* Connectivity log: link training */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+
/* TODO - DP2.0 Log: add connectivity log for FFE PRESET */
-#endif
+
CONN_MSG_LT(link, "%sx%d %s VS=%d, PE=%d, DS=%s",
link_rate,
lt_settings->link_settings.lane_count,
@@ -2177,15 +2012,12 @@ enum dc_status dpcd_configure_lttpr_mode(struct dc_link *link, struct link_train
static void dpcd_exit_training_mode(struct dc_link *link)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint8_t sink_status = 0;
uint8_t i;
-#endif
/* clear training pattern set */
dpcd_set_training_pattern(link, DP_TRAINING_PATTERN_VIDEOIDLE);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* poll for intra-hop disable */
for (i = 0; i < 10; i++) {
if ((core_link_read_dpcd(link, DP_SINK_STATUS, &sink_status, 1) == DC_OK) &&
@@ -2193,7 +2025,6 @@ static void dpcd_exit_training_mode(struct dc_link *link)
break;
udelay(1000);
}
-#endif
}
enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
@@ -2217,7 +2048,6 @@ enum dc_status dpcd_configure_channel_coding(struct dc_link *link,
return status;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static void dpcd_128b_132b_get_aux_rd_interval(struct dc_link *link,
uint32_t *interval_in_us)
{
@@ -2348,7 +2178,6 @@ static enum link_training_result dp_perform_128b_132b_cds_done_sequence(
return status;
}
-#endif
static enum link_training_result dp_perform_8b_10b_link_training(
struct dc_link *link,
@@ -2378,38 +2207,42 @@ static enum link_training_result dp_perform_8b_10b_link_training(
repeater_id--) {
status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
- if (status != LINK_TRAINING_SUCCESS)
+ if (status != LINK_TRAINING_SUCCESS) {
+ repeater_training_done(link, repeater_id);
break;
+ }
status = perform_channel_equalization_sequence(link,
link_res,
lt_settings,
repeater_id);
+ repeater_training_done(link, repeater_id);
+
if (status != LINK_TRAINING_SUCCESS)
break;
- repeater_training_done(link, repeater_id);
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ lt_settings->dpcd_lane_settings[lane].raw = 0;
+ lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
+ lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
+ }
}
-
- for (lane = 0; lane < (uint8_t)lt_settings->link_settings.lane_count; lane++)
- lt_settings->dpcd_lane_settings[lane].raw = 0;
}
if (status == LINK_TRAINING_SUCCESS) {
status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
- if (status == LINK_TRAINING_SUCCESS) {
- status = perform_channel_equalization_sequence(link,
- link_res,
- lt_settings,
- DPRX);
+ if (status == LINK_TRAINING_SUCCESS) {
+ status = perform_channel_equalization_sequence(link,
+ link_res,
+ lt_settings,
+ DPRX);
}
}
return status;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static enum link_training_result dp_perform_128b_132b_link_training(
struct dc_link *link,
const struct link_resource *link_res,
@@ -2437,9 +2270,97 @@ static enum link_training_result dp_perform_128b_132b_link_training(
return result;
}
-#endif
-static enum link_training_result dc_link_dp_perform_fixed_vs_pe_training_sequence(
+static enum link_training_result perform_fixed_vs_pe_nontransparent_training_sequence(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ struct link_training_settings *lt_settings)
+{
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
+ uint8_t lane = 0;
+ uint8_t toggle_rate = 0x6;
+ uint8_t target_rate = 0x6;
+ bool apply_toggle_rate_wa = false;
+ uint8_t repeater_cnt;
+ uint8_t repeater_id;
+
+ /* Fixed VS/PE specific: Force CR AUX RD Interval to at least 16ms */
+ if (lt_settings->cr_pattern_time < 16000)
+ lt_settings->cr_pattern_time = 16000;
+
+ /* Fixed VS/PE specific: Toggle link rate */
+ apply_toggle_rate_wa = (link->vendor_specific_lttpr_link_rate_wa == target_rate);
+ target_rate = get_dpcd_link_rate(&lt_settings->link_settings);
+ toggle_rate = (target_rate == 0x6) ? 0xA : 0x6;
+
+ if (apply_toggle_rate_wa)
+ lt_settings->link_settings.link_rate = toggle_rate;
+
+ if (link->ctx->dc->work_arounds.lt_early_cr_pattern)
+ start_clock_recovery_pattern_early(link, link_res, lt_settings, DPRX);
+
+ /* 1. set link rate, lane count and spread. */
+ dpcd_set_link_settings(link, lt_settings);
+
+ /* Fixed VS/PE specific: Toggle link rate back*/
+ if (apply_toggle_rate_wa) {
+ core_link_write_dpcd(
+ link,
+ DP_LINK_BW_SET,
+ &target_rate,
+ 1);
+ }
+
+ link->vendor_specific_lttpr_link_rate_wa = target_rate;
+
+ if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+
+ /* 2. perform link training (set link training done
+ * to false is done as well)
+ */
+ repeater_cnt = dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt);
+
+ for (repeater_id = repeater_cnt; (repeater_id > 0 && status == LINK_TRAINING_SUCCESS);
+ repeater_id--) {
+ status = perform_clock_recovery_sequence(link, link_res, lt_settings, repeater_id);
+
+ if (status != LINK_TRAINING_SUCCESS) {
+ repeater_training_done(link, repeater_id);
+ break;
+ }
+
+ status = perform_channel_equalization_sequence(link,
+ link_res,
+ lt_settings,
+ repeater_id);
+
+ repeater_training_done(link, repeater_id);
+
+ if (status != LINK_TRAINING_SUCCESS)
+ break;
+
+ for (lane = 0; lane < LANE_COUNT_DP_MAX; lane++) {
+ lt_settings->dpcd_lane_settings[lane].raw = 0;
+ lt_settings->hw_lane_settings[lane].VOLTAGE_SWING = 0;
+ lt_settings->hw_lane_settings[lane].PRE_EMPHASIS = 0;
+ }
+ }
+ }
+
+ if (status == LINK_TRAINING_SUCCESS) {
+ status = perform_clock_recovery_sequence(link, link_res, lt_settings, DPRX);
+ if (status == LINK_TRAINING_SUCCESS) {
+ status = perform_channel_equalization_sequence(link,
+ link_res,
+ lt_settings,
+ DPRX);
+ }
+ }
+
+ return status;
+}
+
+static enum link_training_result dp_perform_fixed_vs_pe_training_sequence(
struct dc_link *link,
const struct link_resource *link_res,
struct link_training_settings *lt_settings)
@@ -2463,6 +2384,11 @@ static enum link_training_result dc_link_dp_perform_fixed_vs_pe_training_sequenc
ASSERT(dp_get_link_encoding_format(&lt_settings->link_settings) ==
DP_8b_10b_ENCODING);
+ if (link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) {
+ status = perform_fixed_vs_pe_nontransparent_training_sequence(link, link_res, lt_settings);
+ return status;
+ }
+
if (offset != 0xFF) {
vendor_lttpr_write_address +=
((DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE) * (offset - 1));
@@ -2514,11 +2440,7 @@ static enum link_training_result dc_link_dp_perform_fixed_vs_pe_training_sequenc
core_link_write_dpcd(link, DP_LANE_COUNT_SET,
&lane_count_set.raw, 1);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
rate = get_dpcd_link_rate(&lt_settings->link_settings);
-#else
- rate = (uint8_t) (lt_settings->link_settings.link_rate);
-#endif
/* Vendor specific: Toggle link rate */
toggle_rate = (rate == 0x6) ? 0xA : 0x6;
@@ -2560,12 +2482,13 @@ static enum link_training_result dc_link_dp_perform_fixed_vs_pe_training_sequenc
retries_cr = 0;
retry_count = 0;
+ memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
+ memset(&dpcd_lane_status_updated, '\0',
+ sizeof(dpcd_lane_status_updated));
+
while ((retries_cr < LINK_TRAINING_MAX_RETRY_COUNT) &&
(retry_count < LINK_TRAINING_MAX_CR_RETRY)) {
- memset(&dpcd_lane_status, '\0', sizeof(dpcd_lane_status));
- memset(&dpcd_lane_status_updated, '\0',
- sizeof(dpcd_lane_status_updated));
/* 1. call HWSS to set lane settings */
dp_set_hw_lane_settings(
@@ -2813,16 +2736,12 @@ enum link_training_result dc_link_dp_perform_link_training(
* Per DP specs starting from here, DPTX device shall not issue
* Non-LT AUX transactions inside training mode.
*/
- if (!link->dc->debug.apply_vendor_specific_lttpr_wa &&
- (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
- link->lttpr_mode == LTTPR_MODE_TRANSPARENT)
- status = dc_link_dp_perform_fixed_vs_pe_training_sequence(link, link_res, &lt_settings);
+ if (link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN)
+ status = dp_perform_fixed_vs_pe_training_sequence(link, link_res, &lt_settings);
else if (encoding == DP_8b_10b_ENCODING)
status = dp_perform_8b_10b_link_training(link, link_res, &lt_settings);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
else if (encoding == DP_128b_132b_ENCODING)
status = dp_perform_128b_132b_link_training(link, link_res, &lt_settings);
-#endif
else
ASSERT(0);
@@ -2863,38 +2782,38 @@ bool perform_link_training_with_retries(
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link;
enum dp_panel_mode panel_mode = dp_get_panel_mode(link);
- struct link_encoder *link_enc;
enum link_training_result status = LINK_TRAINING_CR_FAIL_LANE0;
- struct dc_link_settings current_setting = *link_setting;
-
- /* Dynamically assigned link encoders associated with stream rather than
- * link.
- */
- if (link->is_dig_mapping_flexible && link->dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_stream(link->ctx->dc, pipe_ctx->stream);
- else
- link_enc = link->link_enc;
-
- /* We need to do this before the link training to ensure the idle pattern in SST
- * mode will be sent right after the link training
- */
- if (dp_get_link_encoding_format(&current_setting) == DP_8b_10b_ENCODING) {
- link_enc->funcs->connect_dig_be_to_fe(link_enc,
- pipe_ctx->stream_res.stream_enc->id, true);
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
- }
+ struct dc_link_settings cur_link_settings = *link_setting;
+ struct dc_link_settings max_link_settings = *link_setting;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ int fail_count = 0;
+ bool is_link_bw_low = false; /* link bandwidth < stream bandwidth */
+ bool is_link_bw_min = /* RBR x 1 */
+ (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+ (cur_link_settings.lane_count <= LANE_COUNT_ONE);
+
+ dp_trace_commit_lt_init(link);
+
+ if (dp_get_link_encoding_format(&cur_link_settings) == DP_8b_10b_ENCODING)
+ /* We need to do this before the link training to ensure the idle
+ * pattern in SST mode will be sent right after the link training
+ */
+ link_hwss->setup_stream_encoder(pipe_ctx);
- for (j = 0; j < attempts; ++j) {
+ dp_trace_set_lt_start_timestamp(link, false);
+ j = 0;
+ while (j < attempts && fail_count < (attempts * 10)) {
- DC_LOG_HW_LINK_TRAINING("%s: Beginning link training attempt %u of %d\n",
- __func__, (unsigned int)j + 1, attempts);
+ DC_LOG_HW_LINK_TRAINING("%s: Beginning link training attempt %u of %d @ rate(%d) x lane(%d)\n",
+ __func__, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
+ cur_link_settings.lane_count);
dp_enable_link_phy(
link,
&pipe_ctx->link_res,
signal,
pipe_ctx->clock_source->id,
- &current_setting);
+ &cur_link_settings);
if (stream->sink_patches.dppowerup_delay > 0) {
int delay_dp_power_up_in_ms = stream->sink_patches.dppowerup_delay;
@@ -2919,37 +2838,43 @@ bool perform_link_training_with_retries(
dp_set_panel_mode(link, panel_mode);
if (link->aux_access_disabled) {
- dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &current_setting);
+ dc_link_dp_perform_link_training_skip_aux(link, &pipe_ctx->link_res, &cur_link_settings);
return true;
} else {
/** @todo Consolidate USB4 DP and DPx.x training. */
if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA) {
status = dc_link_dpia_perform_link_training(link,
&pipe_ctx->link_res,
- &current_setting,
+ &cur_link_settings,
skip_video_pattern);
/* Transmit idle pattern once training successful. */
- if (status == LINK_TRAINING_SUCCESS)
+ if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
dp_set_hw_test_pattern(link, &pipe_ctx->link_res, DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
} else {
status = dc_link_dp_perform_link_training(link,
&pipe_ctx->link_res,
- &current_setting,
+ &cur_link_settings,
skip_video_pattern);
}
- if (status == LINK_TRAINING_SUCCESS)
+ dp_trace_lt_total_count_increment(link, false);
+ dp_trace_lt_result_update(link, status, false);
+ dp_trace_set_lt_end_timestamp(link, false);
+ if (status == LINK_TRAINING_SUCCESS && !is_link_bw_low)
return true;
}
+ fail_count++;
+ dp_trace_lt_fail_count_update(link, fail_count, false);
/* latest link training still fail, skip delay and keep PHY on
*/
if (j == (attempts - 1) && link->ep_type == DISPLAY_ENDPOINT_PHY)
break;
- DC_LOG_WARNING("%s: Link training attempt %u of %d failed\n",
- __func__, (unsigned int)j + 1, attempts);
+ DC_LOG_WARNING("%s: Link training attempt %u of %d failed @ rate(%d) x lane(%d)\n",
+ __func__, (unsigned int)j + 1, attempts, cur_link_settings.link_rate,
+ cur_link_settings.lane_count);
dp_disable_link_phy(link, &pipe_ctx->link_res, signal);
@@ -2958,27 +2883,45 @@ bool perform_link_training_with_retries(
enum dc_connection_type type = dc_connection_none;
dc_link_detect_sink(link, &type);
- if (type == dc_connection_none)
+ if (type == dc_connection_none) {
+ DC_LOG_HW_LINK_TRAINING("%s: Aborting training because sink unplugged\n", __func__);
break;
- } else if (do_fallback) {
+ }
+ }
+
+ /* Try to train again at original settings if:
+ * - not falling back between training attempts;
+ * - aborted previous attempt due to reasons other than sink unplug;
+ * - successfully trained but at a link rate lower than that required by stream;
+ * - reached minimum link bandwidth.
+ */
+ if (!do_fallback || (status == LINK_TRAINING_ABORT) ||
+ (status == LINK_TRAINING_SUCCESS && is_link_bw_low) ||
+ is_link_bw_min) {
+ j++;
+ cur_link_settings = *link_setting;
+ delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
+ is_link_bw_low = false;
+ is_link_bw_min = (cur_link_settings.link_rate <= LINK_RATE_LOW) &&
+ (cur_link_settings.lane_count <= LANE_COUNT_ONE);
+
+ } else if (do_fallback) { /* Try training at lower link bandwidth if doing fallback. */
uint32_t req_bw;
uint32_t link_bw;
- decide_fallback_link_setting(link, *link_setting, &current_setting, status);
+ decide_fallback_link_setting(link, &max_link_settings,
+ &cur_link_settings, status);
/* Fail link training if reduced link bandwidth no longer meets
* stream requirements.
*/
req_bw = dc_bandwidth_in_kbps_from_timing(&stream->timing);
- link_bw = dc_link_bandwidth_kbps(link, &current_setting);
+ link_bw = dc_link_bandwidth_kbps(link, &cur_link_settings);
if (req_bw > link_bw)
break;
}
msleep(delay_between_attempts);
-
- delay_between_attempts += LINK_TRAINING_RETRY_DELAY;
}
-
return false;
}
@@ -3074,14 +3017,10 @@ enum link_training_result dc_link_dp_sync_lt_attempt(
dp_cs_id, link_settings);
/* Set FEC enable */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
-#endif
fec_enable = lt_overrides->fec_enable && *lt_overrides->fec_enable;
dp_set_fec_ready(link, NULL, fec_enable);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
}
-#endif
if (lt_overrides->alternate_scrambler_reset) {
if (*lt_overrides->alternate_scrambler_reset)
@@ -3124,13 +3063,9 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
* Still shouldn't turn off dp_receiver (DPCD:600h)
*/
if (link_down == true) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_link_settings link_settings = link->cur_link_settings;
-#endif
dp_disable_link_phy(link, NULL, link->connector_signal);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dp_get_link_encoding_format(&link_settings) == DP_8b_10b_ENCODING)
-#endif
dp_set_fec_ready(link, NULL, false);
}
@@ -3138,7 +3073,6 @@ bool dc_link_dp_sync_lt_end(struct dc_link *link, bool link_down)
return true;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link)
{
enum dc_link_rate lttpr_max_link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
@@ -3152,7 +3086,20 @@ static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link)
return lttpr_max_link_rate;
}
-#endif
+
+static enum dc_link_rate get_cable_max_link_rate(struct dc_link *link)
+{
+ enum dc_link_rate cable_max_link_rate = LINK_RATE_HIGH3;
+
+ if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR20)
+ cable_max_link_rate = LINK_RATE_UHBR20;
+ else if (link->dpcd_caps.cable_id.bits.UHBR13_5_CAPABILITY)
+ cable_max_link_rate = LINK_RATE_UHBR13_5;
+ else if (link->dpcd_caps.cable_id.bits.UHBR10_20_CAPABILITY & DP_UHBR10)
+ cable_max_link_rate = LINK_RATE_UHBR10;
+
+ return cable_max_link_rate;
+}
bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
{
@@ -3163,16 +3110,7 @@ bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_
return false;
}
- /* Links supporting dynamically assigned link encoder will be assigned next
- * available encoder if one not already assigned.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign) {
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- if (link_enc == NULL)
- link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc);
- } else
- link_enc = link->link_enc;
+ link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
if (link_enc && link_enc->funcs->get_max_link_cap) {
@@ -3186,37 +3124,21 @@ bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_
return false;
}
-static struct dc_link_settings get_max_link_cap(struct dc_link *link,
- const struct link_resource *link_res)
+
+struct dc_link_settings dp_get_max_link_cap(struct dc_link *link)
{
struct dc_link_settings max_link_cap = {0};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dc_link_rate lttpr_max_link_rate;
-#endif
+ enum dc_link_rate cable_max_link_rate;
struct link_encoder *link_enc = NULL;
- /* Links supporting dynamically assigned link encoder will be assigned next
- * available encoder if one not already assigned.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign) {
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- if (link_enc == NULL)
- link_enc = link_enc_cfg_get_next_avail_link_enc(link->ctx->dc);
- } else
- link_enc = link->link_enc;
+
+ link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
/* get max link encoder capability */
if (link_enc)
link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (max_link_cap.link_rate >= LINK_RATE_UHBR10) {
- if (!link_res->hpo_dp_link_enc ||
- link->dc->debug.disable_uhbr)
- max_link_cap.link_rate = LINK_RATE_HIGH3;
- }
-#endif
/* Lower link settings based on sink's link cap */
if (link->reported_link_cap.lane_count < max_link_cap.lane_count)
@@ -3229,6 +3151,14 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link,
max_link_cap.link_spread)
max_link_cap.link_spread =
link->reported_link_cap.link_spread;
+
+ /* Lower link settings based on cable attributes */
+ cable_max_link_rate = get_cable_max_link_rate(link);
+
+ if (!link->dc->debug.ignore_cable_id &&
+ cable_max_link_rate < max_link_cap.link_rate)
+ max_link_cap.link_rate = cable_max_link_rate;
+
/*
* account for lttpr repeaters cap
* notes: repeaters do not snoop in the DPRX Capabilities addresses (3.6.3).
@@ -3236,22 +3166,21 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link,
if (link->lttpr_mode != LTTPR_MODE_NON_LTTPR) {
if (link->dpcd_caps.lttpr_caps.max_lane_count < max_link_cap.lane_count)
max_link_cap.lane_count = link->dpcd_caps.lttpr_caps.max_lane_count;
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
lttpr_max_link_rate = get_lttpr_max_link_rate(link);
if (lttpr_max_link_rate < max_link_cap.link_rate)
max_link_cap.link_rate = lttpr_max_link_rate;
-#else
- if (link->dpcd_caps.lttpr_caps.max_link_rate < max_link_cap.link_rate)
- max_link_cap.link_rate = link->dpcd_caps.lttpr_caps.max_link_rate;
-#endif
DC_LOG_HW_LINK_TRAINING("%s\n Training with LTTPR, max_lane count %d max_link rate %d \n",
__func__,
max_link_cap.lane_count,
max_link_cap.link_rate);
}
+
+ if (dp_get_link_encoding_format(&max_link_cap) == DP_128b_132b_ENCODING &&
+ link->dc->debug.disable_uhbr)
+ max_link_cap.link_rate = LINK_RATE_HIGH3;
+
return max_link_cap;
}
@@ -3370,48 +3299,22 @@ bool hpd_rx_irq_check_link_loss_status(
return return_code;
}
-bool dp_verify_link_cap(
+static bool dp_verify_link_cap(
struct dc_link *link,
- const struct link_resource *link_res,
struct dc_link_settings *known_limit_link_setting,
int *fail_count)
{
- struct dc_link_settings max_link_cap = {0};
- struct dc_link_settings cur_link_setting = {0};
- struct dc_link_settings *cur = &cur_link_setting;
- struct dc_link_settings initial_link_settings = {0};
- bool success;
- bool skip_link_training;
+ struct dc_link_settings cur_link_settings = {0};
+ struct dc_link_settings max_link_settings = *known_limit_link_setting;
+ bool success = false;
bool skip_video_pattern;
- enum clock_source_id dp_cs_id = CLOCK_SOURCE_ID_EXTERNAL;
- enum link_training_result status;
+ enum clock_source_id dp_cs_id = get_clock_source_id(link);
+ enum link_training_result status = LINK_TRAINING_SUCCESS;
union hpd_irq_data irq_data;
-
- /* link training starts with the maximum common settings
- * supported by both sink and ASIC.
- */
- max_link_cap = get_max_link_cap(link, link_res);
- initial_link_settings = get_common_supported_link_settings(
- *known_limit_link_setting,
- max_link_cap);
-
- /* Accept reported capabilities if link supports flexible encoder mapping or encoder already in use. */
- if (link->dc->debug.skip_detection_link_training ||
- link->is_dig_mapping_flexible) {
- /* TODO - should we check link encoder's max link caps here?
- * How do we know which link encoder to check from?
- */
- link->verified_link_cap = *known_limit_link_setting;
- return true;
- } else if (link->link_enc && link->dc->res_pool->funcs->link_encs_assign &&
- !link_enc_cfg_is_link_enc_avail(link->ctx->dc, link->link_enc->preferred_engine, link)) {
- link->verified_link_cap = initial_link_settings;
- return true;
- }
+ struct link_resource link_res;
memset(&irq_data, 0, sizeof(irq_data));
- success = false;
- skip_link_training = false;
+ cur_link_settings = max_link_settings;
/* Grant extended timeout request */
if ((link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && (link->dpcd_caps.lttpr_caps.max_ext_timeout > 0)) {
@@ -3420,199 +3323,126 @@ bool dp_verify_link_cap(
core_link_write_dpcd(link, DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT, &grant, sizeof(grant));
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
- reset_dp_hpo_stream_encoders_for_link(link);
-#endif
- /* TODO implement override and monitor patch later */
-
- /* try to train the link from high to low to
- * find the physical link capability
- */
- /* disable PHY done possible by BIOS, will be done by driver itself */
- dp_disable_link_phy(link, link_res, link->connector_signal);
-
- dp_cs_id = get_clock_source_id(link);
-
- cur_link_setting = initial_link_settings;
-
- /* Temporary Renoir-specific workaround for SWDEV-215184;
- * PHY will sometimes be in bad state on hotplugging display from certain USB-C dongle,
- * so add extra cycle of enabling and disabling the PHY before first link training.
- */
- if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C &&
- link->dc->debug.usbc_combo_phy_reset_wa) {
- dp_enable_link_phy(link, link_res, link->connector_signal, dp_cs_id, cur);
- dp_disable_link_phy(link, link_res, link->connector_signal);
- }
-
do {
- skip_video_pattern = true;
-
- if (cur->link_rate == LINK_RATE_LOW)
- skip_video_pattern = false;
+ if (!get_temp_dp_link_res(link, &link_res, &cur_link_settings))
+ continue;
+ skip_video_pattern = cur_link_settings.link_rate != LINK_RATE_LOW;
dp_enable_link_phy(
link,
- link_res,
+ &link_res,
link->connector_signal,
dp_cs_id,
- cur);
+ &cur_link_settings);
+ status = dc_link_dp_perform_link_training(
+ link,
+ &link_res,
+ &cur_link_settings,
+ skip_video_pattern);
- if (skip_link_training)
+ if (status == LINK_TRAINING_SUCCESS) {
success = true;
- else {
- status = dc_link_dp_perform_link_training(
+ udelay(1000);
+ if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK &&
+ hpd_rx_irq_check_link_loss_status(
link,
- link_res,
- cur,
- skip_video_pattern);
- if (status == LINK_TRAINING_SUCCESS)
- success = true;
- else
+ &irq_data))
(*fail_count)++;
- }
- if (success) {
- link->verified_link_cap = *cur;
- udelay(1000);
- if (read_hpd_rx_irq_data(link, &irq_data) == DC_OK)
- if (hpd_rx_irq_check_link_loss_status(
- link,
- &irq_data))
- (*fail_count)++;
+ } else {
+ (*fail_count)++;
}
- /* always disable the link before trying another
- * setting or before returning we'll enable it later
- * based on the actual mode we're driving
- */
- dp_disable_link_phy(link, link_res, link->connector_signal);
+ dp_trace_lt_total_count_increment(link, true);
+ dp_trace_lt_result_update(link, status, true);
+ dp_disable_link_phy(link, &link_res, link->connector_signal);
} while (!success && decide_fallback_link_setting(link,
- initial_link_settings, cur, status));
-
- /* Link Training failed for all Link Settings
- * (Lane Count is still unknown)
- */
- if (!success) {
- /* If all LT fails for all settings,
- * set verified = failed safe (1 lane low)
- */
- link->verified_link_cap.lane_count = LANE_COUNT_ONE;
- link->verified_link_cap.link_rate = LINK_RATE_LOW;
+ &max_link_settings, &cur_link_settings, status));
- link->verified_link_cap.link_spread =
- LINK_SPREAD_DISABLED;
- }
+ link->verified_link_cap = success ?
+ cur_link_settings : fail_safe_link_settings;
+ return success;
+}
+static void apply_usbc_combo_phy_reset_wa(struct dc_link *link,
+ struct dc_link_settings *link_settings)
+{
+ /* Temporary Renoir-specific workaround PHY will sometimes be in bad
+ * state on hotplugging display from certain USB-C dongle, so add extra
+ * cycle of enabling and disabling the PHY before first link training.
+ */
+ struct link_resource link_res = {0};
+ enum clock_source_id dp_cs_id = get_clock_source_id(link);
- return success;
+ dp_enable_link_phy(link, &link_res, link->connector_signal,
+ dp_cs_id, link_settings);
+ dp_disable_link_phy(link, &link_res, link->connector_signal);
}
bool dp_verify_link_cap_with_retries(
struct dc_link *link,
- const struct link_resource *link_res,
struct dc_link_settings *known_limit_link_setting,
int attempts)
{
int i = 0;
bool success = false;
+ int fail_count = 0;
+
+ dp_trace_detect_lt_init(link);
+
+ if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C &&
+ link->dc->debug.usbc_combo_phy_reset_wa)
+ apply_usbc_combo_phy_reset_wa(link, known_limit_link_setting);
+ dp_trace_set_lt_start_timestamp(link, false);
for (i = 0; i < attempts; i++) {
- int fail_count = 0;
enum dc_connection_type type = dc_connection_none;
memset(&link->verified_link_cap, 0,
sizeof(struct dc_link_settings));
if (!dc_link_detect_sink(link, &type) || type == dc_connection_none) {
- link->verified_link_cap.lane_count = LANE_COUNT_ONE;
- link->verified_link_cap.link_rate = LINK_RATE_LOW;
- link->verified_link_cap.link_spread = LINK_SPREAD_DISABLED;
+ link->verified_link_cap = fail_safe_link_settings;
break;
- } else if (dp_verify_link_cap(link, link_res,
- known_limit_link_setting,
+ } else if (dp_verify_link_cap(link, known_limit_link_setting,
&fail_count) && fail_count == 0) {
success = true;
break;
}
msleep(10);
}
- return success;
-}
-bool dp_verify_mst_link_cap(
- struct dc_link *link, const struct link_resource *link_res)
-{
- struct dc_link_settings max_link_cap = {0};
+ dp_trace_lt_fail_count_update(link, fail_count, true);
+ dp_trace_set_lt_end_timestamp(link, true);
- if (dp_get_link_encoding_format(&link->reported_link_cap) ==
- DP_8b_10b_ENCODING) {
- max_link_cap = get_max_link_cap(link, link_res);
- link->verified_link_cap = get_common_supported_link_settings(
- link->reported_link_cap,
- max_link_cap);
- }
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- else if (dp_get_link_encoding_format(&link->reported_link_cap) ==
- DP_128b_132b_ENCODING) {
- dp_verify_link_cap_with_retries(link,
- link_res,
- &link->reported_link_cap,
- LINK_TRAINING_MAX_VERIFY_RETRY);
- }
-#endif
- return true;
+ return success;
}
-static struct dc_link_settings get_common_supported_link_settings(
- struct dc_link_settings link_setting_a,
- struct dc_link_settings link_setting_b)
+/* in DP compliance test, DPR-120 may have
+ * a random value in its MAX_LINK_BW dpcd field.
+ * We map it to the maximum supported link rate that
+ * is smaller than MAX_LINK_BW in this case.
+ */
+static enum dc_link_rate get_link_rate_from_max_link_bw(
+ uint8_t max_link_bw)
{
- struct dc_link_settings link_settings = {0};
+ enum dc_link_rate link_rate;
- link_settings.lane_count =
- (link_setting_a.lane_count <=
- link_setting_b.lane_count) ?
- link_setting_a.lane_count :
- link_setting_b.lane_count;
- link_settings.link_rate =
- (link_setting_a.link_rate <=
- link_setting_b.link_rate) ?
- link_setting_a.link_rate :
- link_setting_b.link_rate;
- link_settings.link_spread = LINK_SPREAD_DISABLED;
-
- /* in DP compliance test, DPR-120 may have
- * a random value in its MAX_LINK_BW dpcd field.
- * We map it to the maximum supported link rate that
- * is smaller than MAX_LINK_BW in this case.
- */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (link_settings.link_rate > LINK_RATE_UHBR20) {
- link_settings.link_rate = LINK_RATE_UHBR20;
- } else if (link_settings.link_rate < LINK_RATE_UHBR20 &&
- link_settings.link_rate > LINK_RATE_UHBR13_5) {
- link_settings.link_rate = LINK_RATE_UHBR13_5;
- } else if (link_settings.link_rate < LINK_RATE_UHBR10 &&
- link_settings.link_rate > LINK_RATE_HIGH3) {
-#else
- if (link_settings.link_rate > LINK_RATE_HIGH3) {
-#endif
- link_settings.link_rate = LINK_RATE_HIGH3;
- } else if (link_settings.link_rate < LINK_RATE_HIGH3
- && link_settings.link_rate > LINK_RATE_HIGH2) {
- link_settings.link_rate = LINK_RATE_HIGH2;
- } else if (link_settings.link_rate < LINK_RATE_HIGH2
- && link_settings.link_rate > LINK_RATE_HIGH) {
- link_settings.link_rate = LINK_RATE_HIGH;
- } else if (link_settings.link_rate < LINK_RATE_HIGH
- && link_settings.link_rate > LINK_RATE_LOW) {
- link_settings.link_rate = LINK_RATE_LOW;
- } else if (link_settings.link_rate < LINK_RATE_LOW) {
- link_settings.link_rate = LINK_RATE_UNKNOWN;
+ if (max_link_bw >= LINK_RATE_HIGH3) {
+ link_rate = LINK_RATE_HIGH3;
+ } else if (max_link_bw < LINK_RATE_HIGH3
+ && max_link_bw >= LINK_RATE_HIGH2) {
+ link_rate = LINK_RATE_HIGH2;
+ } else if (max_link_bw < LINK_RATE_HIGH2
+ && max_link_bw >= LINK_RATE_HIGH) {
+ link_rate = LINK_RATE_HIGH;
+ } else if (max_link_bw < LINK_RATE_HIGH
+ && max_link_bw >= LINK_RATE_LOW) {
+ link_rate = LINK_RATE_LOW;
+ } else {
+ link_rate = LINK_RATE_UNKNOWN;
}
- return link_settings;
+ return link_rate;
}
static inline bool reached_minimum_lane_count(enum dc_lane_count lane_count)
@@ -3642,14 +3472,12 @@ static enum dc_lane_count reduce_lane_count(enum dc_lane_count lane_count)
static enum dc_link_rate reduce_link_rate(enum dc_link_rate link_rate)
{
switch (link_rate) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case LINK_RATE_UHBR20:
return LINK_RATE_UHBR13_5;
case LINK_RATE_UHBR13_5:
return LINK_RATE_UHBR10;
case LINK_RATE_UHBR10:
return LINK_RATE_HIGH3;
-#endif
case LINK_RATE_HIGH3:
return LINK_RATE_HIGH2;
case LINK_RATE_HIGH2:
@@ -3675,7 +3503,8 @@ static enum dc_lane_count increase_lane_count(enum dc_lane_count lane_count)
}
}
-static enum dc_link_rate increase_link_rate(enum dc_link_rate link_rate)
+static enum dc_link_rate increase_link_rate(struct dc_link *link,
+ enum dc_link_rate link_rate)
{
switch (link_rate) {
case LINK_RATE_LOW:
@@ -3684,27 +3513,37 @@ static enum dc_link_rate increase_link_rate(enum dc_link_rate link_rate)
return LINK_RATE_HIGH2;
case LINK_RATE_HIGH2:
return LINK_RATE_HIGH3;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case LINK_RATE_HIGH3:
return LINK_RATE_UHBR10;
case LINK_RATE_UHBR10:
- return LINK_RATE_UHBR13_5;
+ /* upto DP2.x specs UHBR13.5 is the only link rate that could be
+ * not supported by DPRX when higher link rate is supported.
+ * so we treat it as a special case for code simplicity. When we
+ * have new specs with more link rates like this, we should
+ * consider a more generic solution to handle discrete link
+ * rate capabilities.
+ */
+ return link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 ?
+ LINK_RATE_UHBR13_5 : LINK_RATE_UHBR20;
case LINK_RATE_UHBR13_5:
return LINK_RATE_UHBR20;
-#endif
default:
return LINK_RATE_UNKNOWN;
}
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static bool decide_fallback_link_setting_max_bw_policy(
+ struct dc_link *link,
const struct dc_link_settings *max,
- struct dc_link_settings *cur)
+ struct dc_link_settings *cur,
+ enum link_training_result training_result)
{
uint8_t cur_idx = 0, next_idx;
bool found = false;
+ if (training_result == LINK_TRAINING_ABORT)
+ return false;
+
while (cur_idx < ARRAY_SIZE(dp_lt_fallbacks))
/* find current index */
if (dp_lt_fallbacks[cur_idx].lane_count == cur->lane_count &&
@@ -3717,11 +3556,22 @@ static bool decide_fallback_link_setting_max_bw_policy(
while (next_idx < ARRAY_SIZE(dp_lt_fallbacks))
/* find next index */
- if (dp_lt_fallbacks[next_idx].lane_count <= max->lane_count &&
- dp_lt_fallbacks[next_idx].link_rate <= max->link_rate)
- break;
- else
+ if (dp_lt_fallbacks[next_idx].lane_count > max->lane_count ||
+ dp_lt_fallbacks[next_idx].link_rate > max->link_rate)
+ next_idx++;
+ else if (dp_lt_fallbacks[next_idx].link_rate == LINK_RATE_UHBR13_5 &&
+ link->dpcd_caps.dp_128b_132b_supported_link_rates.bits.UHBR13_5 == 0)
+ /* upto DP2.x specs UHBR13.5 is the only link rate that
+ * could be not supported by DPRX when higher link rate
+ * is supported. so we treat it as a special case for
+ * code simplicity. When we have new specs with more
+ * link rates like this, we should consider a more
+ * generic solution to handle discrete link rate
+ * capabilities.
+ */
next_idx++;
+ else
+ break;
if (next_idx < ARRAY_SIZE(dp_lt_fallbacks)) {
cur->lane_count = dp_lt_fallbacks[next_idx].lane_count;
@@ -3731,7 +3581,6 @@ static bool decide_fallback_link_setting_max_bw_policy(
return found;
}
-#endif
/*
* function: set link rate and lane count fallback based
@@ -3743,18 +3592,19 @@ static bool decide_fallback_link_setting_max_bw_policy(
*/
static bool decide_fallback_link_setting(
struct dc_link *link,
- struct dc_link_settings initial_link_settings,
- struct dc_link_settings *current_link_setting,
+ struct dc_link_settings *max,
+ struct dc_link_settings *cur,
enum link_training_result training_result)
{
- if (!current_link_setting)
+ if (!cur)
return false;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(&initial_link_settings) == DP_128b_132b_ENCODING ||
+ if (!max)
+ return false;
+
+ if (dp_get_link_encoding_format(max) == DP_128b_132b_ENCODING ||
link->dc->debug.force_dp2_lt_fallback_method)
- return decide_fallback_link_setting_max_bw_policy(&initial_link_settings,
- current_link_setting);
-#endif
+ return decide_fallback_link_setting_max_bw_policy(link, max, cur,
+ training_result);
switch (training_result) {
case LINK_TRAINING_CR_FAIL_LANE0:
@@ -3762,28 +3612,18 @@ static bool decide_fallback_link_setting(
case LINK_TRAINING_CR_FAIL_LANE23:
case LINK_TRAINING_LQA_FAIL:
{
- if (!reached_minimum_link_rate
- (current_link_setting->link_rate)) {
- current_link_setting->link_rate =
- reduce_link_rate(
- current_link_setting->link_rate);
- } else if (!reached_minimum_lane_count
- (current_link_setting->lane_count)) {
- current_link_setting->link_rate =
- initial_link_settings.link_rate;
+ if (!reached_minimum_link_rate(cur->link_rate)) {
+ cur->link_rate = reduce_link_rate(cur->link_rate);
+ } else if (!reached_minimum_lane_count(cur->lane_count)) {
+ cur->link_rate = max->link_rate;
if (training_result == LINK_TRAINING_CR_FAIL_LANE0)
return false;
else if (training_result == LINK_TRAINING_CR_FAIL_LANE1)
- current_link_setting->lane_count =
- LANE_COUNT_ONE;
- else if (training_result ==
- LINK_TRAINING_CR_FAIL_LANE23)
- current_link_setting->lane_count =
- LANE_COUNT_TWO;
+ cur->lane_count = LANE_COUNT_ONE;
+ else if (training_result == LINK_TRAINING_CR_FAIL_LANE23)
+ cur->lane_count = LANE_COUNT_TWO;
else
- current_link_setting->lane_count =
- reduce_lane_count(
- current_link_setting->lane_count);
+ cur->lane_count = reduce_lane_count(cur->lane_count);
} else {
return false;
}
@@ -3791,16 +3631,17 @@ static bool decide_fallback_link_setting(
}
case LINK_TRAINING_EQ_FAIL_EQ:
{
- if (!reached_minimum_lane_count
- (current_link_setting->lane_count)) {
- current_link_setting->lane_count =
- reduce_lane_count(
- current_link_setting->lane_count);
- } else if (!reached_minimum_link_rate
- (current_link_setting->link_rate)) {
- current_link_setting->link_rate =
- reduce_link_rate(
- current_link_setting->link_rate);
+ if (!reached_minimum_lane_count(cur->lane_count)) {
+ cur->lane_count = reduce_lane_count(cur->lane_count);
+ } else if (!reached_minimum_link_rate(cur->link_rate)) {
+ cur->link_rate = reduce_link_rate(cur->link_rate);
+ /* Reduce max link rate to avoid potential infinite loop.
+ * Needed so that any subsequent CR_FAIL fallback can't
+ * re-set the link rate higher than the link rate from
+ * the latest EQ_FAIL fallback.
+ */
+ max->link_rate = cur->link_rate;
+ cur->lane_count = max->lane_count;
} else {
return false;
}
@@ -3808,11 +3649,15 @@ static bool decide_fallback_link_setting(
}
case LINK_TRAINING_EQ_FAIL_CR:
{
- if (!reached_minimum_link_rate
- (current_link_setting->link_rate)) {
- current_link_setting->link_rate =
- reduce_link_rate(
- current_link_setting->link_rate);
+ if (!reached_minimum_link_rate(cur->link_rate)) {
+ cur->link_rate = reduce_link_rate(cur->link_rate);
+ /* Reduce max link rate to avoid potential infinite loop.
+ * Needed so that any subsequent CR_FAIL fallback can't
+ * re-set the link rate higher than the link rate from
+ * the latest EQ_FAIL fallback.
+ */
+ max->link_rate = cur->link_rate;
+ cur->lane_count = max->lane_count;
} else {
return false;
}
@@ -3907,7 +3752,7 @@ static bool decide_dp_link_settings(struct dc_link *link, struct dc_link_setting
current_link_setting.lane_count);
} else {
current_link_setting.link_rate =
- increase_link_rate(
+ increase_link_rate(link,
current_link_setting.link_rate);
current_link_setting.lane_count =
initial_link_setting.lane_count;
@@ -4022,7 +3867,7 @@ static bool decide_edp_link_settings_with_dsc(struct dc_link *link,
/* minimize lane */
if (current_link_setting.link_rate < max_link_rate) {
current_link_setting.link_rate =
- increase_link_rate(
+ increase_link_rate(link,
current_link_setting.link_rate);
} else {
if (current_link_setting.lane_count <
@@ -4043,7 +3888,7 @@ static bool decide_edp_link_settings_with_dsc(struct dc_link *link,
current_link_setting.lane_count);
} else {
current_link_setting.link_rate =
- increase_link_rate(
+ increase_link_rate(link,
current_link_setting.link_rate);
current_link_setting.lane_count =
initial_link_setting.lane_count;
@@ -4261,9 +4106,32 @@ static bool handle_hpd_irq_psr_sink(struct dc_link *link)
return false;
}
+static enum dc_link_rate get_link_rate_from_test_link_rate(uint8_t test_rate)
+{
+ switch (test_rate) {
+ case DP_TEST_LINK_RATE_RBR:
+ return LINK_RATE_LOW;
+ case DP_TEST_LINK_RATE_HBR:
+ return LINK_RATE_HIGH;
+ case DP_TEST_LINK_RATE_HBR2:
+ return LINK_RATE_HIGH2;
+ case DP_TEST_LINK_RATE_HBR3:
+ return LINK_RATE_HIGH3;
+ case DP_TEST_LINK_RATE_UHBR10:
+ return LINK_RATE_UHBR10;
+ case DP_TEST_LINK_RATE_UHBR20:
+ return LINK_RATE_UHBR20;
+ case DP_TEST_LINK_RATE_UHBR13_5:
+ return LINK_RATE_UHBR13_5;
+ default:
+ return LINK_RATE_UNKNOWN;
+ }
+}
+
static void dp_test_send_link_training(struct dc_link *link)
{
struct dc_link_settings link_settings = {0};
+ uint8_t test_rate = 0;
core_link_read_dpcd(
link,
@@ -4273,8 +4141,9 @@ static void dp_test_send_link_training(struct dc_link *link)
core_link_read_dpcd(
link,
DP_TEST_LINK_RATE,
- (unsigned char *)(&link_settings.link_rate),
+ &test_rate,
1);
+ link_settings.link_rate = get_link_rate_from_test_link_rate(test_rate);
/* Set preferred link settings */
link->verified_link_cap.lane_count = link_settings.lane_count;
@@ -4292,15 +4161,9 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
union phy_test_pattern dpcd_test_pattern;
union lane_adjust dpcd_lane_adjustment[2];
unsigned char dpcd_post_cursor_2_adjustment = 0;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
unsigned char test_pattern_buffer[
(DP_TEST_264BIT_CUSTOM_PATTERN_263_256 -
DP_TEST_264BIT_CUSTOM_PATTERN_7_0)+1] = {0};
-#else
- unsigned char test_pattern_buffer[
- (DP_TEST_80BIT_CUSTOM_PATTERN_79_72 -
- DP_TEST_80BIT_CUSTOM_PATTERN_7_0)+1] = {0};
-#endif
unsigned int test_pattern_size = 0;
enum dp_test_pattern test_pattern;
union lane_adjust dpcd_lane_adjust;
@@ -4326,7 +4189,7 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
if (link->dc->debug.apply_vendor_specific_lttpr_wa &&
(link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
link->lttpr_mode == LTTPR_MODE_TRANSPARENT)
- vendor_specific_lttpr_wa_three_dpcd(
+ dp_fixed_vs_pe_read_lane_adjust(
link,
link_training_settings.dpcd_lane_settings);
@@ -4371,7 +4234,6 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
case PHY_TEST_PATTERN_CP2520_3:
test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case PHY_TEST_PATTERN_128b_132b_TPS1:
test_pattern = DP_TEST_PATTERN_128b_132b_TPS1;
break;
@@ -4399,7 +4261,6 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
case PHY_TEST_PATTERN_SQUARE_PULSE:
test_pattern = DP_TEST_PATTERN_SQUARE_PULSE;
break;
-#endif
default:
test_pattern = DP_TEST_PATTERN_VIDEO_MODE;
break;
@@ -4415,7 +4276,6 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
test_pattern_size);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (test_pattern == DP_TEST_PATTERN_SQUARE_PULSE) {
test_pattern_size = 1; // Square pattern data is 1 byte (DP spec)
core_link_read_dpcd(
@@ -4434,7 +4294,6 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
test_pattern_buffer,
test_pattern_size);
}
-#endif
/* prepare link training settings */
link_training_settings.link_settings = link->cur_link_settings;
@@ -4455,14 +4314,11 @@ static void dp_test_send_phy_test_pattern(struct dc_link *link)
link_training_settings.hw_lane_settings[lane].POST_CURSOR2 =
(enum dc_post_cursor2)
((dpcd_post_cursor_2_adjustment >> (lane * 2)) & 0x03);
- }
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- else if (dp_get_link_encoding_format(&link->cur_link_settings) ==
+ } else if (dp_get_link_encoding_format(&link->cur_link_settings) ==
DP_128b_132b_ENCODING) {
link_training_settings.hw_lane_settings[lane].FFE_PRESET.raw =
dpcd_lane_adjust.tx_ffe.PRESET_VALUE;
}
-#endif
}
dp_hw_to_dpcd_lane_settings(&link_training_settings,
@@ -4629,7 +4485,7 @@ static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video
&dpcd_pattern_type.value,
sizeof(dpcd_pattern_type));
- channel_count = dpcd_test_mode.bits.channel_count + 1;
+ channel_count = min(dpcd_test_mode.bits.channel_count + 1, AUDIO_CHANNELS_COUNT);
// read pattern periods for requested channels when sawTooth pattern is requested
if (dpcd_pattern_type.value == AUDIO_TEST_PATTERN_SAWTOOTH ||
@@ -4741,6 +4597,7 @@ void dc_link_dp_handle_link_loss(struct dc_link *link)
{
int i;
struct pipe_ctx *pipe_ctx;
+ struct dc_link_settings prev_link_settings = link->preferred_link_setting;
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
@@ -4751,6 +4608,10 @@ void dc_link_dp_handle_link_loss(struct dc_link *link)
if (pipe_ctx == NULL || pipe_ctx->stream == NULL)
return;
+ /* toggle stream state with the preference for current link settings */
+ dc_link_set_preferred_training_settings((struct dc *)link->dc,
+ &link->cur_link_settings, NULL, link, true);
+
for (i = 0; i < MAX_PIPES; i++) {
pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
@@ -4766,6 +4627,10 @@ void dc_link_dp_handle_link_loss(struct dc_link *link)
core_link_enable_stream(link->dc->current_state, pipe_ctx);
}
}
+
+ /* restore previous link settings preference */
+ dc_link_set_preferred_training_settings((struct dc *)link->dc,
+ &prev_link_settings, NULL, link, true);
}
bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss,
@@ -4869,6 +4734,8 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
status = false;
if (out_link_loss)
*out_link_loss = true;
+
+ dp_trace_link_loss_increment(link);
}
if (link->type == dc_connection_sst_branch &&
@@ -4970,7 +4837,7 @@ uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw)
return 0;
}
-/**
+/*
* Return PCON's post FRL link training supported BW if its non-zero, otherwise return max_supported_frl_bw.
*/
static uint32_t intersect_frl_link_bw_support(
@@ -5159,7 +5026,6 @@ static void get_active_converter_info(
dp_hw_fw_revision.ieee_fw_rev,
sizeof(dp_hw_fw_revision.ieee_fw_rev));
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (link->dpcd_caps.dpcd_rev.raw >= DPCD_REV_14 &&
link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
union dp_dfp_cap_ext dfp_cap_ext;
@@ -5195,7 +5061,6 @@ static void get_active_converter_info(
DC_LOG_DP2("\tdfp_cap_ext.max_video_h_active_width = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_h_active_width);
DC_LOG_DP2("\tdfp_cap_ext.max_video_v_active_height = %d", link->dpcd_caps.dongle_caps.dfp_cap_ext.max_video_v_active_height);
}
-#endif
}
static void dp_wa_power_up_0010FA(struct dc_link *link, uint8_t *dpcd_data,
@@ -5255,12 +5120,8 @@ static bool dpcd_read_sink_ext_caps(struct dc_link *link)
bool dp_retrieve_lttpr_cap(struct dc_link *link)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint8_t lttpr_dpcd_data[8];
bool allow_lttpr_non_transparent_mode = 0;
-#else
- uint8_t lttpr_dpcd_data[6];
-#endif
bool vbios_lttpr_enable = link->dc->caps.vbios_lttpr_enable;
bool vbios_lttpr_interop = link->dc->caps.vbios_lttpr_aware;
enum dc_status status = DC_ERROR_UNEXPECTED;
@@ -5268,7 +5129,6 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
memset(lttpr_dpcd_data, '\0', sizeof(lttpr_dpcd_data));
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if ((link->dc->config.allow_lttpr_non_transparent_mode.bits.DP2_0 &&
link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED)) {
allow_lttpr_non_transparent_mode = 1;
@@ -5276,7 +5136,6 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
allow_lttpr_non_transparent_mode = 1;
}
-#endif
/*
* Logic to determine LTTPR mode
@@ -5285,25 +5144,17 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
if (vbios_lttpr_enable && vbios_lttpr_interop)
link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
else if (!vbios_lttpr_enable && vbios_lttpr_interop) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (allow_lttpr_non_transparent_mode)
-#else
- if (link->dc->config.allow_lttpr_non_transparent_mode)
-#endif
link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
else
link->lttpr_mode = LTTPR_MODE_TRANSPARENT;
} else if (!vbios_lttpr_enable && !vbios_lttpr_interop) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (!allow_lttpr_non_transparent_mode || !link->dc->caps.extended_aux_timeout_support)
-#else
- if (!link->dc->config.allow_lttpr_non_transparent_mode
- || !link->dc->caps.extended_aux_timeout_support)
-#endif
link->lttpr_mode = LTTPR_MODE_NON_LTTPR;
else
link->lttpr_mode = LTTPR_MODE_NON_TRANSPARENT;
}
+
#if defined(CONFIG_DRM_AMD_DC_DCN)
/* Check DP tunnel LTTPR mode debug option. */
if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
@@ -5320,10 +5171,6 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
lttpr_dpcd_data,
sizeof(lttpr_dpcd_data));
- if (status != DC_OK) {
- DC_LOG_DP2("%s: Read LTTPR caps data failed.\n", __func__);
- return false;
- }
link->dpcd_caps.lttpr_caps.revision.raw =
lttpr_dpcd_data[DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV -
@@ -5348,21 +5195,16 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
link->dpcd_caps.lttpr_caps.max_ext_timeout =
lttpr_dpcd_data[DP_PHY_REPEATER_EXTENDED_WAIT_TIMEOUT -
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
link->dpcd_caps.lttpr_caps.main_link_channel_coding.raw =
lttpr_dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_PHY_REPEATER -
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
link->dpcd_caps.lttpr_caps.supported_128b_132b_rates.raw =
- lttpr_dpcd_data[DP_PHY_REPEATER_128b_132b_RATES -
+ lttpr_dpcd_data[DP_PHY_REPEATER_128B132B_RATES -
DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV];
-#endif
/* Attempt to train in LTTPR transparent mode if repeater count exceeds 8. */
- is_lttpr_present = (dp_convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) != 0 &&
- link->dpcd_caps.lttpr_caps.phy_repeater_cnt < 0xff &&
- link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
+ is_lttpr_present = (link->dpcd_caps.lttpr_caps.max_lane_count > 0 &&
link->dpcd_caps.lttpr_caps.max_lane_count <= 4 &&
link->dpcd_caps.lttpr_caps.revision.raw >= 0x14);
if (is_lttpr_present) {
@@ -5374,6 +5216,110 @@ bool dp_retrieve_lttpr_cap(struct dc_link *link)
return is_lttpr_present;
}
+static bool get_usbc_cable_id(struct dc_link *link, union dp_cable_id *cable_id)
+{
+ union dmub_rb_cmd cmd;
+
+ if (!link->ctx->dmub_srv ||
+ link->ep_type != DISPLAY_ENDPOINT_PHY ||
+ link->link_enc->features.flags.bits.DP_IS_USB_C == 0)
+ return false;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.cable_id.header.type = DMUB_CMD_GET_USBC_CABLE_ID;
+ cmd.cable_id.header.payload_bytes = sizeof(cmd.cable_id.data);
+ cmd.cable_id.data.input.phy_inst = resource_transmitter_to_phy_idx(
+ link->dc, link->link_enc->transmitter);
+ if (dc_dmub_srv_cmd_with_reply_data(link->ctx->dmub_srv, &cmd) &&
+ cmd.cable_id.header.ret_status == 1)
+ cable_id->raw = cmd.cable_id.data.output_raw;
+
+ return cmd.cable_id.header.ret_status == 1;
+}
+
+static union dp_cable_id intersect_cable_id(
+ union dp_cable_id *a, union dp_cable_id *b)
+{
+ union dp_cable_id out;
+
+ out.bits.UHBR10_20_CAPABILITY = MIN(a->bits.UHBR10_20_CAPABILITY,
+ b->bits.UHBR10_20_CAPABILITY);
+ out.bits.UHBR13_5_CAPABILITY = MIN(a->bits.UHBR13_5_CAPABILITY,
+ b->bits.UHBR13_5_CAPABILITY);
+ out.bits.CABLE_TYPE = MAX(a->bits.CABLE_TYPE, b->bits.CABLE_TYPE);
+
+ return out;
+}
+
+static void retrieve_cable_id(struct dc_link *link)
+{
+ union dp_cable_id usbc_cable_id;
+
+ link->dpcd_caps.cable_id.raw = 0;
+ core_link_read_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX,
+ &link->dpcd_caps.cable_id.raw, sizeof(uint8_t));
+
+ if (get_usbc_cable_id(link, &usbc_cable_id))
+ link->dpcd_caps.cable_id = intersect_cable_id(
+ &link->dpcd_caps.cable_id, &usbc_cable_id);
+}
+
+/* DPRX may take some time to respond to AUX messages after HPD asserted.
+ * If AUX read unsuccessful, try to wake unresponsive DPRX by toggling DPCD SET_POWER (0x600).
+ */
+static enum dc_status wa_try_to_wake_dprx(struct dc_link *link, uint64_t timeout_ms)
+{
+ enum dc_status status = DC_ERROR_UNEXPECTED;
+ uint8_t dpcd_data = 0;
+ uint64_t start_ts = 0;
+ uint64_t current_ts = 0;
+ uint64_t time_taken_ms = 0;
+ enum dc_connection_type type = dc_connection_none;
+
+ status = core_link_read_dpcd(
+ link,
+ DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV,
+ &dpcd_data,
+ sizeof(dpcd_data));
+
+ if (status != DC_OK) {
+ DC_LOG_WARNING("%s: Read DPCD LTTPR_CAP failed - try to toggle DPCD SET_POWER for %lld ms.",
+ __func__,
+ timeout_ms);
+ start_ts = dm_get_timestamp(link->ctx);
+
+ do {
+ if (!dc_link_detect_sink(link, &type) || type == dc_connection_none)
+ break;
+
+ dpcd_data = DP_SET_POWER_D3;
+ status = core_link_write_dpcd(
+ link,
+ DP_SET_POWER,
+ &dpcd_data,
+ sizeof(dpcd_data));
+
+ dpcd_data = DP_SET_POWER_D0;
+ status = core_link_write_dpcd(
+ link,
+ DP_SET_POWER,
+ &dpcd_data,
+ sizeof(dpcd_data));
+
+ current_ts = dm_get_timestamp(link->ctx);
+ time_taken_ms = div_u64(dm_get_elapse_time_in_ns(link->ctx, current_ts, start_ts), 1000000);
+ } while (status != DC_OK && time_taken_ms < timeout_ms);
+
+ DC_LOG_WARNING("%s: DPCD SET_POWER %s after %lld ms%s",
+ __func__,
+ (status == DC_OK) ? "succeeded" : "failed",
+ time_taken_ms,
+ (type == dc_connection_none) ? ". Unplugged." : ".");
+ }
+
+ return status;
+}
+
static bool retrieve_link_cap(struct dc_link *link)
{
/* DP_ADAPTER_CAP - DP_DPCD_REV + 1 == 16 and also DP_DSC_BITS_PER_PIXEL_INC - DP_DSC_SUPPORT + 1 == 16,
@@ -5409,6 +5355,15 @@ static bool retrieve_link_cap(struct dc_link *link)
dc_link_aux_try_to_configure_timeout(link->ddc,
LINK_AUX_DEFAULT_LTTPR_TIMEOUT_PERIOD);
+ /* Try to ensure AUX channel active before proceeding. */
+ if (link->dc->debug.aux_wake_wa.bits.enable_wa) {
+ uint64_t timeout_ms = link->dc->debug.aux_wake_wa.bits.timeout_ms;
+
+ if (link->dc->debug.aux_wake_wa.bits.use_default_timeout)
+ timeout_ms = LINK_AUX_WAKE_TIMEOUT_MS;
+ status = wa_try_to_wake_dprx(link, timeout_ms);
+ }
+
is_lttpr_present = dp_retrieve_lttpr_cap(link);
/* Read DP tunneling information. */
status = dpcd_get_tunneling_device_data(link);
@@ -5516,6 +5471,9 @@ static bool retrieve_link_cap(struct dc_link *link)
read_dp_device_vendor_id(link);
+ /* TODO - decouple raw mst capability from policy decision */
+ link->dpcd_caps.is_mst_capable = is_mst_supported(link);
+
get_active_converter_info(ds_port.byte, link);
dp_wa_power_up_0010FA(link, dpcd_data, sizeof(dpcd_data));
@@ -5534,8 +5492,8 @@ static bool retrieve_link_cap(struct dc_link *link)
link->reported_link_cap.lane_count =
link->dpcd_caps.max_ln_count.bits.MAX_LANE_COUNT;
- link->reported_link_cap.link_rate = dpcd_data[
- DP_MAX_LINK_RATE - DP_DPCD_REV];
+ link->reported_link_cap.link_rate = get_link_rate_from_max_link_bw(
+ dpcd_data[DP_MAX_LINK_RATE - DP_DPCD_REV]);
link->reported_link_cap.link_spread =
link->dpcd_caps.max_down_spread.bits.MAX_DOWN_SPREAD ?
LINK_SPREAD_05_DOWNSPREAD_30KHZ : LINK_SPREAD_DISABLED;
@@ -5546,7 +5504,8 @@ static bool retrieve_link_cap(struct dc_link *link)
edp_config_cap.bits.ALT_SCRAMBLER_RESET;
link->dpcd_caps.dpcd_display_control_capable =
edp_config_cap.bits.DPCD_DISPLAY_CONTROL_CAPABLE;
-
+ link->dpcd_caps.channel_coding_cap.raw =
+ dpcd_data[DP_MAIN_LINK_CHANNEL_CODING - DP_DPCD_REV];
link->test_pattern_enabled = false;
link->compliance_test_state.raw = 0;
@@ -5632,7 +5591,6 @@ static bool retrieve_link_cap(struct dc_link *link)
DP_DSC_SUPPORT,
link->dpcd_caps.dsc_caps.dsc_basic_caps.raw,
sizeof(link->dpcd_caps.dsc_caps.dsc_basic_caps.raw));
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (link->dpcd_caps.dongle_type != DISPLAY_DONGLE_NONE) {
status = core_link_read_dpcd(
link,
@@ -5647,21 +5605,31 @@ static bool retrieve_link_cap(struct dc_link *link)
DC_LOG_DSC("\tBRANCH_MAX_LINE_WIDTH 0x%02x",
link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.fields.BRANCH_MAX_LINE_WIDTH);
}
-#else
- status = core_link_read_dpcd(
- link,
- DP_DSC_BRANCH_OVERALL_THROUGHPUT_0,
- link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw,
- sizeof(link->dpcd_caps.dsc_caps.dsc_branch_decoder_caps.raw));
-#endif
+
+ /* Apply work around to disable FEC and DSC for USB4 tunneling in TBT3 compatibility mode
+ * only if required.
+ */
+ if (link->ep_type == DISPLAY_ENDPOINT_USB4_DPIA &&
+ !link->dc->debug.dpia_debug.bits.disable_force_tbt3_work_around &&
+ link->dpcd_caps.is_branch_dev &&
+ link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_90CC24 &&
+ link->dpcd_caps.branch_hw_revision == DP_BRANCH_HW_REV_10 &&
+ (link->dpcd_caps.fec_cap.bits.FEC_CAPABLE ||
+ link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)) {
+ /* A TBT3 device is expected to report no support for FEC or DSC to a USB4 DPIA.
+ * Clear FEC and DSC capabilities as a work around if that is not the case.
+ */
+ link->wa_flags.dpia_forced_tbt3_mode = true;
+ memset(&link->dpcd_caps.dsc_caps, '\0', sizeof(link->dpcd_caps.dsc_caps));
+ memset(&link->dpcd_caps.fec_cap, '\0', sizeof(link->dpcd_caps.fec_cap));
+ DC_LOG_DSC("Clear DSC SUPPORT for USB4 link(%d) in TBT3 compatibility mode", link->link_index);
+ } else
+ link->wa_flags.dpia_forced_tbt3_mode = false;
}
if (!dpcd_read_sink_ext_caps(link))
link->dpcd_sink_ext_caps.raw = 0;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- link->dpcd_caps.channel_coding_cap.raw = dpcd_data[DP_MAIN_LINK_CHANNEL_CODING_CAP - DP_DPCD_REV];
-
if (link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED) {
DC_LOG_DP2("128b/132b encoding is supported at link %d", link->link_index);
@@ -5706,7 +5674,9 @@ static bool retrieve_link_cap(struct dc_link *link)
if (link->dpcd_caps.fec_cap1.bits.AGGREGATED_ERROR_COUNTERS_CAPABLE)
DC_LOG_DP2("\tFEC aggregated error counters are supported");
}
-#endif
+
+ retrieve_cable_id(link);
+ dpcd_write_cable_id_to_dprx(link);
/* Connectivity log: detection */
CONN_DATA_DETECT(link, dpcd_data, sizeof(dpcd_data), "Rx Caps: ");
@@ -5779,14 +5749,6 @@ bool dp_overwrite_extended_receiver_cap(struct dc_link *link)
bool detect_dp_sink_caps(struct dc_link *link)
{
return retrieve_link_cap(link);
-
- /* dc init_hw has power encoder using default
- * signal for connector. For native DP, no
- * need to power up encoder again. If not native
- * DP, hw_init may need check signal or power up
- * encoder here.
- */
- /* TODO save sink caps in link->sink */
}
static enum dc_link_rate linkRateInKHzToLinkRateMultiplier(uint32_t link_rate_in_khz)
@@ -5864,8 +5826,6 @@ void detect_edp_sink_caps(struct dc_link *link)
}
}
}
- link->verified_link_cap = link->reported_link_cap;
-
core_link_read_dpcd(link, DP_EDP_BACKLIGHT_ADJUSTMENT_CAP,
&backlight_adj_cap, sizeof(backlight_adj_cap));
@@ -5873,6 +5833,38 @@ void detect_edp_sink_caps(struct dc_link *link)
(backlight_adj_cap & DP_EDP_DYNAMIC_BACKLIGHT_CAP) ? true:false;
dc_link_set_default_brightness_aux(link);
+
+ core_link_read_dpcd(link, DP_EDP_DPCD_REV,
+ &link->dpcd_caps.edp_rev,
+ sizeof(link->dpcd_caps.edp_rev));
+ /*
+ * PSR is only valid for eDP v1.3 or higher.
+ */
+ if (link->dpcd_caps.edp_rev >= DP_EDP_13) {
+ core_link_read_dpcd(link, DP_PSR_SUPPORT,
+ &link->dpcd_caps.psr_info.psr_version,
+ sizeof(link->dpcd_caps.psr_info.psr_version));
+ if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8)
+ core_link_read_dpcd(link, DP_FORCE_PSRSU_CAPABILITY,
+ &link->dpcd_caps.psr_info.force_psrsu_cap,
+ sizeof(link->dpcd_caps.psr_info.force_psrsu_cap));
+ core_link_read_dpcd(link, DP_PSR_CAPS,
+ &link->dpcd_caps.psr_info.psr_dpcd_caps.raw,
+ sizeof(link->dpcd_caps.psr_info.psr_dpcd_caps.raw));
+ if (link->dpcd_caps.psr_info.psr_dpcd_caps.bits.Y_COORDINATE_REQUIRED) {
+ core_link_read_dpcd(link, DP_PSR2_SU_Y_GRANULARITY,
+ &link->dpcd_caps.psr_info.psr2_su_y_granularity_cap,
+ sizeof(link->dpcd_caps.psr_info.psr2_su_y_granularity_cap));
+ }
+ }
+
+ /*
+ * ALPM is only valid for eDP v1.4 or higher.
+ */
+ if (link->dpcd_caps.dpcd_rev.raw >= DP_EDP_14)
+ core_link_read_dpcd(link, DP_RECEIVER_ALPM_CAP,
+ &link->dpcd_caps.alpm_caps.raw,
+ sizeof(link->dpcd_caps.alpm_caps.raw));
}
void dc_link_dp_enable_hpd(const struct dc_link *link)
@@ -6031,7 +6023,7 @@ static void set_crtc_test_pattern(struct dc_link *link,
else if (link->dc->hwss.set_disp_pattern_generator) {
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
- int dpg_width = width;
+ int dpg_width;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
@@ -6130,15 +6122,14 @@ bool dc_link_dp_set_test_pattern(
if (link->dc->debug.apply_vendor_specific_lttpr_wa &&
(link->chip_caps & EXT_DISPLAY_PATH_CAPS__DP_FIXED_VS_EN) &&
link->lttpr_mode == LTTPR_MODE_TRANSPARENT) {
- dpcd_set_lane_settings(link, p_link_settings, DPRX);
- vendor_specific_lttpr_wa_five(
+ dp_fixed_vs_pe_set_retimer_lane_settings(
link,
p_link_settings->dpcd_lane_settings,
p_link_settings->link_settings.lane_count);
} else {
dp_set_hw_lane_settings(link, &pipe_ctx->link_res, p_link_settings, DPRX);
- dpcd_set_lane_settings(link, p_link_settings, DPRX);
}
+ dpcd_set_lane_settings(link, p_link_settings, DPRX);
}
/* Blank stream if running test pattern */
@@ -6188,7 +6179,6 @@ bool dc_link_dp_set_test_pattern(
case DP_TEST_PATTERN_CP2520_3:
pattern = PHY_TEST_PATTERN_CP2520_3;
break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case DP_TEST_PATTERN_128b_132b_TPS1:
pattern = PHY_TEST_PATTERN_128b_132b_TPS1;
break;
@@ -6216,7 +6206,6 @@ bool dc_link_dp_set_test_pattern(
case DP_TEST_PATTERN_SQUARE_PULSE:
pattern = PHY_TEST_PATTERN_SQUARE_PULSE;
break;
-#endif
default:
return false;
}
@@ -6482,14 +6471,7 @@ enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource
enum dc_status status = DC_OK;
uint8_t fec_config = 0;
- /* Access link encoder based on whether it is statically
- * or dynamically assigned to a link.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- else
- link_enc = link->link_enc;
+ link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
if (!dc_link_should_enable_fec(link))
@@ -6529,14 +6511,7 @@ void dp_set_fec_enable(struct dc_link *link, bool enable)
{
struct link_encoder *link_enc = NULL;
- /* Access link encoder based on whether it is statically
- * or dynamically assigned to a link.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- else
- link_enc = link->link_enc;
+ link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
if (!dc_link_should_enable_fec(link))
@@ -6562,23 +6537,6 @@ void dp_set_fec_enable(struct dc_link *link, bool enable)
}
}
-struct link_encoder *dp_get_link_enc(struct dc_link *link)
-{
- struct link_encoder *link_enc;
-
- link_enc = link->link_enc;
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign) {
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc,
- link);
- if (!link->link_enc)
- link_enc = link_enc_cfg_get_next_avail_link_enc(
- link->ctx->dc);
- }
-
- return link_enc;
-}
-
void dpcd_set_source_specific_data(struct dc_link *link)
{
if (!link->dc->vendor_signature.is_valid) {
@@ -6655,6 +6613,20 @@ void dpcd_set_source_specific_data(struct dc_link *link)
}
}
+void dpcd_write_cable_id_to_dprx(struct dc_link *link)
+{
+ if (!link->dpcd_caps.channel_coding_cap.bits.DP_128b_132b_SUPPORTED ||
+ link->dpcd_caps.cable_id.raw == 0 ||
+ link->dprx_states.cable_id_written)
+ return;
+
+ core_link_write_dpcd(link, DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX,
+ &link->dpcd_caps.cable_id.raw,
+ sizeof(link->dpcd_caps.cable_id.raw));
+
+ link->dprx_states.cable_id_written = 1;
+}
+
bool dc_link_set_backlight_level_nits(struct dc_link *link,
bool isHDR,
uint32_t backlight_millinits,
@@ -6819,15 +6791,12 @@ enum dp_link_encoding dp_get_link_encoding_format(const struct dc_link_settings
if ((link_settings->link_rate >= LINK_RATE_LOW) &&
(link_settings->link_rate <= LINK_RATE_HIGH3))
return DP_8b_10b_ENCODING;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
else if ((link_settings->link_rate >= LINK_RATE_UHBR10) &&
(link_settings->link_rate <= LINK_RATE_UHBR20))
return DP_128b_132b_ENCODING;
-#endif
return DP_UNKNOWN_ENCODING;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link)
{
struct dc_link_settings link_settings = {0};
@@ -7044,7 +7013,6 @@ bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx)
pipe_ctx->link_res.hpo_dp_link_enc &&
dc_is_dp_signal(pipe_ctx->stream->signal));
}
-#endif
void edp_panel_backlight_power_on(struct dc_link *link)
{
@@ -7056,3 +7024,623 @@ void edp_panel_backlight_power_on(struct dc_link *link)
if (link->dc->hwss.edp_backlight_control)
link->dc->hwss.edp_backlight_control(link, true);
}
+
+void dc_link_clear_dprx_states(struct dc_link *link)
+{
+ memset(&link->dprx_states, 0, sizeof(link->dprx_states));
+}
+
+void dp_receiver_power_ctrl(struct dc_link *link, bool on)
+{
+ uint8_t state;
+
+ state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
+
+ if (link->sync_lt_in_progress)
+ return;
+
+ core_link_write_dpcd(link, DP_SET_POWER, &state,
+ sizeof(state));
+
+}
+
+void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode)
+{
+ if (link != NULL && link->dc->debug.enable_driver_sequence_debug)
+ core_link_write_dpcd(link, DP_SOURCE_SEQUENCE,
+ &dp_test_mode, sizeof(dp_test_mode));
+}
+
+
+static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
+{
+ switch (lttpr_repeater_count) {
+ case 0x80: // 1 lttpr repeater
+ return 1;
+ case 0x40: // 2 lttpr repeaters
+ return 2;
+ case 0x20: // 3 lttpr repeaters
+ return 3;
+ case 0x10: // 4 lttpr repeaters
+ return 4;
+ case 0x08: // 5 lttpr repeaters
+ return 5;
+ case 0x04: // 6 lttpr repeaters
+ return 6;
+ case 0x02: // 7 lttpr repeaters
+ return 7;
+ case 0x01: // 8 lttpr repeaters
+ return 8;
+ default:
+ break;
+ }
+ return 0; // invalid value
+}
+
+static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset)
+{
+ return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset);
+}
+
+void dp_enable_link_phy(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ struct pipe_ctx *pipes =
+ link->dc->current_state->res_ctx.pipe_ctx;
+ struct clock_source *dp_cs =
+ link->dc->res_pool->dp_clock_source;
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+ unsigned int i;
+
+ if (link->connector_signal == SIGNAL_TYPE_EDP) {
+ link->dc->hwss.edp_power_control(link, true);
+ link->dc->hwss.edp_wait_for_hpd_ready(link, true);
+ }
+
+ /* If the current pixel clock source is not DTO(happens after
+ * switching from HDMI passive dongle to DP on the same connector),
+ * switch the pixel clock source to DTO.
+ */
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (pipes[i].stream != NULL &&
+ pipes[i].stream->link == link) {
+ if (pipes[i].clock_source != NULL &&
+ pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
+ pipes[i].clock_source = dp_cs;
+ pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz =
+ pipes[i].stream->timing.pix_clk_100hz;
+ pipes[i].clock_source->funcs->program_pix_clk(
+ pipes[i].clock_source,
+ &pipes[i].stream_res.pix_clk_params,
+ &pipes[i].pll_settings);
+ }
+ }
+ }
+
+ link->cur_link_settings = *link_settings;
+
+ if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
+ if (dc->clk_mgr->funcs->notify_link_rate_change)
+ dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
+ }
+
+ if (dmcu != NULL && dmcu->funcs->lock_phy)
+ dmcu->funcs->lock_phy(dmcu);
+
+ if (link_hwss->ext.enable_dp_link_output)
+ link_hwss->ext.enable_dp_link_output(link, link_res, signal,
+ clock_source, link_settings);
+
+ if (dmcu != NULL && dmcu->funcs->unlock_phy)
+ dmcu->funcs->unlock_phy(dmcu);
+
+ dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
+ dp_receiver_power_ctrl(link, true);
+}
+
+void edp_add_delay_for_T9(struct dc_link *link)
+{
+ if (link->local_sink &&
+ link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off > 0)
+ udelay(link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off * 1000);
+}
+
+bool edp_receiver_ready_T9(struct dc_link *link)
+{
+ unsigned int tries = 0;
+ unsigned char sinkstatus = 0;
+ unsigned char edpRev = 0;
+ enum dc_status result = DC_OK;
+
+ result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
+
+ /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
+ if (result == DC_OK && edpRev >= DP_EDP_12) {
+ do {
+ sinkstatus = 1;
+ result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
+ if (sinkstatus == 0)
+ break;
+ if (result != DC_OK)
+ break;
+ udelay(100); //MAx T9
+ } while (++tries < 50);
+ }
+
+ return result;
+}
+bool edp_receiver_ready_T7(struct dc_link *link)
+{
+ unsigned char sinkstatus = 0;
+ unsigned char edpRev = 0;
+ enum dc_status result = DC_OK;
+
+ /* use absolute time stamp to constrain max T7*/
+ unsigned long long enter_timestamp = 0;
+ unsigned long long finish_timestamp = 0;
+ unsigned long long time_taken_in_ns = 0;
+
+ result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
+
+ if (result == DC_OK && edpRev >= DP_EDP_12) {
+ /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
+ enter_timestamp = dm_get_timestamp(link->ctx);
+ do {
+ sinkstatus = 0;
+ result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
+ if (sinkstatus == 1)
+ break;
+ if (result != DC_OK)
+ break;
+ udelay(25);
+ finish_timestamp = dm_get_timestamp(link->ctx);
+ time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, enter_timestamp);
+ } while (time_taken_in_ns < 50 * 1000000); //MAx T7 is 50ms
+ }
+
+ if (link->local_sink &&
+ link->local_sink->edid_caps.panel_patch.extra_t7_ms > 0)
+ udelay(link->local_sink->edid_caps.panel_patch.extra_t7_ms * 1000);
+
+ return result;
+}
+
+void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ struct dc *dc = link->ctx->dc;
+ struct dmcu *dmcu = dc->res_pool->dmcu;
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+
+ if (!link->wa_flags.dp_keep_receiver_powered)
+ dp_receiver_power_ctrl(link, false);
+
+ if (signal == SIGNAL_TYPE_EDP) {
+ if (link->dc->hwss.edp_backlight_control)
+ link->dc->hwss.edp_backlight_control(link, false);
+ if (link_hwss->ext.disable_dp_link_output)
+ link_hwss->ext.disable_dp_link_output(link, link_res, signal);
+ link->dc->hwss.edp_power_control(link, false);
+ } else {
+ if (dmcu != NULL && dmcu->funcs->lock_phy)
+ dmcu->funcs->lock_phy(dmcu);
+ if (link_hwss->ext.disable_dp_link_output)
+ link_hwss->ext.disable_dp_link_output(link, link_res, signal);
+ if (dmcu != NULL && dmcu->funcs->unlock_phy)
+ dmcu->funcs->unlock_phy(dmcu);
+ }
+
+ dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+
+ /* Clear current link setting.*/
+ memset(&link->cur_link_settings, 0,
+ sizeof(link->cur_link_settings));
+
+ if (dc->clk_mgr->funcs->notify_link_rate_change)
+ dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
+}
+
+void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ /* MST disable link only when no stream use the link */
+ if (link->mst_stream_alloc_table.stream_count > 0)
+ return;
+
+ dp_disable_link_phy(link, link_res, signal);
+
+ /* set the sink to SST mode after disabling the link */
+ dp_enable_mst_on_sink(link, false);
+}
+
+bool dp_set_hw_training_pattern(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum dc_dp_training_pattern pattern,
+ uint32_t offset)
+{
+ enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
+
+ switch (pattern) {
+ case DP_TRAINING_PATTERN_SEQUENCE_1:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_2:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_3:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
+ break;
+ case DP_TRAINING_PATTERN_SEQUENCE_4:
+ test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
+ break;
+ case DP_128b_132b_TPS1:
+ test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
+ break;
+ case DP_128b_132b_TPS2:
+ test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
+ break;
+ default:
+ break;
+ }
+
+ dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
+
+ return true;
+}
+
+void dp_set_hw_lane_settings(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct link_training_settings *link_settings,
+ uint32_t offset)
+{
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+
+ if ((link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && !is_immediate_downstream(link, offset))
+ return;
+
+ if (link_hwss->ext.set_dp_lane_settings)
+ link_hwss->ext.set_dp_lane_settings(link, link_res,
+ &link_settings->link_settings,
+ link_settings->hw_lane_settings);
+
+ memmove(link->cur_lane_setting,
+ link_settings->hw_lane_settings,
+ sizeof(link->cur_lane_setting));
+}
+
+void dp_set_hw_test_pattern(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum dp_test_pattern test_pattern,
+ uint8_t *custom_pattern,
+ uint32_t custom_pattern_size)
+{
+ const struct link_hwss *link_hwss = get_link_hwss(link, link_res);
+ struct encoder_set_dp_phy_pattern_param pattern_param = {0};
+
+ pattern_param.dp_phy_pattern = test_pattern;
+ pattern_param.custom_pattern = custom_pattern;
+ pattern_param.custom_pattern_size = custom_pattern_size;
+ pattern_param.dp_panel_mode = dp_get_panel_mode(link);
+
+ if (link_hwss->ext.set_dp_link_test_pattern)
+ link_hwss->ext.set_dp_link_test_pattern(link, link_res, &pattern_param);
+}
+
+void dp_retrain_link_dp_test(struct dc_link *link,
+ struct dc_link_settings *link_setting,
+ bool skip_video_pattern)
+{
+ struct pipe_ctx *pipes =
+ &link->dc->current_state->res_ctx.pipe_ctx[0];
+ unsigned int i;
+
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ if (pipes[i].stream != NULL &&
+ !pipes[i].top_pipe && !pipes[i].prev_odm_pipe &&
+ pipes[i].stream->link != NULL &&
+ pipes[i].stream_res.stream_enc != NULL &&
+ pipes[i].stream->link == link) {
+ udelay(100);
+
+ pipes[i].stream_res.stream_enc->funcs->dp_blank(link,
+ pipes[i].stream_res.stream_enc);
+
+ /* disable any test pattern that might be active */
+ dp_set_hw_test_pattern(link, &pipes[i].link_res,
+ DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
+
+ dp_receiver_power_ctrl(link, false);
+
+ link->dc->hwss.disable_stream(&pipes[i]);
+ if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only)
+ (&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio);
+
+ if (link->link_enc)
+ link->link_enc->funcs->disable_output(
+ link->link_enc,
+ SIGNAL_TYPE_DISPLAY_PORT);
+
+ /* Clear current link setting. */
+ memset(&link->cur_link_settings, 0,
+ sizeof(link->cur_link_settings));
+
+ perform_link_training_with_retries(
+ link_setting,
+ skip_video_pattern,
+ LINK_TRAINING_ATTEMPTS,
+ &pipes[i],
+ SIGNAL_TYPE_DISPLAY_PORT,
+ false);
+
+ link->dc->hwss.enable_stream(&pipes[i]);
+
+ link->dc->hwss.unblank_stream(&pipes[i],
+ link_setting);
+
+ if (pipes[i].stream_res.audio) {
+ /* notify audio driver for
+ * audio modes of monitor */
+ pipes[i].stream_res.audio->funcs->az_enable(
+ pipes[i].stream_res.audio);
+
+ /* un-mute audio */
+ /* TODO: audio should be per stream rather than
+ * per link */
+ pipes[i].stream_res.stream_enc->funcs->
+ audio_mute_control(
+ pipes[i].stream_res.stream_enc, false);
+ }
+ }
+ }
+}
+
+#undef DC_LOGGER
+#define DC_LOGGER \
+ dsc->ctx->logger
+static void dsc_optc_config_log(struct display_stream_compressor *dsc,
+ struct dsc_optc_config *config)
+{
+ uint32_t precision = 1 << 28;
+ uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision;
+ uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision;
+ uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod;
+
+ /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC
+ * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is
+ * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal
+ */
+ ll_bytes_per_pix_fraq *= 10000000;
+ ll_bytes_per_pix_fraq /= precision;
+
+ DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",
+ config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq);
+ DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444);
+ DC_LOG_DSC("\tslice_width %d", config->slice_width);
+}
+
+bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ bool result = false;
+
+ if (dc_is_virtual_signal(stream->signal) || IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ result = true;
+ else
+ result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable);
+ return result;
+}
+
+/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
+ * i.e. after dp_enable_dsc_on_rx() had been called
+ */
+void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct pipe_ctx *odm_pipe;
+ int opp_cnt = 1;
+
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ opp_cnt++;
+
+ if (enable) {
+ struct dsc_config dsc_cfg;
+ struct dsc_optc_config dsc_optc_cfg;
+ enum optc_dsc_mode optc_dsc_mode;
+
+ /* Enable DSC hw block */
+ dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
+ dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+ dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+ dsc_cfg.color_depth = stream->timing.display_color_depth;
+ dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
+ dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+ ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
+ dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
+
+ dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
+ dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
+ struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
+
+ odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
+ odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
+ }
+ dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
+ dsc_cfg.pic_width *= opp_cnt;
+
+ optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
+
+ /* Enable DSC in encoder */
+ if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)
+ && !is_dp_128b_132b_signal(pipe_ctx)) {
+ DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width);
+
+ /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
+ }
+
+ /* Enable DSC in OPTC */
+ DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
+ dsc_optc_config_log(dsc, &dsc_optc_cfg);
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
+ optc_dsc_mode,
+ dsc_optc_cfg.bytes_per_pixel,
+ dsc_optc_cfg.slice_width);
+ } else {
+ /* disable DSC in OPTC */
+ pipe_ctx->stream_res.tg->funcs->set_dsc_config(
+ pipe_ctx->stream_res.tg,
+ OPTC_DSC_DISABLED, 0, 0);
+
+ /* disable DSC in stream encoder */
+ if (dc_is_dp_signal(stream->signal)) {
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ false,
+ NULL,
+ true);
+ else if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
+ pipe_ctx->stream_res.stream_enc,
+ OPTC_DSC_DISABLED, 0, 0);
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc, false, NULL, true);
+ }
+ }
+
+ /* disable DSC block */
+ pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
+ }
+}
+
+bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ bool result = false;
+
+ if (!pipe_ctx->stream->timing.flags.DSC)
+ goto out;
+ if (!dsc)
+ goto out;
+
+ if (enable) {
+ {
+ dp_set_dsc_on_stream(pipe_ctx, true);
+ result = true;
+ }
+ } else {
+ dp_set_dsc_on_rx(pipe_ctx, false);
+ dp_set_dsc_on_stream(pipe_ctx, false);
+ result = true;
+ }
+out:
+ return result;
+}
+
+/*
+ * For dynamic bpp change case, dsc is programmed with MASTER_UPDATE_LOCK enabled;
+ * hence PPS info packet update need to use frame update instead of immediate update.
+ * Added parameter immediate_update for this purpose.
+ * The decision to use frame update is hard-coded in function dp_update_dsc_config(),
+ * which is the only place where a "false" would be passed in for param immediate_update.
+ *
+ * immediate_update is only applicable when DSC is enabled.
+ */
+bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+
+ if (!pipe_ctx->stream->timing.flags.DSC || !dsc)
+ return false;
+
+ if (enable) {
+ struct dsc_config dsc_cfg;
+ uint8_t dsc_packed_pps[128];
+
+ memset(&dsc_cfg, 0, sizeof(dsc_cfg));
+ memset(dsc_packed_pps, 0, 128);
+
+ /* Enable DSC hw block */
+ dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
+ dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
+ dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
+ dsc_cfg.color_depth = stream->timing.display_color_depth;
+ dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
+ dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
+
+ DC_LOG_DSC(" ");
+ dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
+ memcpy(&stream->dsc_packed_pps[0], &dsc_packed_pps[0], sizeof(stream->dsc_packed_pps));
+ if (dc_is_dp_signal(stream->signal)) {
+ DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id);
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ true,
+ &dsc_packed_pps[0],
+ immediate_update);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc,
+ true,
+ &dsc_packed_pps[0],
+ immediate_update);
+ }
+ } else {
+ /* disable DSC PPS in stream encoder */
+ memset(&stream->dsc_packed_pps[0], 0, sizeof(stream->dsc_packed_pps));
+ if (dc_is_dp_signal(stream->signal)) {
+ if (is_dp_128b_132b_signal(pipe_ctx))
+ pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.hpo_dp_stream_enc,
+ false,
+ NULL,
+ true);
+ else
+ pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
+ pipe_ctx->stream_res.stream_enc, false, NULL, true);
+ }
+ }
+
+ return true;
+}
+
+
+bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
+{
+ struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
+
+ if (!pipe_ctx->stream->timing.flags.DSC)
+ return false;
+ if (!dsc)
+ return false;
+
+ dp_set_dsc_on_stream(pipe_ctx, true);
+ dp_set_dsc_pps_sdp(pipe_ctx, true, false);
+ return true;
+}
+
+#undef DC_LOGGER
+#define DC_LOGGER \
+ link->ctx->logger
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c
index 7f25c11f4248..af110bf9470f 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpcd.c
@@ -27,8 +27,8 @@
#include <dc_link.h>
#include <inc/link_hwss.h>
#include <inc/link_dpcd.h>
-#include "drm/drm_dp_helper.h"
#include <dc_dp_types.h>
+#include <drm/display/drm_dp_helper.h>
#include "dm_helpers.h"
#define END_ADDRESS(start, size) (start + size - 1)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c
index 0e95bc5df4e7..1b7a8774b0c9 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_dpia.c
@@ -34,6 +34,7 @@
#include "dm_helpers.h"
#include "dmub/inc/dmub_cmd.h"
#include "inc/link_dpcd.h"
+#include "dc_dmub_srv.h"
#define DC_LOGGER \
link->ctx->logger
@@ -69,6 +70,24 @@ enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link)
return status;
}
+bool dc_link_dpia_query_hpd_status(struct dc_link *link)
+{
+ union dmub_rb_cmd cmd = {0};
+ struct dc_dmub_srv *dmub_srv = link->ctx->dmub_srv;
+ bool is_hpd_high = false;
+
+ /* prepare QUERY_HPD command */
+ cmd.query_hpd.header.type = DMUB_CMD__QUERY_HPD_STATE;
+ cmd.query_hpd.data.instance = link->link_id.enum_id - ENUM_ID_1;
+ cmd.query_hpd.data.ch_type = AUX_CHANNEL_DPIA;
+
+ /* Return HPD status reported by DMUB if query successfully executed. */
+ if (dc_dmub_srv_cmd_with_reply_data(dmub_srv, &cmd) && cmd.query_hpd.data.status == AUX_RET_SUCCESS)
+ is_hpd_high = cmd.query_hpd.data.result;
+
+ return is_hpd_high;
+}
+
/* Configure link as prescribed in link_setting; set LTTPR mode; and
* Initialize link training settings.
* Abort link training if sink unplug detected.
@@ -547,11 +566,9 @@ static uint32_t dpia_get_eq_aux_rd_interval(const struct dc_link *link,
dp_translate_training_aux_read_interval(
link->dpcd_caps.lttpr_caps.aux_rd_interval[hop - 1]);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* Check debug option for extending aux read interval. */
if (link->dc->debug.dpia_debug.bits.extend_aux_rd_interval)
wait_time_microsec = DPIA_DEBUG_EXTENDED_AUX_RD_INTERVAL_US;
-#endif
return wait_time_microsec;
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
index a55944da8d53..42da7f430113 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_link_enc_cfg.c
@@ -122,6 +122,7 @@ static void remove_link_enc_assignment(
stream->link_enc = NULL;
state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].eng_id = ENGINE_ID_UNKNOWN;
state->res_ctx.link_enc_cfg_ctx.link_enc_assignments[i].stream = NULL;
+ dc_stream_release(stream);
break;
}
}
@@ -271,6 +272,13 @@ void link_enc_cfg_init(
state->res_ctx.link_enc_cfg_ctx.mode = LINK_ENC_CFG_STEADY;
}
+void link_enc_cfg_copy(const struct dc_state *src_ctx, struct dc_state *dst_ctx)
+{
+ memcpy(&dst_ctx->res_ctx.link_enc_cfg_ctx,
+ &src_ctx->res_ctx.link_enc_cfg_ctx,
+ sizeof(dst_ctx->res_ctx.link_enc_cfg_ctx));
+}
+
void link_enc_cfg_link_encs_assign(
struct dc *dc,
struct dc_state *state,
@@ -486,7 +494,8 @@ struct link_encoder *link_enc_cfg_get_next_avail_link_enc(struct dc *dc)
}
for (i = 0; i < dc->res_pool->res_cap->num_dig_link_enc; i++) {
- if (encs_assigned[i] == ENGINE_ID_UNKNOWN) {
+ if (encs_assigned[i] == ENGINE_ID_UNKNOWN &&
+ dc->res_pool->link_encoders[i] != NULL) {
link_enc = dc->res_pool->link_encoders[i];
break;
}
@@ -506,6 +515,26 @@ struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream(
return link_enc;
}
+struct link_encoder *link_enc_cfg_get_link_enc(
+ const struct dc_link *link)
+{
+ struct link_encoder *link_enc = NULL;
+
+ /* Links supporting dynamically assigned link encoder will be assigned next
+ * available encoder if one not already assigned.
+ */
+ if (link->is_dig_mapping_flexible &&
+ link->dc->res_pool->funcs->link_encs_assign) {
+ link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
+ if (link_enc == NULL)
+ link_enc = link_enc_cfg_get_next_avail_link_enc(
+ link->ctx->dc);
+ } else
+ link_enc = link->link_enc;
+
+ return link_enc;
+}
+
bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, struct dc_link *link)
{
bool is_avail = true;
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c b/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
deleted file mode 100644
index 45d03d3a95c3..000000000000
--- a/drivers/gpu/drm/amd/display/dc/core/dc_link_hwss.c
+++ /dev/null
@@ -1,917 +0,0 @@
-/* Copyright 2015 Advanced Micro Devices, Inc. */
-
-
-#include "dm_services.h"
-#include "dc.h"
-#include "inc/core_types.h"
-#include "include/ddc_service_types.h"
-#include "include/i2caux_interface.h"
-#include "link_hwss.h"
-#include "hw_sequencer.h"
-#include "dc_link_dp.h"
-#include "dc_link_ddc.h"
-#include "dm_helpers.h"
-#include "dpcd_defs.h"
-#include "dsc.h"
-#include "resource.h"
-#include "link_enc_cfg.h"
-#include "clk_mgr.h"
-#include "inc/link_dpcd.h"
-#include "dccg.h"
-
-static uint8_t convert_to_count(uint8_t lttpr_repeater_count)
-{
- switch (lttpr_repeater_count) {
- case 0x80: // 1 lttpr repeater
- return 1;
- case 0x40: // 2 lttpr repeaters
- return 2;
- case 0x20: // 3 lttpr repeaters
- return 3;
- case 0x10: // 4 lttpr repeaters
- return 4;
- case 0x08: // 5 lttpr repeaters
- return 5;
- case 0x04: // 6 lttpr repeaters
- return 6;
- case 0x02: // 7 lttpr repeaters
- return 7;
- case 0x01: // 8 lttpr repeaters
- return 8;
- default:
- break;
- }
- return 0; // invalid value
-}
-
-static inline bool is_immediate_downstream(struct dc_link *link, uint32_t offset)
-{
- return (convert_to_count(link->dpcd_caps.lttpr_caps.phy_repeater_cnt) == offset);
-}
-
-void dp_receiver_power_ctrl(struct dc_link *link, bool on)
-{
- uint8_t state;
-
- state = on ? DP_POWER_STATE_D0 : DP_POWER_STATE_D3;
-
- if (link->sync_lt_in_progress)
- return;
-
- core_link_write_dpcd(link, DP_SET_POWER, &state,
- sizeof(state));
-}
-
-void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode)
-{
- if (link != NULL && link->dc->debug.enable_driver_sequence_debug)
- core_link_write_dpcd(link, DP_SOURCE_SEQUENCE,
- &dp_test_mode, sizeof(dp_test_mode));
-}
-
-void dp_enable_link_phy(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum signal_type signal,
- enum clock_source_id clock_source,
- const struct dc_link_settings *link_settings)
-{
- struct link_encoder *link_enc;
- struct dc *dc = link->ctx->dc;
- struct dmcu *dmcu = dc->res_pool->dmcu;
-
- struct pipe_ctx *pipes =
- link->dc->current_state->res_ctx.pipe_ctx;
- struct clock_source *dp_cs =
- link->dc->res_pool->dp_clock_source;
- unsigned int i;
-
- /* Link should always be assigned encoder when en-/disabling. */
- if (link->is_dig_mapping_flexible && dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, link);
- else
- link_enc = link->link_enc;
- ASSERT(link_enc);
-
- if (link->connector_signal == SIGNAL_TYPE_EDP) {
- link->dc->hwss.edp_power_control(link, true);
- link->dc->hwss.edp_wait_for_hpd_ready(link, true);
- }
-
- /* If the current pixel clock source is not DTO(happens after
- * switching from HDMI passive dongle to DP on the same connector),
- * switch the pixel clock source to DTO.
- */
- for (i = 0; i < MAX_PIPES; i++) {
- if (pipes[i].stream != NULL &&
- pipes[i].stream->link == link) {
- if (pipes[i].clock_source != NULL &&
- pipes[i].clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
- pipes[i].clock_source = dp_cs;
- pipes[i].stream_res.pix_clk_params.requested_pix_clk_100hz =
- pipes[i].stream->timing.pix_clk_100hz;
- pipes[i].clock_source->funcs->program_pix_clk(
- pipes[i].clock_source,
- &pipes[i].stream_res.pix_clk_params,
- &pipes[i].pll_settings);
- }
- }
- }
-
- link->cur_link_settings = *link_settings;
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
- /* TODO - DP2.0 HW: notify link rate change here */
- } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
- if (dc->clk_mgr->funcs->notify_link_rate_change)
- dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
- }
-#else
- if (dc->clk_mgr->funcs->notify_link_rate_change)
- dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
-#endif
- if (dmcu != NULL && dmcu->funcs->lock_phy)
- dmcu->funcs->lock_phy(dmcu);
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
- enable_dp_hpo_output(link, link_res, link_settings);
- } else if (dp_get_link_encoding_format(link_settings) == DP_8b_10b_ENCODING) {
- if (dc_is_dp_sst_signal(signal)) {
- link_enc->funcs->enable_dp_output(
- link_enc,
- link_settings,
- clock_source);
- } else {
- link_enc->funcs->enable_dp_mst_output(
- link_enc,
- link_settings,
- clock_source);
- }
- }
-#else
- if (dc_is_dp_sst_signal(signal)) {
- link_enc->funcs->enable_dp_output(
- link_enc,
- link_settings,
- clock_source);
- } else {
- link_enc->funcs->enable_dp_mst_output(
- link_enc,
- link_settings,
- clock_source);
- }
-#endif
- if (dmcu != NULL && dmcu->funcs->unlock_phy)
- dmcu->funcs->unlock_phy(dmcu);
-
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
- dp_receiver_power_ctrl(link, true);
-}
-
-void edp_add_delay_for_T9(struct dc_link *link)
-{
- if (link->local_sink &&
- link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off > 0)
- udelay(link->local_sink->edid_caps.panel_patch.extra_delay_backlight_off * 1000);
-}
-
-bool edp_receiver_ready_T9(struct dc_link *link)
-{
- unsigned int tries = 0;
- unsigned char sinkstatus = 0;
- unsigned char edpRev = 0;
- enum dc_status result;
-
- result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
-
- /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
- if (result == DC_OK && edpRev >= DP_EDP_12) {
- do {
- sinkstatus = 1;
- result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
- if (sinkstatus == 0)
- break;
- if (result != DC_OK)
- break;
- udelay(100); //MAx T9
- } while (++tries < 50);
- }
-
- return result;
-}
-bool edp_receiver_ready_T7(struct dc_link *link)
-{
- unsigned char sinkstatus = 0;
- unsigned char edpRev = 0;
- enum dc_status result;
-
- /* use absolute time stamp to constrain max T7*/
- unsigned long long enter_timestamp = 0;
- unsigned long long finish_timestamp = 0;
- unsigned long long time_taken_in_ns = 0;
-
- result = core_link_read_dpcd(link, DP_EDP_DPCD_REV, &edpRev, sizeof(edpRev));
-
- if (result == DC_OK && edpRev >= DP_EDP_12) {
- /* start from eDP version 1.2, SINK_STAUS indicate the sink is ready.*/
- enter_timestamp = dm_get_timestamp(link->ctx);
- do {
- sinkstatus = 0;
- result = core_link_read_dpcd(link, DP_SINK_STATUS, &sinkstatus, sizeof(sinkstatus));
- if (sinkstatus == 1)
- break;
- if (result != DC_OK)
- break;
- udelay(25);
- finish_timestamp = dm_get_timestamp(link->ctx);
- time_taken_in_ns = dm_get_elapse_time_in_ns(link->ctx, finish_timestamp, enter_timestamp);
- } while (time_taken_in_ns < 50 * 1000000); //MAx T7 is 50ms
- }
-
- if (link->local_sink &&
- link->local_sink->edid_caps.panel_patch.extra_t7_ms > 0)
- udelay(link->local_sink->edid_caps.panel_patch.extra_t7_ms * 1000);
-
- return result;
-}
-
-void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal)
-{
- struct dc *dc = link->ctx->dc;
- struct dmcu *dmcu = dc->res_pool->dmcu;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- struct hpo_dp_link_encoder *hpo_link_enc = link_res->hpo_dp_link_enc;
-#endif
- struct link_encoder *link_enc;
-
- /* Link should always be assigned encoder when en-/disabling. */
- if (link->is_dig_mapping_flexible && dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(dc, link);
- else
- link_enc = link->link_enc;
- ASSERT(link_enc);
-
- if (!link->wa_flags.dp_keep_receiver_powered)
- dp_receiver_power_ctrl(link, false);
-
- if (signal == SIGNAL_TYPE_EDP) {
- if (link->dc->hwss.edp_backlight_control)
- link->dc->hwss.edp_backlight_control(link, false);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING)
- disable_dp_hpo_output(link, link_res, signal);
- else
- link_enc->funcs->disable_output(link_enc, signal);
-#else
- link_enc->funcs->disable_output(link_enc, signal);
-#endif
- link->dc->hwss.edp_power_control(link, false);
- } else {
- if (dmcu != NULL && dmcu->funcs->lock_phy)
- dmcu->funcs->lock_phy(dmcu);
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(&link->cur_link_settings) == DP_128b_132b_ENCODING &&
- hpo_link_enc)
- disable_dp_hpo_output(link, link_res, signal);
- else
- link_enc->funcs->disable_output(link_enc, signal);
-#else
- link_enc->funcs->disable_output(link_enc, signal);
-#endif
- if (dmcu != NULL && dmcu->funcs->unlock_phy)
- dmcu->funcs->unlock_phy(dmcu);
- }
-
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
-
- /* Clear current link setting.*/
- memset(&link->cur_link_settings, 0,
- sizeof(link->cur_link_settings));
-
- if (dc->clk_mgr->funcs->notify_link_rate_change)
- dc->clk_mgr->funcs->notify_link_rate_change(dc->clk_mgr, link);
-}
-
-void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal)
-{
- /* MST disable link only when no stream use the link */
- if (link->mst_stream_alloc_table.stream_count > 0)
- return;
-
- dp_disable_link_phy(link, link_res, signal);
-
- /* set the sink to SST mode after disabling the link */
- dp_enable_mst_on_sink(link, false);
-}
-
-bool dp_set_hw_training_pattern(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum dc_dp_training_pattern pattern,
- uint32_t offset)
-{
- enum dp_test_pattern test_pattern = DP_TEST_PATTERN_UNSUPPORTED;
-
- switch (pattern) {
- case DP_TRAINING_PATTERN_SEQUENCE_1:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN1;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_2:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN2;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_3:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN3;
- break;
- case DP_TRAINING_PATTERN_SEQUENCE_4:
- test_pattern = DP_TEST_PATTERN_TRAINING_PATTERN4;
- break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- case DP_128b_132b_TPS1:
- test_pattern = DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE;
- break;
- case DP_128b_132b_TPS2:
- test_pattern = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE;
- break;
-#endif
- default:
- break;
- }
-
- dp_set_hw_test_pattern(link, link_res, test_pattern, NULL, 0);
-
- return true;
-}
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-#define DC_LOGGER \
- link->ctx->logger
-#endif
-void dp_set_hw_lane_settings(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct link_training_settings *link_settings,
- uint32_t offset)
-{
- struct link_encoder *encoder = link->link_enc;
-
- if ((link->lttpr_mode == LTTPR_MODE_NON_TRANSPARENT) && !is_immediate_downstream(link, offset))
- return;
-
- /* call Encoder to set lane settings */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dp_get_link_encoding_format(&link_settings->link_settings) ==
- DP_128b_132b_ENCODING) {
- link_res->hpo_dp_link_enc->funcs->set_ffe(
- link_res->hpo_dp_link_enc,
- &link_settings->link_settings,
- link_settings->lane_settings[0].FFE_PRESET.raw);
- } else if (dp_get_link_encoding_format(&link_settings->link_settings)
- == DP_8b_10b_ENCODING) {
- encoder->funcs->dp_set_lane_settings(encoder, link_settings);
- }
-#else
- encoder->funcs->dp_set_lane_settings(encoder, link_settings);
-#endif
- memmove(link->cur_lane_setting,
- link_settings->lane_settings,
- sizeof(link->cur_lane_setting));
-}
-
-void dp_set_hw_test_pattern(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum dp_test_pattern test_pattern,
- uint8_t *custom_pattern,
- uint32_t custom_pattern_size)
-{
- struct encoder_set_dp_phy_pattern_param pattern_param = {0};
- struct link_encoder *encoder;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- enum dp_link_encoding link_encoding_format = dp_get_link_encoding_format(&link->cur_link_settings);
-#endif
-
- /* Access link encoder based on whether it is statically
- * or dynamically assigned to a link.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign)
- encoder = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- else
- encoder = link->link_enc;
-
- pattern_param.dp_phy_pattern = test_pattern;
- pattern_param.custom_pattern = custom_pattern;
- pattern_param.custom_pattern_size = custom_pattern_size;
- pattern_param.dp_panel_mode = dp_get_panel_mode(link);
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- switch (link_encoding_format) {
- case DP_128b_132b_ENCODING:
- link_res->hpo_dp_link_enc->funcs->set_link_test_pattern(
- link_res->hpo_dp_link_enc, &pattern_param);
- break;
- case DP_8b_10b_ENCODING:
- ASSERT(encoder);
- encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
- break;
- default:
- DC_LOG_ERROR("%s: Unknown link encoding format.", __func__);
- break;
- }
-#else
- encoder->funcs->dp_set_phy_pattern(encoder, &pattern_param);
-#endif
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
-}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-#undef DC_LOGGER
-#endif
-
-void dp_retrain_link_dp_test(struct dc_link *link,
- struct dc_link_settings *link_setting,
- bool skip_video_pattern)
-{
- struct pipe_ctx *pipes =
- &link->dc->current_state->res_ctx.pipe_ctx[0];
- unsigned int i;
-
- for (i = 0; i < MAX_PIPES; i++) {
- if (pipes[i].stream != NULL &&
- !pipes[i].top_pipe && !pipes[i].prev_odm_pipe &&
- pipes[i].stream->link != NULL &&
- pipes[i].stream_res.stream_enc != NULL &&
- pipes[i].stream->link == link) {
- udelay(100);
-
- pipes[i].stream_res.stream_enc->funcs->dp_blank(link,
- pipes[i].stream_res.stream_enc);
-
- /* disable any test pattern that might be active */
- dp_set_hw_test_pattern(link, &pipes[i].link_res,
- DP_TEST_PATTERN_VIDEO_MODE, NULL, 0);
-
- dp_receiver_power_ctrl(link, false);
-
- link->dc->hwss.disable_stream(&pipes[i]);
- if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only)
- (&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio);
-
- if (link->link_enc)
- link->link_enc->funcs->disable_output(
- link->link_enc,
- SIGNAL_TYPE_DISPLAY_PORT);
-
- /* Clear current link setting. */
- memset(&link->cur_link_settings, 0,
- sizeof(link->cur_link_settings));
-
- perform_link_training_with_retries(
- link_setting,
- skip_video_pattern,
- LINK_TRAINING_ATTEMPTS,
- &pipes[i],
- SIGNAL_TYPE_DISPLAY_PORT,
- false);
-
- link->dc->hwss.enable_stream(&pipes[i]);
-
- link->dc->hwss.unblank_stream(&pipes[i],
- link_setting);
-
- if (pipes[i].stream_res.audio) {
- /* notify audio driver for
- * audio modes of monitor */
- pipes[i].stream_res.audio->funcs->az_enable(
- pipes[i].stream_res.audio);
-
- /* un-mute audio */
- /* TODO: audio should be per stream rather than
- * per link */
- pipes[i].stream_res.stream_enc->funcs->
- audio_mute_control(
- pipes[i].stream_res.stream_enc, false);
- }
- }
- }
-}
-
-#define DC_LOGGER \
- dsc->ctx->logger
-static void dsc_optc_config_log(struct display_stream_compressor *dsc,
- struct dsc_optc_config *config)
-{
- uint32_t precision = 1 << 28;
- uint32_t bytes_per_pixel_int = config->bytes_per_pixel / precision;
- uint32_t bytes_per_pixel_mod = config->bytes_per_pixel % precision;
- uint64_t ll_bytes_per_pix_fraq = bytes_per_pixel_mod;
-
- /* 7 fractional digits decimal precision for bytes per pixel is enough because DSC
- * bits per pixel precision is 1/16th of a pixel, which means bytes per pixel precision is
- * 1/16/8 = 1/128 of a byte, or 0.0078125 decimal
- */
- ll_bytes_per_pix_fraq *= 10000000;
- ll_bytes_per_pix_fraq /= precision;
-
- DC_LOG_DSC("\tbytes_per_pixel 0x%08x (%d.%07d)",
- config->bytes_per_pixel, bytes_per_pixel_int, (uint32_t)ll_bytes_per_pix_fraq);
- DC_LOG_DSC("\tis_pixel_format_444 %d", config->is_pixel_format_444);
- DC_LOG_DSC("\tslice_width %d", config->slice_width);
-}
-
-bool dp_set_dsc_on_rx(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- bool result = false;
-
- if (dc_is_virtual_signal(stream->signal) || IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
- result = true;
- else
- result = dm_helpers_dp_write_dsc_enable(dc->ctx, stream, enable);
- return result;
-}
-
-/* The stream with these settings can be sent (unblanked) only after DSC was enabled on RX first,
- * i.e. after dp_enable_dsc_on_rx() had been called
- */
-void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct pipe_ctx *odm_pipe;
- int opp_cnt = 1;
-
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- opp_cnt++;
-
- if (enable) {
- struct dsc_config dsc_cfg;
- struct dsc_optc_config dsc_optc_cfg;
- enum optc_dsc_mode optc_dsc_mode;
-
- /* Enable DSC hw block */
- dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
- dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
- dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
- dsc_cfg.color_depth = stream->timing.display_color_depth;
- dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
- dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
- ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
- dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
-
- dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
- dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
- struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
-
- odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
- odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
- }
- dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
- dsc_cfg.pic_width *= opp_cnt;
-
- optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
-
- /* Enable DSC in encoder */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)
- && !is_dp_128b_132b_signal(pipe_ctx)) {
-#else
- if (dc_is_dp_signal(stream->signal) && !IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
-#endif
- DC_LOG_DSC("Setting stream encoder DSC config for engine %d:", (int)pipe_ctx->stream_res.stream_enc->id);
- dsc_optc_config_log(dsc, &dsc_optc_cfg);
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(pipe_ctx->stream_res.stream_enc,
- optc_dsc_mode,
- dsc_optc_cfg.bytes_per_pixel,
- dsc_optc_cfg.slice_width);
-
- /* PPS SDP is set elsewhere because it has to be done after DIG FE is connected to DIG BE */
- }
-
- /* Enable DSC in OPTC */
- DC_LOG_DSC("Setting optc DSC config for tg instance %d:", pipe_ctx->stream_res.tg->inst);
- dsc_optc_config_log(dsc, &dsc_optc_cfg);
- pipe_ctx->stream_res.tg->funcs->set_dsc_config(pipe_ctx->stream_res.tg,
- optc_dsc_mode,
- dsc_optc_cfg.bytes_per_pixel,
- dsc_optc_cfg.slice_width);
- } else {
- /* disable DSC in OPTC */
- pipe_ctx->stream_res.tg->funcs->set_dsc_config(
- pipe_ctx->stream_res.tg,
- OPTC_DSC_DISABLED, 0, 0);
-
- /* disable DSC in stream encoder */
- if (dc_is_dp_signal(stream->signal)) {
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- false,
- NULL,
- true);
- else
-#endif
- if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_config(
- pipe_ctx->stream_res.stream_enc,
- OPTC_DSC_DISABLED, 0, 0);
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc, false, NULL, true);
- }
- }
-
- /* disable DSC block */
- pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
- }
-}
-
-bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
- bool result = false;
-
- if (!pipe_ctx->stream->timing.flags.DSC)
- goto out;
- if (!dsc)
- goto out;
-
- if (enable) {
- {
- dp_set_dsc_on_stream(pipe_ctx, true);
- result = true;
- }
- } else {
- dp_set_dsc_on_rx(pipe_ctx, false);
- dp_set_dsc_on_stream(pipe_ctx, false);
- result = true;
- }
-out:
- return result;
-}
-
-/*
- * For dynamic bpp change case, dsc is programmed with MASTER_UPDATE_LOCK enabled;
- * hence PPS info packet update need to use frame update instead of immediate update.
- * Added parameter immediate_update for this purpose.
- * The decision to use frame update is hard-coded in function dp_update_dsc_config(),
- * which is the only place where a "false" would be passed in for param immediate_update.
- *
- * immediate_update is only applicable when DSC is enabled.
- */
-bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
- struct dc_stream_state *stream = pipe_ctx->stream;
-
- if (!pipe_ctx->stream->timing.flags.DSC || !dsc)
- return false;
-
- if (enable) {
- struct dsc_config dsc_cfg;
- uint8_t dsc_packed_pps[128];
-
- memset(&dsc_cfg, 0, sizeof(dsc_cfg));
- memset(dsc_packed_pps, 0, 128);
-
- /* Enable DSC hw block */
- dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
- dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
- dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
- dsc_cfg.color_depth = stream->timing.display_color_depth;
- dsc_cfg.is_odm = pipe_ctx->next_odm_pipe ? true : false;
- dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
-
- DC_LOG_DSC(" ");
- dsc->funcs->dsc_get_packed_pps(dsc, &dsc_cfg, &dsc_packed_pps[0]);
- if (dc_is_dp_signal(stream->signal)) {
- DC_LOG_DSC("Setting stream encoder DSC PPS SDP for engine %d\n", (int)pipe_ctx->stream_res.stream_enc->id);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- true,
- &dsc_packed_pps[0],
- immediate_update);
- else
-#endif
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc,
- true,
- &dsc_packed_pps[0],
- immediate_update);
- }
- } else {
- /* disable DSC PPS in stream encoder */
- if (dc_is_dp_signal(stream->signal)) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (is_dp_128b_132b_signal(pipe_ctx))
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- false,
- NULL,
- true);
- else
-#endif
- pipe_ctx->stream_res.stream_enc->funcs->dp_set_dsc_pps_info_packet(
- pipe_ctx->stream_res.stream_enc, false, NULL, true);
- }
- }
-
- return true;
-}
-
-
-bool dp_update_dsc_config(struct pipe_ctx *pipe_ctx)
-{
- struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
-
- if (!pipe_ctx->stream->timing.flags.DSC)
- return false;
- if (!dsc)
- return false;
-
- dp_set_dsc_on_stream(pipe_ctx, true);
- dp_set_dsc_pps_sdp(pipe_ctx, true, false);
- return true;
-}
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-#undef DC_LOGGER
-#define DC_LOGGER \
- link->ctx->logger
-
-static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
-{
- switch (link->link_enc->transmitter) {
- case TRANSMITTER_UNIPHY_A:
- return PHYD32CLKA;
- case TRANSMITTER_UNIPHY_B:
- return PHYD32CLKB;
- case TRANSMITTER_UNIPHY_C:
- return PHYD32CLKC;
- case TRANSMITTER_UNIPHY_D:
- return PHYD32CLKD;
- case TRANSMITTER_UNIPHY_E:
- return PHYD32CLKE;
- default:
- return PHYD32CLKA;
- }
-}
-
-void enable_dp_hpo_output(struct dc_link *link,
- const struct link_resource *link_res,
- const struct dc_link_settings *link_settings)
-{
- const struct dc *dc = link->dc;
- enum phyd32clk_clock_source phyd32clk;
-
- /* Enable PHY PLL at target bit rate
- * UHBR10 = 10Gbps (SYMCLK32 = 312.5MHz)
- * UBR13.5 = 13.5Gbps (SYMCLK32 = 421.875MHz)
- * UHBR20 = 20Gbps (SYMCLK32 = 625MHz)
- */
- if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
- switch (link_settings->link_rate) {
- case LINK_RATE_UHBR10:
- dm_set_phyd32clk(dc->ctx, 312500);
- break;
- case LINK_RATE_UHBR13_5:
- dm_set_phyd32clk(dc->ctx, 412875);
- break;
- case LINK_RATE_UHBR20:
- dm_set_phyd32clk(dc->ctx, 625000);
- break;
- default:
- return;
- }
- } else {
- /* DP2.0 HW: call transmitter control to enable PHY */
- link_res->hpo_dp_link_enc->funcs->enable_link_phy(
- link_res->hpo_dp_link_enc,
- link_settings,
- link->link_enc->transmitter,
- link->link_enc->hpd_source);
- }
-
- /* DCCG muxing and DTBCLK DTO */
- if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
- dc->res_pool->dccg->funcs->set_physymclk(
- dc->res_pool->dccg,
- link->link_enc_hw_inst,
- PHYSYMCLK_FORCE_SRC_PHYD32CLK,
- true);
-
- phyd32clk = get_phyd32clk_src(link);
- dc->res_pool->dccg->funcs->enable_symclk32_le(
- dc->res_pool->dccg,
- link_res->hpo_dp_link_enc->inst,
- phyd32clk);
- link_res->hpo_dp_link_enc->funcs->link_enable(
- link_res->hpo_dp_link_enc,
- link_settings->lane_count);
- }
-}
-
-void disable_dp_hpo_output(struct dc_link *link,
- const struct link_resource *link_res,
- enum signal_type signal)
-{
- const struct dc *dc = link->dc;
-
- link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
-
- if (IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment)) {
- dc->res_pool->dccg->funcs->disable_symclk32_le(
- dc->res_pool->dccg,
- link_res->hpo_dp_link_enc->inst);
-
- dc->res_pool->dccg->funcs->set_physymclk(
- dc->res_pool->dccg,
- link->link_enc_hw_inst,
- PHYSYMCLK_FORCE_SRC_SYMCLK,
- false);
-
- dm_set_phyd32clk(dc->ctx, 0);
- } else {
- /* DP2.0 HW: call transmitter control to disable PHY */
- link_res->hpo_dp_link_enc->funcs->disable_link_phy(
- link_res->hpo_dp_link_enc,
- signal);
- }
-}
-
-void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable)
-{
- struct dc_stream_state *stream = pipe_ctx->stream;
- struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct pipe_ctx *odm_pipe;
- int odm_combine_num_segments = 1;
- enum phyd32clk_clock_source phyd32clk;
-
- if (enable) {
- for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
- odm_combine_num_segments++;
-
- dc->res_pool->dccg->funcs->set_dpstreamclk(
- dc->res_pool->dccg,
- DTBCLK0,
- pipe_ctx->stream_res.tg->inst);
-
- phyd32clk = get_phyd32clk_src(stream->link);
- dc->res_pool->dccg->funcs->enable_symclk32_se(
- dc->res_pool->dccg,
- pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
- phyd32clk);
-
- dc->res_pool->dccg->funcs->set_dtbclk_dto(
- dc->res_pool->dccg,
- pipe_ctx->stream_res.tg->inst,
- stream->phy_pix_clk,
- odm_combine_num_segments,
- &stream->timing);
- } else {
- dc->res_pool->dccg->funcs->set_dtbclk_dto(
- dc->res_pool->dccg,
- pipe_ctx->stream_res.tg->inst,
- 0,
- 0,
- &stream->timing);
- dc->res_pool->dccg->funcs->disable_symclk32_se(
- dc->res_pool->dccg,
- pipe_ctx->stream_res.hpo_dp_stream_enc->inst);
- dc->res_pool->dccg->funcs->set_dpstreamclk(
- dc->res_pool->dccg,
- REFCLK,
- pipe_ctx->stream_res.tg->inst);
- }
-}
-
-void reset_dp_hpo_stream_encoders_for_link(struct dc_link *link)
-{
- const struct dc *dc = link->dc;
- struct dc_state *state = dc->current_state;
- uint8_t i;
-
- for (i = 0; i < MAX_PIPES; i++) {
- if (state->res_ctx.pipe_ctx[i].stream_res.hpo_dp_stream_enc &&
- state->res_ctx.pipe_ctx[i].stream &&
- state->res_ctx.pipe_ctx[i].stream->link == link &&
- !state->res_ctx.pipe_ctx[i].stream->dpms_off) {
- setup_dp_hpo_stream(&state->res_ctx.pipe_ctx[i], false);
- }
- }
-}
-
-#undef DC_LOGGER
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
index 18757c158523..6774dd8bb53e 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c
@@ -43,6 +43,10 @@
#include "dpcd_defs.h"
#include "link_enc_cfg.h"
#include "dc_link_dp.h"
+#include "virtual/virtual_link_hwss.h"
+#include "link/link_hwss_dio.h"
+#include "link/link_hwss_dpia.h"
+#include "link/link_hwss_hpo_dp.h"
#if defined(CONFIG_DRM_AMD_DC_SI)
#include "dce60/dce60_resource.h"
@@ -52,7 +56,6 @@
#include "dce110/dce110_resource.h"
#include "dce112/dce112_resource.h"
#include "dce120/dce120_resource.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "dcn10/dcn10_resource.h"
#include "dcn20/dcn20_resource.h"
#include "dcn21/dcn21_resource.h"
@@ -62,7 +65,8 @@
#include "dcn302/dcn302_resource.h"
#include "dcn303/dcn303_resource.h"
#include "dcn31/dcn31_resource.h"
-#endif
+#include "dcn315/dcn315_resource.h"
+#include "dcn316/dcn316_resource.h"
#define DC_LOGGER_INIT(logger)
@@ -118,7 +122,6 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
else
dc_version = DCE_VERSION_12_0;
break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case FAMILY_RV:
dc_version = DCN_VERSION_1_0;
if (ASICREV_IS_RAVEN2(asic_id.hw_internal_rev))
@@ -131,7 +134,7 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
case FAMILY_NV:
dc_version = DCN_VERSION_2_0;
- if (asic_id.chip_id == DEVICE_ID_NV_13FE) {
+ if (asic_id.chip_id == DEVICE_ID_NV_13FE || asic_id.chip_id == DEVICE_ID_NV_143F) {
dc_version = DCN_VERSION_2_01;
break;
}
@@ -151,7 +154,14 @@ enum dce_version resource_parse_asic_id(struct hw_asic_id asic_id)
if (ASICREV_IS_YELLOW_CARP(asic_id.hw_internal_rev))
dc_version = DCN_VERSION_3_1;
break;
-#endif
+ case AMDGPU_FAMILY_GC_10_3_6:
+ if (ASICREV_IS_GC_10_3_6(asic_id.hw_internal_rev))
+ dc_version = DCN_VERSION_3_15;
+ break;
+ case AMDGPU_FAMILY_GC_10_3_7:
+ if (ASICREV_IS_GC_10_3_7(asic_id.hw_internal_rev))
+ dc_version = DCN_VERSION_3_16;
+ break;
default:
dc_version = DCE_VERSION_UNKNOWN;
@@ -242,6 +252,12 @@ struct resource_pool *dc_create_resource_pool(struct dc *dc,
case DCN_VERSION_3_1:
res_pool = dcn31_create_resource_pool(init_data, dc);
break;
+ case DCN_VERSION_3_15:
+ res_pool = dcn315_create_resource_pool(init_data, dc);
+ break;
+ case DCN_VERSION_3_16:
+ res_pool = dcn316_create_resource_pool(init_data, dc);
+ break;
#endif
default:
break;
@@ -356,7 +372,6 @@ bool resource_construct(
}
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
pool->hpo_dp_stream_enc_count = 0;
if (create_funcs->create_hpo_dp_stream_encoder) {
for (i = 0; i < caps->num_hpo_dp_stream_encoder; i++) {
@@ -377,9 +392,7 @@ bool resource_construct(
pool->hpo_dp_link_enc_count++;
}
}
-#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
for (i = 0; i < caps->num_mpc_3dlut; i++) {
pool->mpc_lut[i] = dc_create_3dlut_func();
if (pool->mpc_lut[i] == NULL)
@@ -388,7 +401,7 @@ bool resource_construct(
if (pool->mpc_shaper[i] == NULL)
DC_ERR("DC: failed to create MPC shaper!\n");
}
-#endif
+
dc->caps.dynamic_audio = false;
if (pool->audio_count < pool->stream_enc_count) {
dc->caps.dynamic_audio = true;
@@ -1058,6 +1071,15 @@ bool resource_build_scaling_params(struct pipe_ctx *pipe_ctx)
bool res = false;
DC_LOGGER_INIT(pipe_ctx->stream->ctx->logger);
+ /* Invalid input */
+ if (!plane_state->dst_rect.width ||
+ !plane_state->dst_rect.height ||
+ !plane_state->src_rect.width ||
+ !plane_state->src_rect.height) {
+ ASSERT(0);
+ return false;
+ }
+
pipe_ctx->plane_res.scl_data.format = convert_pixel_format_to_dalsurface(
pipe_ctx->plane_state->format);
@@ -1342,7 +1364,6 @@ static struct pipe_ctx *acquire_free_pipe_for_head(
return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static int acquire_first_split_pipe(
struct resource_context *res_ctx,
const struct resource_pool *pool,
@@ -1377,7 +1398,6 @@ static int acquire_first_split_pipe(
}
return -1;
}
-#endif
bool dc_add_plane_to_context(
const struct dc *dc,
@@ -1420,13 +1440,12 @@ bool dc_add_plane_to_context(
while (head_pipe) {
free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
- #if defined(CONFIG_DRM_AMD_DC_DCN)
if (!free_pipe) {
int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
if (pipe_idx >= 0)
free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
}
- #endif
+
if (!free_pipe) {
dc_plane_state_release(plane_state);
return false;
@@ -1612,8 +1631,8 @@ bool dc_add_all_planes_for_stream(
return add_all_planes_for_stream(dc, stream, &set, 1, context);
}
-static bool is_timing_changed(struct dc_stream_state *cur_stream,
- struct dc_stream_state *new_stream)
+bool is_timing_changed(struct dc_stream_state *cur_stream,
+ struct dc_stream_state *new_stream)
{
if (cur_stream == NULL)
return true;
@@ -1640,6 +1659,9 @@ static bool are_stream_backends_same(
if (is_timing_changed(stream_a, stream_b))
return false;
+ if (stream_a->signal != stream_b->signal)
+ return false;
+
if (stream_a->dpms_off != stream_b->dpms_off)
return false;
@@ -1664,8 +1686,8 @@ bool dc_is_stream_unchanged(
if (old_stream->ignore_msa_timing_param != stream->ignore_msa_timing_param)
return false;
- // Only Have Audio left to check whether it is same or not. This is a corner case for Tiled sinks
- if (old_stream->audio_info.mode_count != stream->audio_info.mode_count)
+ /*compare audio info*/
+ if (memcmp(&old_stream->audio_info, &stream->audio_info, sizeof(stream->audio_info)) != 0)
return false;
return true;
@@ -1674,8 +1696,8 @@ bool dc_is_stream_unchanged(
/*
* dc_is_stream_scaling_unchanged() - Compare scaling rectangles of two streams.
*/
-bool dc_is_stream_scaling_unchanged(
- struct dc_stream_state *old_stream, struct dc_stream_state *stream)
+bool dc_is_stream_scaling_unchanged(struct dc_stream_state *old_stream,
+ struct dc_stream_state *stream)
{
if (old_stream == stream)
return true;
@@ -1710,7 +1732,6 @@ static void update_stream_engine_usage(
}
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static void update_hpo_dp_stream_engine_usage(
struct resource_context *res_ctx,
const struct resource_pool *pool,
@@ -1812,7 +1833,6 @@ static void remove_hpo_dp_link_enc_from_ctx(struct resource_context *res_ctx,
pipe_ctx->link_res.hpo_dp_link_enc = NULL;
}
}
-#endif
/* TODO: release audio object */
void update_audio_usage(
@@ -1858,7 +1878,6 @@ static int acquire_first_free_pipe(
return -1;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for_link(
struct resource_context *res_ctx,
const struct resource_pool *pool,
@@ -1876,7 +1895,6 @@ static struct hpo_dp_stream_encoder *find_first_free_match_hpo_dp_stream_enc_for
return NULL;
}
-#endif
static struct audio *find_first_free_audio(
struct resource_context *res_ctx,
@@ -1907,7 +1925,7 @@ static struct audio *find_first_free_audio(
return pool->audios[i];
}
}
- return 0;
+ return NULL;
}
/*
@@ -1964,7 +1982,6 @@ enum dc_status dc_remove_stream_from_ctx(
dc->res_pool,
del_pipe->stream_res.stream_enc,
false);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(del_pipe)) {
update_hpo_dp_stream_engine_usage(
&new_ctx->res_ctx, dc->res_pool,
@@ -1972,7 +1989,6 @@ enum dc_status dc_remove_stream_from_ctx(
false);
remove_hpo_dp_link_enc_from_ctx(&new_ctx->res_ctx, del_pipe, del_pipe->stream);
}
-#endif
if (del_pipe->stream_res.audio)
update_audio_usage(
@@ -2096,6 +2112,8 @@ static int acquire_resource_from_hw_enabled_state(
{
struct dc_link *link = stream->link;
unsigned int i, inst, tg_inst = 0;
+ uint32_t numPipes = 1;
+ uint32_t id_src[4] = {0};
/* Check for enabled DIG to identify enabled display */
if (!link->link_enc->funcs->is_dig_enabled(link->link_enc))
@@ -2125,37 +2143,67 @@ static int acquire_resource_from_hw_enabled_state(
struct pipe_ctx *pipe_ctx = &res_ctx->pipe_ctx[tg_inst];
pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
- pipe_ctx->plane_res.mi = pool->mis[tg_inst];
- pipe_ctx->plane_res.hubp = pool->hubps[tg_inst];
- pipe_ctx->plane_res.ipp = pool->ipps[tg_inst];
- pipe_ctx->plane_res.xfm = pool->transforms[tg_inst];
- pipe_ctx->plane_res.dpp = pool->dpps[tg_inst];
- pipe_ctx->stream_res.opp = pool->opps[tg_inst];
-
- if (pool->dpps[tg_inst]) {
- pipe_ctx->plane_res.mpcc_inst = pool->dpps[tg_inst]->inst;
+ id_src[0] = tg_inst;
- // Read DPP->MPCC->OPP Pipe from HW State
- if (pool->mpc->funcs->read_mpcc_state) {
- struct mpcc_state s = {0};
+ if (pipe_ctx->stream_res.tg->funcs->get_optc_source)
+ pipe_ctx->stream_res.tg->funcs->get_optc_source(pipe_ctx->stream_res.tg,
+ &numPipes, &id_src[0], &id_src[1]);
- pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
-
- if (s.dpp_id < MAX_MPCC)
- pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id = s.dpp_id;
+ if (id_src[0] == 0xf && id_src[1] == 0xf) {
+ id_src[0] = tg_inst;
+ numPipes = 1;
+ }
- if (s.bot_mpcc_id < MAX_MPCC)
- pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
- &pool->mpc->mpcc_array[s.bot_mpcc_id];
+ for (i = 0; i < numPipes; i++) {
+ //Check if src id invalid
+ if (id_src[i] == 0xf)
+ return -1;
+
+ pipe_ctx->stream_res.tg = pool->timing_generators[tg_inst];
+ pipe_ctx->plane_res.mi = pool->mis[id_src[i]];
+ pipe_ctx->plane_res.hubp = pool->hubps[id_src[i]];
+ pipe_ctx->plane_res.ipp = pool->ipps[id_src[i]];
+ pipe_ctx->plane_res.xfm = pool->transforms[id_src[i]];
+ pipe_ctx->plane_res.dpp = pool->dpps[id_src[i]];
+ pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
+
+ if (pool->dpps[id_src[i]]) {
+ pipe_ctx->plane_res.mpcc_inst = pool->dpps[id_src[i]]->inst;
+
+ if (pool->mpc->funcs->read_mpcc_state) {
+ struct mpcc_state s = {0};
+ pool->mpc->funcs->read_mpcc_state(pool->mpc, pipe_ctx->plane_res.mpcc_inst, &s);
+ if (s.dpp_id < MAX_MPCC)
+ pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].dpp_id =
+ s.dpp_id;
+ if (s.bot_mpcc_id < MAX_MPCC)
+ pool->mpc->mpcc_array[pipe_ctx->plane_res.mpcc_inst].mpcc_bot =
+ &pool->mpc->mpcc_array[s.bot_mpcc_id];
+ if (s.opp_id < MAX_OPP)
+ pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
+ }
+ }
+ pipe_ctx->pipe_idx = id_src[i];
- if (s.opp_id < MAX_OPP)
- pipe_ctx->stream_res.opp->mpc_tree_params.opp_id = s.opp_id;
+ if (id_src[i] >= pool->timing_generator_count) {
+ id_src[i] = pool->timing_generator_count - 1;
+ pipe_ctx->stream_res.tg = pool->timing_generators[id_src[i]];
+ pipe_ctx->stream_res.opp = pool->opps[id_src[i]];
}
+
+ pipe_ctx->stream = stream;
}
- pipe_ctx->pipe_idx = tg_inst;
- pipe_ctx->stream = stream;
- return tg_inst;
+ if (numPipes == 2) {
+ stream->apply_boot_odm_mode = dm_odm_combine_policy_2to1;
+ res_ctx->pipe_ctx[id_src[0]].next_odm_pipe = &res_ctx->pipe_ctx[id_src[1]];
+ res_ctx->pipe_ctx[id_src[0]].prev_odm_pipe = NULL;
+ res_ctx->pipe_ctx[id_src[1]].next_odm_pipe = NULL;
+ res_ctx->pipe_ctx[id_src[1]].prev_odm_pipe = &res_ctx->pipe_ctx[id_src[0]];
+ } else
+ stream->apply_boot_odm_mode = dm_odm_combine_mode_disabled;
+
+ return id_src[0];
}
return -1;
@@ -2169,7 +2217,7 @@ static void mark_seamless_boot_stream(
if (dc->config.allow_seamless_boot_optimization &&
!dcb->funcs->is_accelerated_mode(dcb)) {
- if (dc_validate_seamless_boot_timing(dc, stream->sink, &stream->timing))
+ if (dc_validate_boot_timing(dc, stream->sink, &stream->timing))
stream->apply_seamless_boot_optimization = true;
}
}
@@ -2203,10 +2251,8 @@ enum dc_status resource_map_pool_resources(
/* acquire new resources */
pipe_idx = acquire_first_free_pipe(&context->res_ctx, pool, stream);
-#ifdef CONFIG_DRM_AMD_DC_DCN
if (pipe_idx < 0)
pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
-#endif
if (pipe_idx < 0 || context->res_ctx.pipe_ctx[pipe_idx].stream_res.tg == NULL)
return DC_NO_CONTROLLER_RESOURCE;
@@ -2225,7 +2271,6 @@ enum dc_status resource_map_pool_resources(
pipe_ctx->stream_res.stream_enc,
true);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* Allocate DP HPO Stream Encoder based on signal, hw capabilities
* and link settings
*/
@@ -2250,7 +2295,6 @@ enum dc_status resource_map_pool_resources(
return DC_NO_LINK_ENC_RESOURCE;
}
}
-#endif
/* TODO: Add check if ASIC support and EDID audio */
if (!stream->converter_disable_audio &&
@@ -2271,14 +2315,10 @@ enum dc_status resource_map_pool_resources(
/* Add ABM to the resource if on EDP */
if (pipe_ctx->stream && dc_is_embedded_signal(pipe_ctx->stream->signal)) {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (pool->abm)
pipe_ctx->stream_res.abm = pool->abm;
else
pipe_ctx->stream_res.abm = pool->multiple_abms[pipe_ctx->stream_res.tg->inst];
-#else
- pipe_ctx->stream_res.abm = pool->abm;
-#endif
}
for (i = 0; i < context->stream_count; i++)
@@ -2322,6 +2362,9 @@ void dc_resource_state_construct(
bool dc_resource_is_dsc_encoding_supported(const struct dc *dc)
{
+ if (dc->res_pool == NULL)
+ return false;
+
return dc->res_pool->res_cap->num_dsc > 0;
}
@@ -2396,7 +2439,6 @@ enum dc_status dc_validate_global_state(
if (!dc->res_pool->funcs->validate_bandwidth(dc, new_ctx, fast_validate))
result = DC_FAIL_BANDWIDTH_VALIDATE;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/*
* Only update link encoder to stream assignment after bandwidth validation passed.
* TODO: Split out assignment and validation.
@@ -2404,7 +2446,6 @@ enum dc_status dc_validate_global_state(
if (result == DC_OK && dc->res_pool->funcs->link_encs_assign && fast_validate == false)
dc->res_pool->funcs->link_encs_assign(
dc, new_ctx, new_ctx->streams, new_ctx->stream_count);
-#endif
return result;
}
@@ -2602,6 +2643,8 @@ static void set_avi_info_frame(
hdmi_info.bits.YQ0_YQ1 = YYC_QUANTIZATION_LIMITED_RANGE;
///VIC
+ if (pipe_ctx->stream->timing.hdmi_vic != 0)
+ vic = 0;
format = stream->timing.timing_3d_format;
/*todo, add 3DStereo support*/
if (format != TIMING_3D_FORMAT_NONE) {
@@ -2920,12 +2963,10 @@ bool pipe_need_reprogram(
if (pipe_ctx_old->stream_res.dsc != pipe_ctx->stream_res.dsc)
return true;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (pipe_ctx_old->stream_res.hpo_dp_stream_enc != pipe_ctx->stream_res.hpo_dp_stream_enc)
return true;
if (pipe_ctx_old->link_res.hpo_dp_link_enc != pipe_ctx->link_res.hpo_dp_link_enc)
return true;
-#endif
/* DIG link encoder resource assignment for stream changed. */
if (pipe_ctx_old->stream->ctx->dc->res_pool->funcs->link_encs_assign) {
@@ -3132,10 +3173,8 @@ unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format)
case SURFACE_PIXEL_FORMAT_GRPH_ARGB2101010:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR2101010_XR_BIAS:
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case SURFACE_PIXEL_FORMAT_GRPH_RGBE:
case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
-#endif
return 32;
case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
@@ -3192,10 +3231,9 @@ void get_audio_check(struct audio_info *aud_modes,
}
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
+static struct hpo_dp_link_encoder *get_temp_hpo_dp_link_enc(
const struct resource_context *res_ctx,
- const struct resource_pool *pool,
+ const struct resource_pool *const pool,
const struct dc_link *link)
{
struct hpo_dp_link_encoder *hpo_dp_link_enc = NULL;
@@ -3211,7 +3249,24 @@ struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
return hpo_dp_link_enc;
}
-#endif
+
+bool get_temp_dp_link_res(struct dc_link *link,
+ struct link_resource *link_res,
+ struct dc_link_settings *link_settings)
+{
+ const struct dc *dc = link->dc;
+ const struct resource_context *res_ctx = &dc->current_state->res_ctx;
+
+ memset(link_res, 0, sizeof(*link_res));
+
+ if (dp_get_link_encoding_format(link_settings) == DP_128b_132b_ENCODING) {
+ link_res->hpo_dp_link_enc = get_temp_hpo_dp_link_enc(res_ctx,
+ dc->res_pool, link);
+ if (!link_res->hpo_dp_link_enc)
+ return false;
+ }
+ return true;
+}
void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
struct dc_state *context)
@@ -3272,7 +3327,6 @@ uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter tr
/* TODO - get transmitter to phy idx mapping from DMUB */
uint8_t phy_idx = transmitter - TRANSMITTER_UNIPHY_A;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (dc->ctx->dce_version == DCN_VERSION_3_1 &&
dc->ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) {
switch (transmitter) {
@@ -3296,6 +3350,39 @@ uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter tr
break;
}
}
-#endif
+
return phy_idx;
}
+
+const struct link_hwss *get_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res)
+{
+ /* Link_hwss is only accessible by getter function instead of accessing
+ * by pointers in dc with the intent to protect against breaking polymorphism.
+ */
+ if (can_use_hpo_dp_link_hwss(link, link_res))
+ /* TODO: some assumes that if decided link settings is 128b/132b
+ * channel coding format hpo_dp_link_enc should be used.
+ * Others believe that if hpo_dp_link_enc is available in link
+ * resource then hpo_dp_link_enc must be used. This bound between
+ * hpo_dp_link_enc != NULL and decided link settings is loosely coupled
+ * with a premise that both hpo_dp_link_enc pointer and decided link
+ * settings are determined based on single policy function like
+ * "decide_link_settings" from upper layer. This "convention"
+ * cannot be maintained and enforced at current level.
+ * Therefore a refactor is due so we can enforce a strong bound
+ * between those two parameters at this level.
+ *
+ * To put it simple, we want to make enforcement at low level so that
+ * we will not return link hwss if caller plans to do 8b/10b
+ * with an hpo encoder. Or we can return a very dummy one that doesn't
+ * do work for all functions
+ */
+ return get_hpo_dp_link_hwss();
+ else if (can_use_dpia_link_hwss(link, link_res))
+ return get_dpia_link_hwss();
+ else if (can_use_dio_link_hwss(link, link_res))
+ return get_dio_link_hwss();
+ else
+ return get_virtual_link_hwss();
+}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index 57cf4cb82370..de8b214132a2 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -273,6 +273,8 @@ static void program_cursor_attributes(
if (!pipe_to_program) {
pipe_to_program = pipe_ctx;
dc->hwss.cursor_lock(dc, pipe_to_program, true);
+ if (pipe_to_program->next_odm_pipe)
+ dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, true);
}
dc->hwss.set_cursor_attribute(pipe_ctx);
@@ -280,8 +282,11 @@ static void program_cursor_attributes(
dc->hwss.set_cursor_sdr_white_level(pipe_ctx);
}
- if (pipe_to_program)
+ if (pipe_to_program) {
dc->hwss.cursor_lock(dc, pipe_to_program, false);
+ if (pipe_to_program->next_odm_pipe)
+ dc->hwss.cursor_lock(dc, pipe_to_program->next_odm_pipe, false);
+ }
}
#ifndef TRIM_FSFT
@@ -309,9 +314,7 @@ bool dc_stream_set_cursor_attributes(
const struct dc_cursor_attributes *attributes)
{
struct dc *dc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool reset_idle_optimizations = false;
-#endif
if (NULL == stream) {
dm_error("DC: dc_stream is NULL!\n");
@@ -330,7 +333,6 @@ bool dc_stream_set_cursor_attributes(
dc = stream->ctx->dc;
stream->cursor_attributes = *attributes;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
dc_z10_restore(dc);
/* disable idle optimizations while updating cursor */
if (dc->idle_optimizations_allowed) {
@@ -338,15 +340,12 @@ bool dc_stream_set_cursor_attributes(
reset_idle_optimizations = true;
}
-#endif
program_cursor_attributes(dc, stream, attributes);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* re-enable idle optimizations if necessary */
if (reset_idle_optimizations)
dc_allow_idle_optimizations(dc, true);
-#endif
return true;
}
@@ -391,9 +390,7 @@ bool dc_stream_set_cursor_position(
const struct dc_cursor_position *position)
{
struct dc *dc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool reset_idle_optimizations = false;
-#endif
if (NULL == stream) {
dm_error("DC: dc_stream is NULL!\n");
@@ -406,7 +403,6 @@ bool dc_stream_set_cursor_position(
}
dc = stream->ctx->dc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
dc_z10_restore(dc);
/* disable idle optimizations if enabling cursor */
@@ -415,16 +411,13 @@ bool dc_stream_set_cursor_position(
reset_idle_optimizations = true;
}
-#endif
stream->cursor_position = *position;
program_cursor_position(dc, stream, position);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* re-enable idle optimizations if necessary */
if (reset_idle_optimizations)
dc_allow_idle_optimizations(dc, true);
-#endif
return true;
}
@@ -713,6 +706,20 @@ enum dc_status dc_stream_add_dsc_to_resource(struct dc *dc,
}
}
+struct pipe_ctx *dc_stream_get_pipe_ctx(struct dc_stream_state *stream)
+{
+ int i = 0;
+
+ for (i = 0; i < MAX_PIPES; i++) {
+ struct pipe_ctx *pipe = &stream->ctx->dc->current_state->res_ctx.pipe_ctx[i];
+
+ if (pipe->stream == stream)
+ return pipe;
+ }
+
+ return NULL;
+}
+
void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
{
DC_LOG_DC(
@@ -737,5 +744,21 @@ void dc_stream_log(const struct dc *dc, const struct dc_stream_state *stream)
DC_LOG_DC(
"\tlink: %d\n",
stream->link->link_index);
+
+ DC_LOG_DC(
+ "\tdsc: %d, mst_pbn: %d\n",
+ stream->timing.flags.DSC,
+ stream->timing.dsc_cfg.mst_pbn);
+
+ if (stream->sink) {
+ if (stream->sink->sink_signal != SIGNAL_TYPE_VIRTUAL &&
+ stream->sink->sink_signal != SIGNAL_TYPE_NONE) {
+
+ DC_LOG_DC(
+ "\tdispname: %s signal: %x\n",
+ stream->sink->edid_caps.display_name,
+ stream->signal);
+ }
+ }
}
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
index e6b9c6a71841..5bc6ff2fa73e 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_surface.c
@@ -61,6 +61,8 @@ static void dc_plane_construct(struct dc_context *ctx, struct dc_plane_state *pl
plane_state->blend_tf->type = TF_TYPE_BYPASS;
}
+ plane_state->pre_multiplied_alpha = true;
+
}
static void dc_plane_destruct(struct dc_plane_state *plane_state)
diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h
index b51864890621..817028d3c4a0 100644
--- a/drivers/gpu/drm/amd/display/dc/dc.h
+++ b/drivers/gpu/drm/amd/display/dc/dc.h
@@ -47,7 +47,7 @@ struct aux_payload;
struct set_config_cmd_payload;
struct dmub_notification;
-#define DC_VER "3.2.167"
+#define DC_VER "3.2.187"
#define MAX_SURFACES 3
#define MAX_PLANES 6
@@ -188,6 +188,7 @@ struct dc_caps {
bool psp_setup_panel_mode;
bool extended_aux_timeout_support;
bool dmcub_support;
+ bool zstate_support;
uint32_t num_of_internal_disp;
enum dp_protocol_version max_dp_protocol_version;
unsigned int mall_size_per_mem_channel;
@@ -195,10 +196,8 @@ struct dc_caps {
unsigned int cursor_cache_size;
struct dc_plane_cap planes[MAX_PLANES];
struct dc_color_caps color;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool dp_hpo;
bool hdmi_frl_pcon_support;
-#endif
bool edp_dsc_support;
bool vbios_lttpr_aware;
bool vbios_lttpr_enable;
@@ -223,7 +222,6 @@ struct dc_dcc_setting {
unsigned int max_compressed_blk_size;
unsigned int max_uncompressed_blk_size;
bool independent_64b_blks;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
//These bitfields to be used starting with DCN
struct {
uint32_t dcc_256_64_64 : 1;//available in ASICs before DCN (the worst compression case)
@@ -231,7 +229,6 @@ struct dc_dcc_setting {
uint32_t dcc_256_128_128 : 1; //available starting with DCN
uint32_t dcc_256_256_unconstrained : 1; //available in ASICs before DCN (the best compression case)
} dcc_controls;
-#endif
};
struct dc_surface_dcc_cap {
@@ -307,7 +304,6 @@ struct dc_cap_funcs {
struct link_training_settings;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union allow_lttpr_non_transparent_mode {
struct {
bool DP1_4A : 1;
@@ -315,7 +311,7 @@ union allow_lttpr_non_transparent_mode {
} bits;
unsigned char raw;
};
-#endif
+
/* Structure to hold configuration flags set by dm at dc creation. */
struct dc_config {
bool gpu_vm_support;
@@ -323,29 +319,24 @@ struct dc_config {
bool fbc_support;
bool disable_fractional_pwm;
bool allow_seamless_boot_optimization;
- bool power_down_display_on_boot;
+ bool seamless_boot_edp_requested;
bool edp_not_connected;
bool edp_no_power_sequencing;
bool force_enum_edp;
bool forced_clocks;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union allow_lttpr_non_transparent_mode allow_lttpr_non_transparent_mode;
-#else
- bool allow_lttpr_non_transparent_mode;
-#endif
bool multi_mon_pp_mclk_switch;
bool disable_dmcu;
bool enable_4to1MPC;
bool enable_windowed_mpo_odm;
- bool allow_edp_hotplug_detection;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+ uint32_t allow_edp_hotplug_detection;
bool clamp_min_dcfclk;
-#endif
uint64_t vblank_alignment_dto_params;
uint8_t vblank_alignment_max_frame_time_diff;
bool is_asymmetric_memory;
bool is_single_rank_dimm;
bool use_pipe_ctx_sync_logic;
+ bool ignore_dpref_ss;
};
enum visual_confirm {
@@ -361,6 +352,13 @@ enum dc_psr_power_opts {
psr_power_opt_invalid = 0x0,
psr_power_opt_smu_opt_static_screen = 0x1,
psr_power_opt_z10_static_screen = 0x10,
+ psr_power_opt_ds_disable_allow = 0x100,
+};
+
+enum dml_hostvm_override_opts {
+ DML_HOSTVM_NO_OVERRIDE = 0x0,
+ DML_HOSTVM_OVERRIDE_FALSE = 0x1,
+ DML_HOSTVM_OVERRIDE_TRUE = 0x2,
};
enum dcc_option {
@@ -393,13 +391,12 @@ enum dcn_pwr_state {
DCN_PWR_STATE_LOW_POWER = 3,
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dcn_zstate_support_state {
DCN_ZSTATE_SUPPORT_UNKNOWN,
DCN_ZSTATE_SUPPORT_ALLOW,
+ DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY,
DCN_ZSTATE_SUPPORT_DISALLOW,
};
-#endif
/*
* For any clocks that may differ per pipe
* only the max is stored in this structure
@@ -417,10 +414,9 @@ struct dc_clocks {
int phyclk_khz;
int dramclk_khz;
bool p_state_change_support;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dcn_zstate_support_state zstate_support;
bool dtbclk_en;
-#endif
+ int ref_dtbclk_khz;
enum dcn_pwr_state pwr_state;
/*
* Elements below are not compared for the purposes of
@@ -519,12 +515,29 @@ union root_clock_optimization_options {
union dpia_debug_options {
struct {
- uint32_t disable_dpia:1;
- uint32_t force_non_lttpr:1;
- uint32_t extend_aux_rd_interval:1;
- uint32_t disable_mst_dsc_work_around:1;
- uint32_t hpd_delay_in_ms:12;
- uint32_t reserved:16;
+ uint32_t disable_dpia:1; /* bit 0 */
+ uint32_t force_non_lttpr:1; /* bit 1 */
+ uint32_t extend_aux_rd_interval:1; /* bit 2 */
+ uint32_t disable_mst_dsc_work_around:1; /* bit 3 */
+ uint32_t hpd_delay_in_ms:12; /* bits 4-15 */
+ uint32_t disable_force_tbt3_work_around:1; /* bit 16 */
+ uint32_t reserved:15;
+ } bits;
+ uint32_t raw;
+};
+
+/* AUX wake work around options
+ * 0: enable/disable work around
+ * 1: use default timeout LINK_AUX_WAKE_TIMEOUT_MS
+ * 15-2: reserved
+ * 31-16: timeout in ms
+ */
+union aux_wake_wa_options {
+ struct {
+ uint32_t enable_wa : 1;
+ uint32_t use_default_timeout : 1;
+ uint32_t rsvd: 14;
+ uint32_t timeout_ms : 16;
} bits;
uint32_t raw;
};
@@ -633,9 +646,7 @@ struct dc_debug_options {
bool disable_pplib_clock_request;
bool disable_clock_gate;
bool disable_mem_low_power;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool pstate_enabled;
-#endif
bool disable_dmcu;
bool disable_psr;
bool force_abm_enable;
@@ -652,20 +663,17 @@ struct dc_debug_options {
uint32_t edid_read_retry_times;
bool remove_disconnect_edp;
unsigned int force_odm_combine; //bit vector based on otg inst
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+ unsigned int seamless_boot_odm_combine;
unsigned int force_odm_combine_4to1; //bit vector based on otg inst
bool disable_z9_mpc;
-#endif
unsigned int force_fclk_khz;
bool enable_tri_buf;
bool dmub_offload_enabled;
bool dmcub_emulation;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool disable_idle_power_optimizations;
unsigned int mall_size_override;
unsigned int mall_additional_timer_percent;
bool mall_error_as_fatal;
-#endif
bool dmub_command_table; /* for testing only */
struct dc_bw_validation_profile bw_val_profile;
bool disable_fec;
@@ -674,9 +682,7 @@ struct dc_debug_options {
* watermarks are not affected.
*/
unsigned int force_min_dcfclk_mhz;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
int dwb_fi_phase;
-#endif
bool disable_timing_sync;
bool cm_in_bypass;
int force_clock_mode;/*every mode change.*/
@@ -688,13 +694,12 @@ struct dc_debug_options {
bool disable_dsc_edp;
unsigned int force_dsc_edp_policy;
bool enable_dram_clock_change_one_display_vactive;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* TODO - remove once tested */
bool legacy_dp2_lt;
bool set_mst_en_for_sst;
bool disable_uhbr;
bool force_dp2_lt_fallback_method;
-#endif
+ bool ignore_cable_id;
union mem_low_power_enable_options enable_mem_low_power;
union root_clock_optimization_options root_clock_optimization;
bool hpo_optimization;
@@ -708,12 +713,17 @@ struct dc_debug_options {
bool enable_driver_sequence_debug;
enum det_size crb_alloc_policy;
int crb_alloc_policy_min_disp_count;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool disable_z10;
+ bool enable_z9_disable_interface;
bool enable_sw_cntl_psr;
union dpia_debug_options dpia_debug;
-#endif
bool apply_vendor_specific_lttpr_wa;
+ bool extended_blank_optimization;
+ union aux_wake_wa_options aux_wake_wa;
+ /* uses value at boot and disables switch */
+ bool disable_dtb_ref_clk_switch;
+ uint8_t psr_power_use_phy_fsm;
+ enum dml_hostvm_override_opts dml_hostvm_override;
};
struct gpu_info_soc_bounding_box_v1_0;
@@ -742,11 +752,9 @@ struct dc {
/* Inputs into BW and WM calculations. */
struct bw_calcs_dceip *bw_dceip;
struct bw_calcs_vbios *bw_vbios;
-#ifdef CONFIG_DRM_AMD_DC_DCN
struct dcn_soc_bounding_box *dcn_soc;
struct dcn_ip_params *dcn_ip;
struct display_mode_lib dml;
-#endif
/* HW functions */
struct hw_sequencer_funcs hwss;
@@ -755,12 +763,8 @@ struct dc {
/* Require to optimize clocks and bandwidth for added/removed planes */
bool optimized_required;
bool wm_optimized_required;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool idle_optimizations_allowed;
-#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool enable_c20_dtm_b0;
-#endif
/* Require to maintain clocks and bandwidth for UEFI enabled HW */
@@ -810,9 +814,7 @@ struct dc_init_data {
uint64_t log_mask;
struct dpcd_vendor_signature vendor_signature;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool force_smu_not_present;
-#endif
};
struct dc_callback_init {
@@ -1005,15 +1007,14 @@ struct dc_plane_state {
struct dc_transfer_func *in_shaper_func;
struct dc_transfer_func *blend_tf;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_transfer_func *gamcor_tf;
-#endif
enum surface_pixel_format format;
enum dc_rotation_angle rotation;
enum plane_stereo_format stereo_format;
bool is_tiling_rotated;
bool per_pixel_alpha;
+ bool pre_multiplied_alpha;
bool global_alpha;
int global_alpha_value;
bool visible;
@@ -1048,6 +1049,7 @@ struct dc_plane_info {
bool horizontal_mirror;
bool visible;
bool per_pixel_alpha;
+ bool pre_multiplied_alpha;
bool global_alpha;
int global_alpha_value;
bool input_csc_enabled;
@@ -1104,18 +1106,6 @@ struct dc_transfer_func *dc_create_transfer_func(void);
struct dc_3dlut *dc_create_3dlut_func(void);
void dc_3dlut_func_release(struct dc_3dlut *lut);
void dc_3dlut_func_retain(struct dc_3dlut *lut);
-/*
- * This structure holds a surface address. There could be multiple addresses
- * in cases such as Stereo 3D, Planar YUV, etc. Other per-flip attributes such
- * as frame durations and DCC format can also be set.
- */
-struct dc_flip_addrs {
- struct dc_plane_address address;
- unsigned int flip_timestamp_in_us;
- bool flip_immediate;
- /* TODO: add flip duration for FreeSync */
- bool triplebuffer_flips;
-};
void dc_post_update_surfaces_to_stream(
struct dc *dc);
@@ -1131,7 +1121,7 @@ struct dc_validation_set {
uint8_t plane_count;
};
-bool dc_validate_seamless_boot_timing(const struct dc *dc,
+bool dc_validate_boot_timing(const struct dc *dc,
const struct dc_sink *sink,
struct dc_crtc_timing *crtc_timing);
@@ -1156,13 +1146,11 @@ void dc_resource_state_construct(
const struct dc *dc,
struct dc_state *dst_ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool dc_acquire_release_mpc_3dlut(
struct dc *dc, bool acquire,
struct dc_stream_state *stream,
struct dc_3dlut **lut,
struct dc_transfer_func **shaper);
-#endif
void dc_resource_state_copy_construct(
const struct dc_state *src_ctx,
@@ -1208,10 +1196,12 @@ struct dpcd_caps {
/* dongle type (DP converter, CV smart dongle) */
enum display_dongle_type dongle_type;
+ bool is_dongle_type_one;
/* branch device or sink device */
bool is_branch_dev;
/* Dongle's downstream count. */
union sink_count sink_count;
+ bool is_mst_capable;
/* If dongle_type == DISPLAY_DONGLE_DP_HDMI_CONVERTER,
indicates 'Frame Sequential-to-lllFrame Pack' conversion capability.*/
struct dc_dongle_caps dongle_caps;
@@ -1234,15 +1224,16 @@ struct dpcd_caps {
union dpcd_fec_capability fec_cap;
struct dpcd_dsc_capabilities dsc_caps;
struct dc_lttpr_caps lttpr_caps;
- struct psr_caps psr_caps;
struct dpcd_usb4_dp_tunneling_info usb4_dp_tun_info;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union dp_128b_132b_supported_link_rates dp_128b_132b_supported_link_rates;
union dp_main_line_channel_coding_cap channel_coding_cap;
union dp_sink_video_fallback_formats fallback_formats;
union dp_fec_capability1 fec_cap1;
-#endif
+ union dp_cable_id cable_id;
+ uint8_t edp_rev;
+ union edp_alpm_caps alpm_caps;
+ struct edp_psr_info psr_info;
};
union dpcd_sink_ext_caps {
@@ -1290,10 +1281,8 @@ struct hdcp_caps {
#include "dc_link.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint32_t dc_get_opp_for_plane(struct dc *dc, struct dc_plane_state *plane);
-#endif
/*******************************************************************************
* Sink Interfaces - A sink corresponds to a display output device
******************************************************************************/
@@ -1368,6 +1357,8 @@ struct dc_sink_init_data {
bool converter_disable_audio;
};
+bool dc_extended_blank_supported(struct dc *dc);
+
struct dc_sink *dc_sink_create(const struct dc_sink_init_data *init_params);
/* Newer interfaces */
@@ -1415,7 +1406,6 @@ bool dc_is_dmcu_initialized(struct dc *dc);
enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping);
void dc_get_clock(struct dc *dc, enum dc_clock_type clock_type, struct dc_clock_config *clock_cfg);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool dc_is_plane_eligible_for_idle_optimizations(struct dc *dc, struct dc_plane_state *plane,
struct dc_cursor_attributes *cursor_attr);
@@ -1440,16 +1430,15 @@ void dc_enable_dcmode_clk_limit(struct dc *dc, bool enable);
/* cleanup on driver unload */
void dc_hardware_release(struct dc *dc);
-#endif
-
bool dc_set_psr_allow_active(struct dc *dc, bool enable);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
void dc_z10_restore(const struct dc *dc);
void dc_z10_save_init(struct dc *dc);
-#endif
+bool dc_is_dmub_outbox_supported(struct dc *dc);
bool dc_enable_dmub_notifications(struct dc *dc);
+void dc_enable_dmub_outbox(struct dc *dc);
+
bool dc_process_dmub_aux_transfer_async(struct dc *dc,
uint32_t link_index,
struct aux_payload *payload);
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
index 353dac420f34..2c54b6e0498b 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dp_types.h
@@ -53,7 +53,6 @@ enum dc_link_rate {
LINK_RATE_RBR2 = 0x0C, // Rate_5 (RBR2)- 3.24 Gbps/Lane
LINK_RATE_RATE_6 = 0x10, // Rate_6 - 4.32 Gbps/Lane
LINK_RATE_HIGH2 = 0x14, // Rate_7 (HBR2)- 5.40 Gbps/Lane
-#if defined(CONFIG_DRM_AMD_DC_DCN)
LINK_RATE_HIGH3 = 0x1E, // Rate_8 (HBR3)- 8.10 Gbps/Lane
/* Starting from DP2.0 link rate enum directly represents actual
* link rate value in unit of 10 mbps
@@ -61,9 +60,6 @@ enum dc_link_rate {
LINK_RATE_UHBR10 = 1000, // UHBR10 - 10.0 Gbps/Lane
LINK_RATE_UHBR13_5 = 1350, // UHBR13.5 - 13.5 Gbps/Lane
LINK_RATE_UHBR20 = 2000, // UHBR10 - 20.0 Gbps/Lane
-#else
- LINK_RATE_HIGH3 = 0x1E // Rate_8 (HBR3)- 8.10 Gbps/Lane
-#endif
};
enum dc_link_spread {
@@ -100,7 +96,6 @@ enum dc_post_cursor2 {
POST_CURSOR2_MAX_LEVEL = POST_CURSOR2_LEVEL3,
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dc_dp_ffe_preset_level {
DP_FFE_PRESET_LEVEL0 = 0,
DP_FFE_PRESET_LEVEL1,
@@ -120,7 +115,6 @@ enum dc_dp_ffe_preset_level {
DP_FFE_PRESET_LEVEL15,
DP_FFE_PRESET_MAX_LEVEL = DP_FFE_PRESET_LEVEL15,
};
-#endif
enum dc_dp_training_pattern {
DP_TRAINING_PATTERN_SEQUENCE_1 = 0,
@@ -128,19 +122,25 @@ enum dc_dp_training_pattern {
DP_TRAINING_PATTERN_SEQUENCE_3,
DP_TRAINING_PATTERN_SEQUENCE_4,
DP_TRAINING_PATTERN_VIDEOIDLE,
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DP_128b_132b_TPS1,
DP_128b_132b_TPS2,
DP_128b_132b_TPS2_CDS,
-#endif
};
enum dp_link_encoding {
DP_UNKNOWN_ENCODING = 0,
DP_8b_10b_ENCODING = 1,
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DP_128b_132b_ENCODING = 2,
-#endif
+};
+
+enum dp_test_link_rate {
+ DP_TEST_LINK_RATE_RBR = 0x06,
+ DP_TEST_LINK_RATE_HBR = 0x0A,
+ DP_TEST_LINK_RATE_HBR2 = 0x14,
+ DP_TEST_LINK_RATE_HBR3 = 0x1E,
+ DP_TEST_LINK_RATE_UHBR10 = 0x01,
+ DP_TEST_LINK_RATE_UHBR20 = 0x02,
+ DP_TEST_LINK_RATE_UHBR13_5 = 0x03,
};
struct dc_link_settings {
@@ -152,7 +152,6 @@ struct dc_link_settings {
bool dpcd_source_device_specific_field_support;
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union dc_dp_ffe_preset {
struct {
uint8_t level : 4;
@@ -163,24 +162,19 @@ union dc_dp_ffe_preset {
} settings;
uint8_t raw;
};
-#endif
struct dc_lane_settings {
enum dc_voltage_swing VOLTAGE_SWING;
enum dc_pre_emphasis PRE_EMPHASIS;
enum dc_post_cursor2 POST_CURSOR2;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union dc_dp_ffe_preset FFE_PRESET;
-#endif
};
struct dc_link_training_overrides {
enum dc_voltage_swing *voltage_swing;
enum dc_pre_emphasis *pre_emphasis;
enum dc_post_cursor2 *post_cursor2;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union dc_dp_ffe_preset *ffe_preset;
-#endif
uint16_t *cr_pattern_time;
uint16_t *eq_pattern_time;
@@ -194,7 +188,6 @@ struct dc_link_training_overrides {
bool *fec_enable;
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union payload_table_update_status {
struct {
uint8_t VC_PAYLOAD_TABLE_UPDATED:1;
@@ -202,7 +195,6 @@ union payload_table_update_status {
} bits;
uint8_t raw;
};
-#endif
union dpcd_rev {
struct {
@@ -291,14 +283,10 @@ union lane_align_status_updated {
struct {
uint8_t INTERLANE_ALIGN_DONE:1;
uint8_t POST_LT_ADJ_REQ_IN_PROGRESS:1;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint8_t EQ_INTERLANE_ALIGN_DONE_128b_132b:1;
uint8_t CDS_INTERLANE_ALIGN_DONE_128b_132b:1;
uint8_t LT_FAILED_128b_132b:1;
uint8_t RESERVED:1;
-#else
- uint8_t RESERVED:4;
-#endif
uint8_t DOWNSTREAM_PORT_STATUS_CHANGED:1;
uint8_t LINK_STATUS_UPDATED:1;
} bits;
@@ -311,12 +299,10 @@ union lane_adjust {
uint8_t PRE_EMPHASIS_LANE:2;
uint8_t RESERVED:4;
} bits;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct {
uint8_t PRESET_VALUE :4;
uint8_t RESERVED :4;
} tx_ffe;
-#endif
uint8_t raw;
};
@@ -346,12 +332,10 @@ union dpcd_training_lane {
uint8_t MAX_PRE_EMPHASIS_REACHED:1;
uint8_t RESERVED:2;
} bits;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct {
uint8_t PRESET_VALUE :4;
uint8_t RESERVED :4;
} tx_ffe;
-#endif
uint8_t raw;
};
@@ -646,7 +630,7 @@ union test_request {
uint8_t LINK_TEST_PATTRN :1;
uint8_t EDID_READ :1;
uint8_t PHY_TEST_PATTERN :1;
- uint8_t RESERVED :1;
+ uint8_t PHY_TEST_CHANNEL_CODING_TYPE :2;
uint8_t AUDIO_TEST_PATTERN :1;
uint8_t TEST_AUDIO_DISABLED_VIDEO :1;
} bits;
@@ -665,18 +649,9 @@ union test_response {
union phy_test_pattern {
struct {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* This field is 7 bits for DP2.0 */
uint8_t PATTERN :7;
uint8_t RESERVED :1;
-#else
- /* DpcdPhyTestPatterns. This field is 2 bits for DP1.1
- * and 3 bits for DP1.2.
- */
- uint8_t PATTERN :3;
- /* BY speci, bit7:2 is 0 for DP1.1. */
- uint8_t RESERVED :5;
-#endif
} bits;
uint8_t raw;
};
@@ -754,14 +729,10 @@ union dpcd_fec_capability {
uint8_t UNCORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
uint8_t CORRECTED_BLOCK_ERROR_COUNT_CAPABLE:1;
uint8_t BIT_ERROR_COUNT_CAPABLE:1;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint8_t PARITY_BLOCK_ERROR_COUNT_CAPABLE:1;
uint8_t ARITY_BIT_ERROR_COUNT_CAPABLE:1;
uint8_t FEC_RUNNING_INDICATOR_SUPPORTED:1;
uint8_t FEC_ERROR_REPORTING_POLICY_SUPPORTED:1;
-#else
- uint8_t RESERVED:4;
-#endif
} bits;
uint8_t raw;
};
@@ -925,7 +896,6 @@ struct dpcd_usb4_dp_tunneling_info {
uint8_t usb4_topology_id[DPCD_USB4_TOPOLOGY_ID_LEN];
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#ifndef DP_MAIN_LINK_CHANNEL_CODING_CAP
#define DP_MAIN_LINK_CHANNEL_CODING_CAP 0x006
#endif
@@ -941,6 +911,9 @@ struct dpcd_usb4_dp_tunneling_info {
#ifndef DP_LINK_SQUARE_PATTERN
#define DP_LINK_SQUARE_PATTERN 0x10F
#endif
+#ifndef DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX
+#define DP_CABLE_ATTRIBUTES_UPDATED_BY_DPTX 0x110
+#endif
#ifndef DP_DSC_CONFIGURATION
#define DP_DSC_CONFIGURATION 0x161
#endif
@@ -953,6 +926,9 @@ struct dpcd_usb4_dp_tunneling_info {
#ifndef DP_128b_132b_TRAINING_AUX_RD_INTERVAL
#define DP_128b_132b_TRAINING_AUX_RD_INTERVAL 0x2216
#endif
+#ifndef DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX
+#define DP_CABLE_ATTRIBUTES_UPDATED_BY_DPRX 0x2217
+#endif
#ifndef DP_TEST_264BIT_CUSTOM_PATTERN_7_0
#define DP_TEST_264BIT_CUSTOM_PATTERN_7_0 0X2230
#endif
@@ -994,8 +970,8 @@ struct dpcd_usb4_dp_tunneling_info {
#endif
#ifndef DP_INTRA_HOP_AUX_REPLY_INDICATION
#define DP_INTRA_HOP_AUX_REPLY_INDICATION (1 << 3)
-#endif
/* TODO - Use DRM header to replace above once available */
+#endif // DP_INTRA_HOP_AUX_REPLY_INDICATION
union dp_main_line_channel_coding_cap {
struct {
@@ -1027,8 +1003,8 @@ union dp_128b_132b_supported_link_rates {
union dp_128b_132b_supported_lttpr_link_rates {
struct {
uint8_t UHBR10 :1;
- uint8_t UHBR13_5:1;
uint8_t UHBR20 :1;
+ uint8_t UHBR13_5:1;
uint8_t RESERVED:5;
} bits;
uint8_t raw;
@@ -1052,6 +1028,16 @@ union dp_fec_capability1 {
uint8_t raw;
};
+union dp_cable_id {
+ struct {
+ uint8_t UHBR10_20_CAPABILITY :2;
+ uint8_t UHBR13_5_CAPABILITY :1;
+ uint8_t CABLE_TYPE :3;
+ uint8_t RESERVED :2;
+ } bits;
+ uint8_t raw;
+};
+
struct dp_color_depth_caps {
uint8_t support_6bpc :1;
uint8_t support_8bpc :1;
@@ -1091,6 +1077,34 @@ union dp_128b_132b_training_aux_rd_interval {
} bits;
uint8_t raw;
};
-#endif
+
+union edp_alpm_caps {
+ struct {
+ uint8_t AUX_WAKE_ALPM_CAP :1;
+ uint8_t PM_STATE_2A_SUPPORT :1;
+ uint8_t AUX_LESS_ALPM_CAP :1;
+ uint8_t RESERVED :5;
+ } bits;
+ uint8_t raw;
+};
+
+union edp_psr_dpcd_caps {
+ struct {
+ uint8_t LINK_TRAINING_ON_EXIT_NOT_REQUIRED :1;
+ uint8_t PSR_SETUP_TIME :3;
+ uint8_t Y_COORDINATE_REQUIRED :1;
+ uint8_t SU_GRANULARITY_REQUIRED :1;
+ uint8_t FRAME_SYNC_IS_NOT_NEEDED_FOR_SU :1;
+ uint8_t RESERVED :1;
+ } bits;
+ uint8_t raw;
+};
+
+struct edp_psr_info {
+ uint8_t psr_version;
+ union edp_psr_dpcd_caps psr_dpcd_caps;
+ uint8_t psr2_su_y_granularity_cap;
+ uint8_t force_psrsu_cap;
+};
#endif /* DC_DP_TYPES_H */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_helper.c b/drivers/gpu/drm/amd/display/dc/dc_helper.c
index ab6bc5d79012..f43cce16bb6c 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_helper.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_helper.c
@@ -588,6 +588,66 @@ uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx,
return reg_val;
}
+
+uint32_t generic_indirect_reg_update_ex_sync(const struct dc_context *ctx,
+ uint32_t index, uint32_t reg_val, int n,
+ uint8_t shift1, uint32_t mask1, uint32_t field_value1,
+ ...)
+{
+ uint32_t shift, mask, field_value;
+ int i = 1;
+
+ va_list ap;
+
+ va_start(ap, field_value1);
+
+ reg_val = set_reg_field_value_ex(reg_val, field_value1, mask1, shift1);
+
+ while (i < n) {
+ shift = va_arg(ap, uint32_t);
+ mask = va_arg(ap, uint32_t);
+ field_value = va_arg(ap, uint32_t);
+
+ reg_val = set_reg_field_value_ex(reg_val, field_value, mask, shift);
+ i++;
+ }
+
+ dm_write_index_reg(ctx, CGS_IND_REG__PCIE, index, reg_val);
+ va_end(ap);
+
+ return reg_val;
+}
+
+uint32_t generic_indirect_reg_get_sync(const struct dc_context *ctx,
+ uint32_t index, int n,
+ uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
+ ...)
+{
+ uint32_t shift, mask, *field_value;
+ uint32_t value = 0;
+ int i = 1;
+
+ va_list ap;
+
+ va_start(ap, field_value1);
+
+ value = dm_read_index_reg(ctx, CGS_IND_REG__PCIE, index);
+ *field_value1 = get_reg_field_value_ex(value, mask1, shift1);
+
+ while (i < n) {
+ shift = va_arg(ap, uint32_t);
+ mask = va_arg(ap, uint32_t);
+ field_value = va_arg(ap, uint32_t *);
+
+ *field_value = get_reg_field_value_ex(value, mask, shift);
+ i++;
+ }
+
+ va_end(ap);
+
+ return value;
+}
+
void reg_sequence_start_gather(const struct dc_context *ctx)
{
/* if reg sequence is supported and enabled, set flag to
diff --git a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
index eac34f591a3f..aa7e3a07191d 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_hw_types.h
@@ -201,8 +201,9 @@ enum surface_pixel_format {
SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb,
SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr,
SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb,
+ SURFACE_PIXEL_FORMAT_SUBSAMPLE_END,
+ SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010 =
SURFACE_PIXEL_FORMAT_SUBSAMPLE_END,
- SURFACE_PIXEL_FORMAT_VIDEO_ACrYCb2101010,
SURFACE_PIXEL_FORMAT_VIDEO_CrYCbA1010102,
SURFACE_PIXEL_FORMAT_VIDEO_AYCrCb8888,
SURFACE_PIXEL_FORMAT_INVALID
@@ -235,6 +236,22 @@ enum pixel_format {
PIXEL_FORMAT_UNKNOWN
};
+/*
+ * This structure holds a surface address. There could be multiple addresses
+ * in cases such as Stereo 3D, Planar YUV, etc. Other per-flip attributes such
+ * as frame durations and DCC format can also be set.
+ */
+#define DC_MAX_DIRTY_RECTS 3
+struct dc_flip_addrs {
+ struct dc_plane_address address;
+ unsigned int flip_timestamp_in_us;
+ bool flip_immediate;
+ /* TODO: add flip duration for FreeSync */
+ bool triplebuffer_flips;
+ unsigned int dirty_rect_count;
+ struct rect dirty_rects[DC_MAX_DIRTY_RECTS];
+};
+
enum tile_split_values {
DC_DISPLAY_MICRO_TILING = 0x0,
DC_THIN_MICRO_TILING = 0x1,
@@ -745,6 +762,7 @@ struct dc_dsc_config {
bool is_frl; /* indicate if DSC is applied based on HDMI FRL sink's capability */
#endif
bool is_dp; /* indicate if DSC is applied based on DP's capability */
+ uint32_t mst_pbn; /* pbn of display on dsc mst hub */
};
struct dc_crtc_timing {
uint32_t h_total;
diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h
index c0e37ad0e26c..a3c37ee3f849 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_link.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_link.h
@@ -43,14 +43,16 @@ struct dc_link_status {
struct dpcd_caps *dpcd_caps;
};
+struct dprx_states {
+ bool cable_id_written;
+};
+
/* DP MST stream allocation (payload bandwidth number) */
struct link_mst_stream_allocation {
/* DIG front */
const struct stream_encoder *stream_enc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* HPO DP Stream Encoder */
const struct hpo_dp_stream_encoder *hpo_dp_stream_enc;
-#endif
/* associate DRM payload table with DC stream encoder */
uint8_t vcp_id;
/* number of slots required for the DP stream in transport packet */
@@ -65,13 +67,32 @@ struct link_mst_stream_allocation_table {
struct link_mst_stream_allocation stream_allocations[MAX_CONTROLLER_NUM];
};
-struct time_stamp {
- uint64_t edp_poweroff;
- uint64_t edp_poweron;
+struct edp_trace_power_timestamps {
+ uint64_t poweroff;
+ uint64_t poweron;
};
-struct link_trace {
- struct time_stamp time_stamp;
+struct dp_trace_lt_counts {
+ unsigned int total;
+ unsigned int fail;
+};
+
+struct dp_trace_lt {
+ struct dp_trace_lt_counts counts;
+ struct dp_trace_timestamps {
+ unsigned long long start;
+ unsigned long long end;
+ } timestamps;
+ enum link_training_result result;
+ bool is_logged;
+};
+
+struct dp_trace {
+ struct dp_trace_lt detect_lt_trace;
+ struct dp_trace_lt commit_lt_trace;
+ unsigned int link_loss_count;
+ bool is_initialized;
+ struct edp_trace_power_timestamps edp_trace_power_timestamps;
};
/* PSR feature flags */
@@ -119,6 +140,8 @@ struct dc_link {
bool edp_sink_present;
+ struct dp_trace dp_trace;
+
/* caps is the same as reported_link_cap. link_traing use
* reported_link_cap. Will clean up. TODO
*/
@@ -197,12 +220,14 @@ struct dc_link {
bool dp_mot_reset_segment;
/* Some USB4 docks do not handle turning off MST DSC once it has been enabled. */
bool dpia_mst_dsc_always_on;
+ /* Forced DPIA into TBT3 compatibility mode. */
+ bool dpia_forced_tbt3_mode;
} wa_flags;
struct link_mst_stream_allocation_table mst_stream_alloc_table;
struct dc_link_status link_status;
+ struct dprx_states dprx_states;
- struct link_trace link_trace;
struct gpio *hpd_gpio;
enum dc_link_fec_state fec_state;
};
@@ -307,6 +332,7 @@ void dc_link_blank_dp_stream(struct dc_link *link, bool hw_init);
*/
enum dc_detect_reason {
DETECT_REASON_BOOT,
+ DETECT_REASON_RESUMEFROMS3S4,
DETECT_REASON_HPD,
DETECT_REASON_HPDRX,
DETECT_REASON_FALLBACK,
@@ -316,10 +342,8 @@ enum dc_detect_reason {
bool dc_link_detect(struct dc_link *dc_link, enum dc_detect_reason reason);
bool dc_link_get_hpd_state(struct dc_link *dc_link);
enum dc_status dc_link_allocate_mst_payload(struct pipe_ctx *pipe_ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dc_status dc_link_reduce_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
enum dc_status dc_link_increase_mst_payload(struct pipe_ctx *pipe_ctx, uint32_t req_pbn);
-#endif
/* Notify DC about DP RX Interrupt (aka Short Pulse Interrupt).
* Return:
@@ -438,6 +462,11 @@ const struct dc_link_settings *dc_link_get_link_cap(
void dc_link_overwrite_extended_receiver_cap(
struct dc_link *link);
+bool dc_is_oem_i2c_device_present(
+ struct dc *dc,
+ size_t slave_address
+);
+
bool dc_submit_i2c(
struct dc *dc,
uint32_t link_index,
@@ -453,14 +482,29 @@ uint32_t dc_bandwidth_in_kbps_from_timing(
bool dc_link_is_fec_supported(const struct dc_link *link);
bool dc_link_should_enable_fec(const struct dc_link *link);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint32_t dc_link_bw_kbps_from_raw_frl_link_rate_data(uint8_t bw);
enum dp_link_encoding dc_link_dp_mst_decide_link_encoding_format(const struct dc_link *link);
-#endif
-const struct link_resource *dc_link_get_cur_link_res(const struct dc_link *link);
+void dc_link_get_cur_link_res(const struct dc_link *link,
+ struct link_resource *link_res);
/* take a snapshot of current link resource allocation state */
void dc_get_cur_link_res_map(const struct dc *dc, uint32_t *map);
/* restore link resource allocation state from a snapshot */
void dc_restore_link_res_map(const struct dc *dc, uint32_t *map);
+void dc_link_clear_dprx_states(struct dc_link *link);
+struct gpio *get_hpd_gpio(struct dc_bios *dcb,
+ struct graphics_object_id link_id,
+ struct gpio_service *gpio_service);
+void dp_trace_reset(struct dc_link *link);
+bool dc_dp_trace_is_initialized(struct dc_link *link);
+unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
+ bool in_detection);
+void dc_dp_trace_set_is_logged_flag(struct dc_link *link,
+ bool in_detection,
+ bool is_logged);
+bool dc_dp_trace_is_logged(struct dc_link *link,
+ bool in_detection);
+struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
+ bool in_detection);
+unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link);
#endif /* DC_LINK_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_stream.h b/drivers/gpu/drm/amd/display/dc/dc_stream.h
index e37c4a10bfd5..58941f4defb3 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_stream.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_stream.h
@@ -115,12 +115,10 @@ struct periodic_interrupt_config {
int lines_offset;
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_mst_stream_bw_update {
bool is_increase; // is bandwidth reduced or increased
uint32_t mst_stream_bw; // new mst bandwidth in kbps
};
-#endif
union stream_update_flags {
struct {
@@ -132,9 +130,8 @@ union stream_update_flags {
uint32_t gamut_remap:1;
uint32_t wb_update:1;
uint32_t dsc_changed : 1;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint32_t mst_bw : 1;
-#endif
+ uint32_t crtc_timing_adjust : 1;
} bits;
uint32_t raw;
@@ -165,7 +162,7 @@ struct dc_stream_state {
struct dc_info_packet vrr_infopacket;
struct dc_info_packet vsc_infopacket;
struct dc_info_packet vsp_infopacket;
-
+ uint8_t dsc_packed_pps[128];
struct rect src; /* composition area */
struct rect dst; /* stream addressable area */
@@ -249,6 +246,7 @@ struct dc_stream_state {
bool apply_edp_fast_boot_optimization;
bool apply_seamless_boot_optimization;
+ uint32_t apply_boot_odm_mode;
uint32_t stream_id;
@@ -288,13 +286,12 @@ struct dc_stream_update {
struct dc_writeback_update *wb_update;
struct dc_dsc_config *dsc_config;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_mst_stream_bw_update *mst_bw_update;
-#endif
struct dc_transfer_func *func_shaper;
struct dc_3dlut *lut3d_func;
struct test_pattern *pending_test_pattern;
+ struct dc_crtc_timing_adjust *crtc_timing_adjust;
};
bool dc_is_stream_unchanged(
@@ -530,4 +527,6 @@ bool dc_stream_get_crtc_position(struct dc *dc,
unsigned int *v_pos,
unsigned int *nom_v_pos);
+struct pipe_ctx *dc_stream_get_pipe_ctx(struct dc_stream_state *stream);
+
#endif /* DC_STREAM_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dc_types.h b/drivers/gpu/drm/amd/display/dc/dc_types.h
index 0285a4b38d05..2ba9f528c0fe 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_types.h
@@ -138,6 +138,7 @@ enum dc_edid_status {
EDID_BAD_CHECKSUM,
EDID_THE_SAME,
EDID_FALL_BACK,
+ EDID_PARTIAL_VALID,
};
enum act_return_status {
@@ -395,14 +396,11 @@ struct dc_lttpr_caps {
uint8_t max_link_rate;
uint8_t phy_repeater_cnt;
uint8_t max_ext_timeout;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
union dp_main_link_channel_coding_lttpr_cap main_link_channel_coding;
union dp_128b_132b_supported_lttpr_link_rates supported_128b_132b_rates;
-#endif
uint8_t aux_rd_interval[MAX_REPEATER_CNT - 1];
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_dongle_dfp_cap_ext {
bool supported;
uint16_t max_pixel_rate_in_mps;
@@ -414,7 +412,6 @@ struct dc_dongle_dfp_cap_ext {
struct dp_color_depth_caps ycbcr422_color_depth_caps;
struct dp_color_depth_caps ycbcr420_color_depth_caps;
};
-#endif
struct dc_dongle_caps {
/* dongle type (DP converter, CV smart dongle) */
@@ -429,10 +426,8 @@ struct dc_dongle_caps {
bool is_dp_hdmi_ycbcr420_converter;
uint32_t dp_hdmi_max_bpc;
uint32_t dp_hdmi_max_pixel_clk_in_khz;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint32_t dp_hdmi_frl_max_link_bw_in_kbps;
struct dc_dongle_dfp_cap_ext dfp_cap_ext;
-#endif
};
/* Scaling format */
enum scaling_transformation {
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
index 6d42a9cc9916..9e39cd7b203e 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_aux.c
@@ -87,7 +87,8 @@ static void release_engine(
engine->ddc = NULL;
- REG_UPDATE(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1);
+ REG_UPDATE_2(AUX_ARB_CONTROL, AUX_SW_DONE_USING_AUX_REG, 1,
+ AUX_SW_USE_AUX_REG_REQ, 0);
}
#define SW_CAN_ACCESS_AUX 1
@@ -413,7 +414,8 @@ static bool acquire(
return false;
if (!acquire_engine(engine)) {
- dal_ddc_close(ddc);
+ engine->ddc = ddc;
+ release_engine(engine);
return false;
}
@@ -564,13 +566,11 @@ int dce_aux_transfer_raw(struct ddc_service *ddc,
struct ddc *ddc_pin = ddc->ddc_pin;
struct dce_aux *aux_engine;
struct aux_request_transaction_data aux_req;
- struct aux_reply_transaction_data aux_rep;
uint8_t returned_bytes = 0;
int res = -1;
uint32_t status;
memset(&aux_req, 0, sizeof(aux_req));
- memset(&aux_rep, 0, sizeof(aux_rep));
aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en];
if (!acquire(aux_engine, ddc_pin)) {
@@ -878,7 +878,7 @@ bool dce_aux_transfer_with_retries(struct ddc_service *ddc,
default:
DC_TRACE_LEVEL_MESSAGE(DAL_TRACE_LEVEL_ERROR,
LOG_FLAG_Error_I2cAux,
- "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: FAILURE: AUX_TRANSACTION_REPLY_* unknown, default case.");
+ "dce_aux_transfer_with_retries: AUX_RET_SUCCESS: FAILURE: AUX_TRANSACTION_REPLY_* unknown, default case. Reply: %d", *payload->reply);
goto fail;
}
break;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
index 1435d7bc1f21..07359eb89efc 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clk_mgr.c
@@ -450,6 +450,8 @@ void dce_clock_read_ss_info(struct dce_clk_mgr *clk_mgr_dce)
clk_mgr_dce->dprefclk_ss_percentage =
info.spread_spectrum_percentage;
}
+ if (clk_mgr_dce->base.ctx->dc->debug.ignore_dpref_ss)
+ clk_mgr_dce->dprefclk_ss_percentage = 0;
}
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
index 2c7eb982eabc..845aa8a1027d 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.c
@@ -918,7 +918,6 @@ static bool dce112_program_pix_clk(
struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
struct bp_pixel_clock_parameters bp_pc_params = {0};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) {
unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
unsigned dp_dto_ref_100hz = 7000000;
@@ -932,7 +931,6 @@ static bool dce112_program_pix_clk(
REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
return true;
}
-#endif
/* First disable SS
* ATOMBIOS will enable by default SS on PLL for DP,
* do not disable it here
@@ -971,6 +969,96 @@ static bool dce112_program_pix_clk(
return true;
}
+static bool dcn31_program_pix_clk(
+ struct clock_source *clock_source,
+ struct pixel_clk_params *pix_clk_params,
+ struct pll_settings *pll_settings)
+{
+ struct dce110_clk_src *clk_src = TO_DCE110_CLK_SRC(clock_source);
+ unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
+ unsigned int dp_dto_ref_khz = clock_source->ctx->dc->clk_mgr->dprefclk_khz;
+ const struct pixel_rate_range_table_entry *e =
+ look_up_in_video_optimized_rate_tlb(pix_clk_params->requested_pix_clk_100hz / 10);
+ struct bp_pixel_clock_parameters bp_pc_params = {0};
+ enum transmitter_color_depth bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
+ // For these signal types Driver to program DP_DTO without calling VBIOS Command table
+ if (dc_is_dp_signal(pix_clk_params->signal_type) || dc_is_virtual_signal(pix_clk_params->signal_type)) {
+ if (e) {
+ /* Set DTO values: phase = target clock, modulo = reference clock*/
+ REG_WRITE(PHASE[inst], e->target_pixel_rate_khz * e->mult_factor);
+ REG_WRITE(MODULO[inst], dp_dto_ref_khz * e->div_factor);
+ } else {
+ /* Set DTO values: phase = target clock, modulo = reference clock*/
+ REG_WRITE(PHASE[inst], pll_settings->actual_pix_clk_100hz * 100);
+ REG_WRITE(MODULO[inst], dp_dto_ref_khz * 1000);
+ }
+ REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
+ } else {
+ if (IS_FPGA_MAXIMUS_DC(clock_source->ctx->dce_environment)) {
+ unsigned int inst = pix_clk_params->controller_id - CONTROLLER_ID_D0;
+ unsigned dp_dto_ref_100hz = 7000000;
+ unsigned clock_100hz = pll_settings->actual_pix_clk_100hz;
+
+ /* Set DTO values: phase = target clock, modulo = reference clock */
+ REG_WRITE(PHASE[inst], clock_100hz);
+ REG_WRITE(MODULO[inst], dp_dto_ref_100hz);
+
+ /* Enable DTO */
+ REG_UPDATE(PIXEL_RATE_CNTL[inst], DP_DTO0_ENABLE, 1);
+ return true;
+ }
+
+ /*ATOMBIOS expects pixel rate adjusted by deep color ratio)*/
+ bp_pc_params.controller_id = pix_clk_params->controller_id;
+ bp_pc_params.pll_id = clock_source->id;
+ bp_pc_params.target_pixel_clock_100hz = pll_settings->actual_pix_clk_100hz;
+ bp_pc_params.encoder_object_id = pix_clk_params->encoder_object_id;
+ bp_pc_params.signal_type = pix_clk_params->signal_type;
+
+ // Make sure we send the correct color depth to DMUB for HDMI
+ if (pix_clk_params->signal_type == SIGNAL_TYPE_HDMI_TYPE_A) {
+ switch (pix_clk_params->color_depth) {
+ case COLOR_DEPTH_888:
+ bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
+ break;
+ case COLOR_DEPTH_101010:
+ bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_30;
+ break;
+ case COLOR_DEPTH_121212:
+ bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_36;
+ break;
+ case COLOR_DEPTH_161616:
+ bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_48;
+ break;
+ default:
+ bp_pc_colour_depth = TRANSMITTER_COLOR_DEPTH_24;
+ break;
+ }
+ bp_pc_params.color_depth = bp_pc_colour_depth;
+ }
+
+ if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO) {
+ bp_pc_params.flags.SET_GENLOCK_REF_DIV_SRC =
+ pll_settings->use_external_clk;
+ bp_pc_params.flags.SET_XTALIN_REF_SRC =
+ !pll_settings->use_external_clk;
+ if (pix_clk_params->flags.SUPPORT_YCBCR420) {
+ bp_pc_params.flags.SUPPORT_YUV_420 = 1;
+ }
+ }
+ if (clk_src->bios->funcs->set_pixel_clock(
+ clk_src->bios, &bp_pc_params) != BP_RESULT_OK)
+ return false;
+ /* Resync deep color DTO */
+ if (clock_source->id != CLOCK_SOURCE_ID_DP_DTO)
+ dce112_program_pixel_clk_resync(clk_src,
+ pix_clk_params->signal_type,
+ pix_clk_params->color_depth,
+ pix_clk_params->flags.SUPPORT_YCBCR420);
+ }
+
+ return true;
+}
static bool dce110_clock_source_power_down(
struct clock_source *clk_src)
@@ -1013,9 +1101,12 @@ static bool get_pixel_clk_frequency_100hz(
* not be programmed equal to DPREFCLK
*/
modulo_hz = REG_READ(MODULO[inst]);
- *pixel_clk_khz = div_u64((uint64_t)clock_hz*
- clock_source->ctx->dc->clk_mgr->dprefclk_khz*10,
- modulo_hz);
+ if (modulo_hz)
+ *pixel_clk_khz = div_u64((uint64_t)clock_hz*
+ clock_source->ctx->dc->clk_mgr->dprefclk_khz*10,
+ modulo_hz);
+ else
+ *pixel_clk_khz = 0;
} else {
/* NOTE: There is agreement with VBIOS here that MODULO is
* programmed equal to DPREFCLK, in which case PHASE will be
@@ -1029,7 +1120,6 @@ static bool get_pixel_clk_frequency_100hz(
return false;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
const struct pixel_rate_range_table_entry video_optimized_pixel_rates[] = {
// /1.001 rates
@@ -1079,7 +1169,6 @@ const struct pixel_rate_range_table_entry *look_up_in_video_optimized_rate_tlb(
return NULL;
}
-#endif
static bool dcn20_program_pix_clk(
struct clock_source *clock_source,
@@ -1126,7 +1215,6 @@ static const struct clock_source_funcs dcn20_clk_src_funcs = {
.override_dp_pix_clk = dcn20_override_dp_pix_clk
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static bool dcn3_program_pix_clk(
struct clock_source *clock_source,
struct pixel_clk_params *pix_clk_params,
@@ -1162,7 +1250,7 @@ static uint32_t dcn3_get_pix_clk_dividers(
struct pixel_clk_params *pix_clk_params,
struct pll_settings *pll_settings)
{
- unsigned long long actual_pix_clk_100Hz = pix_clk_params->requested_pix_clk_100hz;
+ unsigned long long actual_pix_clk_100Hz = pix_clk_params ? pix_clk_params->requested_pix_clk_100hz : 0;
struct dce110_clk_src *clk_src;
clk_src = TO_DCE110_CLK_SRC(cs);
@@ -1205,7 +1293,14 @@ static const struct clock_source_funcs dcn3_clk_src_funcs = {
.get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
.get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
};
-#endif
+
+static const struct clock_source_funcs dcn31_clk_src_funcs = {
+ .cs_power_down = dce110_clock_source_power_down,
+ .program_pix_clk = dcn31_program_pix_clk,
+ .get_pix_clk_dividers = dcn3_get_pix_clk_dividers,
+ .get_pixel_clk_frequency_100hz = get_pixel_clk_frequency_100hz
+};
+
/*****************************************/
/* Constructor */
/*****************************************/
@@ -1591,7 +1686,6 @@ bool dcn20_clk_src_construct(
return ret;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool dcn3_clk_src_construct(
struct dce110_clk_src *clk_src,
struct dc_context *ctx,
@@ -1607,9 +1701,23 @@ bool dcn3_clk_src_construct(
return ret;
}
-#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+bool dcn31_clk_src_construct(
+ struct dce110_clk_src *clk_src,
+ struct dc_context *ctx,
+ struct dc_bios *bios,
+ enum clock_source_id id,
+ const struct dce110_clk_src_regs *regs,
+ const struct dce110_clk_src_shift *cs_shift,
+ const struct dce110_clk_src_mask *cs_mask)
+{
+ bool ret = dce112_clk_src_construct(clk_src, ctx, bios, id, regs, cs_shift, cs_mask);
+
+ clk_src->base.funcs = &dcn31_clk_src_funcs;
+
+ return ret;
+}
+
bool dcn301_clk_src_construct(
struct dce110_clk_src *clk_src,
struct dc_context *ctx,
@@ -1625,4 +1733,3 @@ bool dcn301_clk_src_construct(
return ret;
}
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h
index 692fa23ca02b..9eec3524335f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_clock_source.h
@@ -100,7 +100,6 @@
SRII(PIXEL_RATE_CNTL, OTG, 2),\
SRII(PIXEL_RATE_CNTL, OTG, 3)
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#define CS_COMMON_REG_LIST_DCN3_0(index, pllid) \
SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\
SRII(PHASE, DP_DTO, 0),\
@@ -130,9 +129,7 @@
SRII(PIXEL_RATE_CNTL, OTG, 1),\
SRII(PIXEL_RATE_CNTL, OTG, 2),\
SRII(PIXEL_RATE_CNTL, OTG, 3)
-#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#define CS_COMMON_REG_LIST_DCN3_02(index, pllid) \
SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\
SRII(PHASE, DP_DTO, 0),\
@@ -160,15 +157,13 @@
SRII(PIXEL_RATE_CNTL, OTG, 0),\
SRII(PIXEL_RATE_CNTL, OTG, 1)
-#endif
+
#define CS_COMMON_MASK_SH_LIST_DCN2_0(mask_sh)\
CS_SF(DP_DTO0_PHASE, DP_DTO0_PHASE, mask_sh),\
CS_SF(DP_DTO0_MODULO, DP_DTO0_MODULO, mask_sh),\
CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\
CS_SF(OTG0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE, mask_sh)
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-
#define CS_COMMON_REG_LIST_DCN1_0(index, pllid) \
SRI(PIXCLK_RESYNC_CNTL, PHYPLL, pllid),\
SRII(PHASE, DP_DTO, 0),\
@@ -190,7 +185,6 @@
CS_SF(PHYPLLA_PIXCLK_RESYNC_CNTL, PHYPLLA_DCCG_DEEP_COLOR_CNTL, mask_sh),\
CS_SF(OTG0_PIXEL_RATE_CNTL, DP_DTO0_ENABLE, mask_sh)
-#endif
#define CS_REG_FIELD_LIST(type) \
type PLL_REF_DIV_SRC; \
@@ -274,7 +268,6 @@ bool dcn20_clk_src_construct(
const struct dce110_clk_src_shift *cs_shift,
const struct dce110_clk_src_mask *cs_mask);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool dcn3_clk_src_construct(
struct dce110_clk_src *clk_src,
struct dc_context *ctx,
@@ -292,7 +285,15 @@ bool dcn301_clk_src_construct(
const struct dce110_clk_src_regs *regs,
const struct dce110_clk_src_shift *cs_shift,
const struct dce110_clk_src_mask *cs_mask);
-#endif
+
+bool dcn31_clk_src_construct(
+ struct dce110_clk_src *clk_src,
+ struct dc_context *ctx,
+ struct dc_bios *bios,
+ enum clock_source_id id,
+ const struct dce110_clk_src_regs *regs,
+ const struct dce110_clk_src_shift *cs_shift,
+ const struct dce110_clk_src_mask *cs_mask);
/* this table is use to find *1.001 and /1.001 pixel rates from non-precise pixel rate */
struct pixel_rate_range_table_entry {
@@ -303,10 +304,8 @@ struct pixel_rate_range_table_entry {
unsigned short div_factor;
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
extern const struct pixel_rate_range_table_entry video_optimized_pixel_rates[];
const struct pixel_rate_range_table_entry *look_up_in_video_optimized_rate_tlb(
unsigned int pixel_rate_khz);
-#endif
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
index 8cd841320ded..7183ac5780a4 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_dmcu.c
@@ -70,9 +70,7 @@
//Register access policy version
#define mmMP0_SMN_C2PMSG_91 0x1609B
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static const uint32_t abm_gain_stepsize = 0x0060;
-#endif
static bool dce_dmcu_init(struct dmcu *dmcu)
{
@@ -333,7 +331,6 @@ static void dce_get_psr_wait_loop(
return;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static void dcn10_get_dmcu_version(struct dmcu *dmcu)
{
struct dce_dmcu *dmcu_dce = TO_DCE_DMCU(dmcu);
@@ -930,7 +927,6 @@ static bool dcn10_recv_edid_cea_ack(struct dmcu *dmcu, int *offset)
return false;
}
-#endif //(CONFIG_DRM_AMD_DC_DCN)
#if defined(CONFIG_DRM_AMD_SECURE_DISPLAY)
static void dcn10_forward_crc_window(struct dmcu *dmcu,
@@ -1021,7 +1017,6 @@ static const struct dmcu_funcs dce_funcs = {
.is_dmcu_initialized = dce_is_dmcu_initialized
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static const struct dmcu_funcs dcn10_funcs = {
.dmcu_init = dcn10_dmcu_init,
.load_iram = dcn10_dmcu_load_iram,
@@ -1065,7 +1060,6 @@ static const struct dmcu_funcs dcn21_funcs = {
.lock_phy = dcn20_lock_phy,
.unlock_phy = dcn20_unlock_phy
};
-#endif
static void dce_dmcu_construct(
struct dce_dmcu *dmcu_dce,
@@ -1085,7 +1079,6 @@ static void dce_dmcu_construct(
dmcu_dce->dmcu_mask = dmcu_mask;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
static void dcn21_dmcu_construct(
struct dce_dmcu *dmcu_dce,
struct dc_context *ctx,
@@ -1103,7 +1096,6 @@ static void dcn21_dmcu_construct(
dmcu_dce->base.psp_version = psp_version;
}
}
-#endif
struct dmcu *dce_dmcu_create(
struct dc_context *ctx,
@@ -1126,7 +1118,6 @@ struct dmcu *dce_dmcu_create(
return &dmcu_dce->base;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dmcu *dcn10_dmcu_create(
struct dc_context *ctx,
const struct dce_dmcu_registers *regs,
@@ -1189,7 +1180,6 @@ struct dmcu *dcn21_dmcu_create(
return &dmcu_dce->base;
}
-#endif
void dce_dmcu_destroy(struct dmcu **dmcu)
{
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c
index dd41736bb5c4..f5cd2392fc5f 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.c
@@ -25,6 +25,32 @@
#include "dce_i2c.h"
#include "reg_helper.h"
+bool dce_i2c_oem_device_present(
+ struct resource_pool *pool,
+ struct ddc_service *ddc,
+ size_t slave_address
+)
+{
+ struct dc *dc = ddc->ctx->dc;
+ struct dc_bios *dcb = dc->ctx->dc_bios;
+ struct graphics_object_id id = {0};
+ struct graphics_object_i2c_info i2c_info;
+
+ if (!dc->ctx->dc_bios->fw_info.oem_i2c_present)
+ return false;
+
+ id.id = dc->ctx->dc_bios->fw_info.oem_i2c_obj_id;
+ id.enum_id = 0;
+ id.type = OBJECT_TYPE_GENERIC;
+ if (dcb->funcs->get_i2c_info(dcb, id, &i2c_info) != BP_RESULT_OK)
+ return false;
+
+ if (i2c_info.i2c_slave_address != slave_address)
+ return false;
+
+ return true;
+}
+
bool dce_i2c_submit_command(
struct resource_pool *pool,
struct ddc *ddc,
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.h b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.h
index a171c5cd8439..535fd58de450 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_i2c.h
@@ -30,6 +30,12 @@
#include "dce_i2c_hw.h"
#include "dce_i2c_sw.h"
+bool dce_i2c_oem_device_present(
+ struct resource_pool *pool,
+ struct ddc_service *ddc,
+ size_t slave_address
+);
+
bool dce_i2c_submit_command(
struct resource_pool *pool,
struct ddc *ddc,
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
index f1c61d5aee6c..0bc41414481e 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c
@@ -1325,7 +1325,8 @@ void dce110_link_encoder_disable_output(
void dce110_link_encoder_dp_set_lane_settings(
struct link_encoder *enc,
- const struct link_training_settings *link_settings)
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
{
struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
union dpcd_training_lane_set training_lane_set = { { 0 } };
@@ -1340,26 +1341,26 @@ void dce110_link_encoder_dp_set_lane_settings(
cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
cntl.transmitter = enc110->base.transmitter;
cntl.connector_obj_id = enc110->base.connector;
- cntl.lanes_number = link_settings->link_settings.lane_count;
+ cntl.lanes_number = link_settings->lane_count;
cntl.hpd_sel = enc110->base.hpd_source;
- cntl.pixel_clock = link_settings->link_settings.link_rate *
+ cntl.pixel_clock = link_settings->link_rate *
LINK_RATE_REF_FREQ_IN_KHZ;
- for (lane = 0; lane < link_settings->link_settings.lane_count; lane++) {
+ for (lane = 0; lane < link_settings->lane_count; lane++) {
/* translate lane settings */
training_lane_set.bits.VOLTAGE_SWING_SET =
- link_settings->lane_settings[lane].VOLTAGE_SWING;
+ lane_settings[lane].VOLTAGE_SWING;
training_lane_set.bits.PRE_EMPHASIS_SET =
- link_settings->lane_settings[lane].PRE_EMPHASIS;
+ lane_settings[lane].PRE_EMPHASIS;
/* post cursor 2 setting only applies to HBR2 link rate */
- if (link_settings->link_settings.link_rate == LINK_RATE_HIGH2) {
+ if (link_settings->link_rate == LINK_RATE_HIGH2) {
/* this is passed to VBIOS
* to program post cursor 2 level */
training_lane_set.bits.POST_CURSOR2_SET =
- link_settings->lane_settings[lane].POST_CURSOR2;
+ lane_settings[lane].POST_CURSOR2;
}
cntl.lane_select = lane;
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h
index fc6ade824c23..261c70e01e33 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h
@@ -279,7 +279,8 @@ void dce110_link_encoder_disable_output(
/* set DP lane settings */
void dce110_link_encoder_dp_set_lane_settings(
struct link_encoder *enc,
- const struct link_training_settings *link_settings);
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
void dce110_link_encoder_dp_set_phy_pattern(
struct link_encoder *enc,
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
index 779bc92a2968..a8c92b517df1 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c
@@ -136,7 +136,7 @@ static void dce110_update_generic_info_packet(
AFMT_GENERIC0_UPDATE, (packet_index == 0),
AFMT_GENERIC2_UPDATE, (packet_index == 2));
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+
if (REG(AFMT_VBI_PACKET_CONTROL1)) {
switch (packet_index) {
case 0:
@@ -175,7 +175,6 @@ static void dce110_update_generic_info_packet(
break;
}
}
-#endif
}
static void dce110_update_hdmi_info_packet(
@@ -230,7 +229,6 @@ static void dce110_update_hdmi_info_packet(
HDMI_GENERIC1_SEND, send,
HDMI_GENERIC1_LINE, line);
break;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case 4:
if (REG(HDMI_GENERIC_PACKET_CONTROL2))
REG_UPDATE_3(HDMI_GENERIC_PACKET_CONTROL2,
@@ -259,7 +257,6 @@ static void dce110_update_hdmi_info_packet(
HDMI_GENERIC1_SEND, send,
HDMI_GENERIC1_LINE, line);
break;
-#endif
default:
/* invalid HW packet index */
DC_LOG_WARNING(
@@ -277,7 +274,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
bool use_vsc_sdp_for_colorimetry,
uint32_t enable_sdp_splitting)
{
-#if defined(CONFIG_DRM_AMD_DC_DCN)
uint32_t h_active_start;
uint32_t v_active_start;
uint32_t misc0 = 0;
@@ -288,7 +284,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
uint8_t colorimetry_bpc;
uint8_t dynamic_range_rgb = 0; /*full range*/
uint8_t dynamic_range_ycbcr = 1; /*bt709*/
-#endif
struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
struct dc_crtc_timing hw_crtc_timing = *crtc_timing;
@@ -329,10 +324,8 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
if (enc110->se_mask->DP_VID_M_DOUBLE_VALUE_EN)
REG_UPDATE(DP_VID_TIMING, DP_VID_M_DOUBLE_VALUE_EN, 1);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (enc110->se_mask->DP_VID_N_MUL)
REG_UPDATE(DP_VID_TIMING, DP_VID_N_MUL, 1);
-#endif
break;
default:
REG_UPDATE(DP_PIXEL_FORMAT, DP_PIXEL_ENCODING,
@@ -340,10 +333,8 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
break;
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (REG(DP_MSA_MISC))
misc1 = REG_READ(DP_MSA_MISC);
-#endif
/* set color depth */
@@ -374,7 +365,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
/* set dynamic range and YCbCr range */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
switch (hw_crtc_timing.display_color_depth) {
case COLOR_DEPTH_666:
colorimetry_bpc = 0;
@@ -454,7 +444,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
DP_DYN_RANGE, dynamic_range_rgb,
DP_YCBCR_RANGE, dynamic_range_ycbcr);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (REG(DP_MSA_COLORIMETRY))
REG_SET(DP_MSA_COLORIMETRY, 0, DP_MSA_MISC0, misc0);
@@ -468,7 +457,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
REG_SET_2(DP_MSA_TIMING_PARAM1, 0,
DP_MSA_HTOTAL, hw_crtc_timing.h_total,
DP_MSA_VTOTAL, hw_crtc_timing.v_total);
-#endif
/* calcuate from vesa timing parameters
* h_active_start related to leading edge of sync
@@ -489,7 +477,6 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
hw_crtc_timing.v_front_porch;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* start at begining of left border */
if (REG(DP_MSA_TIMING_PARAM2))
REG_SET_2(DP_MSA_TIMING_PARAM2, 0,
@@ -514,9 +501,7 @@ static void dce110_stream_encoder_dp_set_stream_attribute(
hw_crtc_timing.h_addressable + hw_crtc_timing.h_border_right,
DP_MSA_VHEIGHT, hw_crtc_timing.v_border_top +
hw_crtc_timing.v_addressable + hw_crtc_timing.v_border_bottom);
-#endif
}
-#endif
}
static void dce110_stream_encoder_set_stream_attribute_helper(
@@ -787,7 +772,6 @@ static void dce110_stream_encoder_update_hdmi_info_packets(
dce110_update_hdmi_info_packet(enc110, 3, &info_frame->hdrsmd);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (enc110->se_mask->HDMI_DB_DISABLE) {
/* for bring up, disable dp double TODO */
if (REG(HDMI_DB_CONTROL))
@@ -799,7 +783,6 @@ static void dce110_stream_encoder_update_hdmi_info_packets(
dce110_update_hdmi_info_packet(enc110, 3, &info_frame->spd);
dce110_update_hdmi_info_packet(enc110, 4, &info_frame->hdrsmd);
}
-#endif
}
static void dce110_stream_encoder_stop_hdmi_info_packets(
@@ -825,7 +808,6 @@ static void dce110_stream_encoder_stop_hdmi_info_packets(
HDMI_GENERIC1_LINE, 0,
HDMI_GENERIC1_SEND, 0);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* stop generic packets 2 & 3 on HDMI */
if (REG(HDMI_GENERIC_PACKET_CONTROL2))
REG_SET_6(HDMI_GENERIC_PACKET_CONTROL2, 0,
@@ -844,7 +826,6 @@ static void dce110_stream_encoder_stop_hdmi_info_packets(
HDMI_GENERIC1_CONT, 0,
HDMI_GENERIC1_LINE, 0,
HDMI_GENERIC1_SEND, 0);
-#endif
}
static void dce110_stream_encoder_update_dp_info_packets(
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c
index faad8555ddbb..fff1d07d865d 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.c
@@ -22,20 +22,23 @@
* Authors: AMD
*/
-#include "dmub_outbox.h"
+#include "dc.h"
#include "dc_dmub_srv.h"
+#include "dmub_outbox.h"
#include "dmub/inc/dmub_cmd.h"
-/**
- * dmub_enable_outbox_notification - Sends inbox cmd to dmub to enable outbox1
- * messages with interrupt. Dmub sends outbox1
- * message and triggers outbox1 interrupt.
- * @dc: dc structure
+/*
+ * Function: dmub_enable_outbox_notification
+ *
+ * @brief
+ * Sends inbox cmd to dmub for enabling outbox notifications to x86.
+ *
+ * @param
+ * [in] dmub_srv: dmub_srv structure
*/
-void dmub_enable_outbox_notification(struct dc *dc)
+void dmub_enable_outbox_notification(struct dc_dmub_srv *dmub_srv)
{
union dmub_rb_cmd cmd;
- struct dc_context *dc_ctx = dc->ctx;
memset(&cmd, 0x0, sizeof(cmd));
cmd.outbox1_enable.header.type = DMUB_CMD__OUTBOX1_ENABLE;
@@ -45,7 +48,7 @@ void dmub_enable_outbox_notification(struct dc *dc)
sizeof(cmd.outbox1_enable.header);
cmd.outbox1_enable.enable = true;
- dc_dmub_srv_cmd_queue(dc_ctx->dmub_srv, &cmd);
- dc_dmub_srv_cmd_execute(dc_ctx->dmub_srv);
- dc_dmub_srv_wait_idle(dc_ctx->dmub_srv);
+ dc_dmub_srv_cmd_queue(dmub_srv, &cmd);
+ dc_dmub_srv_cmd_execute(dmub_srv);
+ dc_dmub_srv_wait_idle(dmub_srv);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.h b/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.h
index 4e0aa0d1a2d5..58ceabb9d497 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.h
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_outbox.h
@@ -26,8 +26,8 @@
#ifndef _DMUB_OUTBOX_H_
#define _DMUB_OUTBOX_H_
-#include "dc.h"
+struct dc_dmub_srv;
-void dmub_enable_outbox_notification(struct dc *dc);
+void dmub_enable_outbox_notification(struct dc_dmub_srv *dmub_srv);
#endif /* _DMUB_OUTBOX_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
index 87ed48d5530d..1d4f0c45b536 100644
--- a/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
+++ b/drivers/gpu/drm/amd/display/dc/dce/dmub_psr.c
@@ -138,6 +138,10 @@ static bool dmub_psr_set_version(struct dmub_psr *dmub, struct dc_stream_state *
cmd.psr_set_version.psr_set_version_data.version = PSR_VERSION_UNSUPPORTED;
break;
}
+
+ if (cmd.psr_set_version.psr_set_version_data.version == PSR_VERSION_UNSUPPORTED)
+ return false;
+
cmd.psr_set_version.psr_set_version_data.cmd_version = DMUB_CMD_PSR_CONTROL_VERSION_1;
cmd.psr_set_version.psr_set_version_data.panel_inst = panel_inst;
cmd.psr_set_version.header.payload_bytes = sizeof(struct dmub_cmd_psr_set_version_data);
@@ -227,7 +231,7 @@ static void dmub_psr_set_level(struct dmub_psr *dmub, uint16_t psr_level, uint8_
dc_dmub_srv_wait_idle(dc->dmub_srv);
}
-/**
+/*
* Set PSR power optimization flags.
*/
static void dmub_psr_set_power_opt(struct dmub_psr *dmub, unsigned int power_opt, uint8_t panel_inst)
@@ -316,6 +320,7 @@ static bool dmub_psr_copy_settings(struct dmub_psr *dmub,
copy_settings_data->otg_inst = 0;
// Misc
+ copy_settings_data->use_phy_fsm = link->ctx->dc->debug.psr_power_use_phy_fsm;
copy_settings_data->psr_level = psr_context->psr_level.u32all;
copy_settings_data->smu_optimizations_en = psr_context->allow_smu_optimizations;
copy_settings_data->multi_disp_optimizations_en = psr_context->allow_multi_disp_optimizations;
diff --git a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
index eb2755bdb30e..5f2afa5b4814 100644
--- a/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dce110/dce110_hw_sequencer.c
@@ -49,9 +49,7 @@
#include "link_enc_cfg.h"
#include "link_hwss.h"
#include "dc_link_dp.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "dccg.h"
-#endif
#include "clock_source.h"
#include "clk_mgr.h"
#include "abm.h"
@@ -69,6 +67,7 @@
#include "dcn10/dcn10_hw_sequencer.h"
+#include "link/link_dp_trace.h"
#include "dce110_hw_sequencer.h"
#define GAMMA_HW_POINTS_NUM 256
@@ -669,17 +668,12 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
struct dc_link *link = pipe_ctx->stream->link;
const struct dc *dc = link->dc;
-
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
uint32_t active_total_with_borders;
uint32_t early_control = 0;
struct timing_generator *tg = pipe_ctx->stream_res.tg;
- /* For MST, there are multiply stream go to only one link.
- * connect DIG back_end to front_end while enable_stream and
- * disconnect them during disable_stream
- * BY this, it is logic clean to separate stream and link */
- link->link_enc->funcs->connect_dig_be_to_fe(link->link_enc,
- pipe_ctx->stream_res.stream_enc->id, true);
+ link_hwss->setup_stream_encoder(pipe_ctx);
dc->hwss.update_info_frame(pipe_ctx);
@@ -795,7 +789,7 @@ void dce110_edp_wait_for_hpd_ready(
dal_gpio_destroy_irq(&hpd);
if (false == edp_hpd_high) {
- DC_LOG_ERROR(
+ DC_LOG_WARNING(
"%s: wait timed out!\n", __func__);
}
}
@@ -826,19 +820,19 @@ void dce110_edp_power_control(
div64_u64(dm_get_elapse_time_in_ns(
ctx,
current_ts,
- link->link_trace.time_stamp.edp_poweroff), 1000000);
+ dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
unsigned long long time_since_edp_poweron_ms =
div64_u64(dm_get_elapse_time_in_ns(
ctx,
current_ts,
- link->link_trace.time_stamp.edp_poweron), 1000000);
+ dp_trace_get_edp_poweron_timestamp(link)), 1000000);
DC_LOG_HW_RESUME_S3(
"%s: transition: power_up=%d current_ts=%llu edp_poweroff=%llu edp_poweron=%llu time_since_edp_poweroff_ms=%llu time_since_edp_poweron_ms=%llu",
__func__,
power_up,
current_ts,
- link->link_trace.time_stamp.edp_poweroff,
- link->link_trace.time_stamp.edp_poweron,
+ dp_trace_get_edp_poweroff_timestamp(link),
+ dp_trace_get_edp_poweron_timestamp(link),
time_since_edp_poweroff_ms,
time_since_edp_poweron_ms);
@@ -853,7 +847,7 @@ void dce110_edp_power_control(
link->local_sink->edid_caps.panel_patch.extra_t12_ms;
/* Adjust remaining_min_edp_poweroff_time_ms if this is not the first time. */
- if (link->link_trace.time_stamp.edp_poweroff != 0) {
+ if (dp_trace_get_edp_poweroff_timestamp(link) != 0) {
if (time_since_edp_poweroff_ms < remaining_min_edp_poweroff_time_ms)
remaining_min_edp_poweroff_time_ms =
remaining_min_edp_poweroff_time_ms - time_since_edp_poweroff_ms;
@@ -911,17 +905,13 @@ void dce110_edp_power_control(
__func__, (power_up ? "On":"Off"),
bp_result);
- if (!power_up)
- /*save driver power off time stamp*/
- link->link_trace.time_stamp.edp_poweroff = dm_get_timestamp(ctx);
- else
- link->link_trace.time_stamp.edp_poweron = dm_get_timestamp(ctx);
+ dp_trace_set_edp_power_timestamp(link, power_up);
DC_LOG_HW_RESUME_S3(
"%s: updated values: edp_poweroff=%llu edp_poweron=%llu\n",
__func__,
- link->link_trace.time_stamp.edp_poweroff,
- link->link_trace.time_stamp.edp_poweron);
+ dp_trace_get_edp_poweroff_timestamp(link),
+ dp_trace_get_edp_poweron_timestamp(link));
if (bp_result != BP_RESULT_OK)
DC_LOG_ERROR(
@@ -949,14 +939,14 @@ void dce110_edp_wait_for_T12(
return;
if (!link->panel_cntl->funcs->is_panel_powered_on(link->panel_cntl) &&
- link->link_trace.time_stamp.edp_poweroff != 0) {
+ dp_trace_get_edp_poweroff_timestamp(link) != 0) {
unsigned int t12_duration = 500; // Default T12 as per spec
unsigned long long current_ts = dm_get_timestamp(ctx);
unsigned long long time_since_edp_poweroff_ms =
div64_u64(dm_get_elapse_time_in_ns(
ctx,
current_ts,
- link->link_trace.time_stamp.edp_poweroff), 1000000);
+ dp_trace_get_edp_poweroff_timestamp(link)), 1000000);
t12_duration += link->local_sink->edid_caps.panel_patch.extra_t12_ms; // Add extra T12
@@ -1112,17 +1102,12 @@ void dce110_enable_audio_stream(struct pipe_ctx *pipe_ctx)
clk_mgr->funcs->enable_pme_wa(clk_mgr);
/* un-mute audio */
/* TODO: audio should be per stream rather than per link */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx))
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.hpo_dp_stream_enc, false);
else
pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.stream_enc, false);
-#else
- pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
- pipe_ctx->stream_res.stream_enc, false);
-#endif
if (pipe_ctx->stream_res.audio)
pipe_ctx->stream_res.audio->enabled = true;
}
@@ -1145,32 +1130,22 @@ void dce110_disable_audio_stream(struct pipe_ctx *pipe_ctx)
if (pipe_ctx->stream_res.audio && pipe_ctx->stream_res.audio->enabled == false)
return;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx))
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.hpo_dp_stream_enc, true);
else
pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
pipe_ctx->stream_res.stream_enc, true);
-#else
- pipe_ctx->stream_res.stream_enc->funcs->audio_mute_control(
- pipe_ctx->stream_res.stream_enc, true);
-#endif
if (pipe_ctx->stream_res.audio) {
pipe_ctx->stream_res.audio->enabled = false;
if (dc_is_dp_signal(pipe_ctx->stream->signal))
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx))
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_disable(
pipe_ctx->stream_res.hpo_dp_stream_enc);
else
pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
pipe_ctx->stream_res.stream_enc);
-#else
- pipe_ctx->stream_res.stream_enc->funcs->dp_audio_disable(
- pipe_ctx->stream_res.stream_enc);
-#endif
else
pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_disable(
pipe_ctx->stream_res.stream_enc);
@@ -1195,7 +1170,7 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link;
struct dc *dc = pipe_ctx->stream->ctx->dc;
- struct link_encoder *link_enc = NULL;
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
if (dc_is_hdmi_tmds_signal(pipe_ctx->stream->signal)) {
pipe_ctx->stream_res.stream_enc->funcs->stop_hdmi_info_packets(
@@ -1204,54 +1179,26 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
pipe_ctx->stream_res.stream_enc);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx)) {
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->stop_dp_info_packets(
pipe_ctx->stream_res.hpo_dp_stream_enc);
} else if (dc_is_dp_signal(pipe_ctx->stream->signal))
-#else
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
-#endif
pipe_ctx->stream_res.stream_enc->funcs->stop_dp_info_packets(
pipe_ctx->stream_res.stream_enc);
dc->hwss.disable_audio_stream(pipe_ctx);
- /* Link encoder may have been dynamically assigned to non-physical display endpoint. */
- if (link->ep_type == DISPLAY_ENDPOINT_PHY)
- link_enc = link->link_enc;
- else if (dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_link(link->ctx->dc, link);
- ASSERT(link_enc);
+ link_hwss->reset_stream_encoder(pipe_ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx)) {
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->disable(
- pipe_ctx->stream_res.hpo_dp_stream_enc);
- setup_dp_hpo_stream(pipe_ctx, false);
- /* TODO - DP2.0 HW: unmap stream from link encoder here */
- } else {
- if (link_enc)
- link_enc->funcs->connect_dig_be_to_fe(
- link_enc,
- pipe_ctx->stream_res.stream_enc->id,
- false);
- }
-#else
- if (link_enc)
- link_enc->funcs->connect_dig_be_to_fe(
- link->link_enc,
- pipe_ctx->stream_res.stream_enc->id,
- false);
-#endif
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE);
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- if (dc->hwseq->funcs.setup_hpo_hw_control && is_dp_128b_132b_signal(pipe_ctx))
- dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, false);
-#endif
-
+ /* TODO: This looks like a bug to me as we are disabling HPO IO when
+ * we are just disabling a single HPO stream. Shouldn't we disable HPO
+ * HW control only when HPOs for all streams are disabled?
+ */
+ if (pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control)
+ pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control(
+ pipe_ctx->stream->ctx->dc->hwseq, false);
+ }
}
void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
@@ -1285,15 +1232,11 @@ void dce110_blank_stream(struct pipe_ctx *pipe_ctx)
link->dc->hwss.set_abm_immediate_disable(pipe_ctx);
}
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx)) {
/* TODO - DP2.0 HW: Set ODM mode in dp hpo encoder here */
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_blank(
pipe_ctx->stream_res.hpo_dp_stream_enc);
} else if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
-#else
- if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
-#endif
pipe_ctx->stream_res.stream_enc->funcs->dp_blank(link, pipe_ctx->stream_res.stream_enc);
if (!dc_is_embedded_signal(pipe_ctx->stream->signal)) {
@@ -1422,11 +1365,9 @@ static void program_scaler(const struct dc *dc,
{
struct tg_color color = {0};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* TOFPGA */
if (pipe_ctx->plane_res.xfm->funcs->transform_set_pixel_storage_depth == NULL)
return;
-#endif
if (dc->debug.visual_confirm == VISUAL_CONFIRM_SURFACE)
get_surface_visual_confirm_color(pipe_ctx, &color);
@@ -1535,7 +1476,6 @@ static enum dc_status apply_single_controller_ctx_to_hw(
build_audio_output(context, pipe_ctx, &audio_output);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
-#if defined(CONFIG_DRM_AMD_DC_DCN)
if (is_dp_128b_132b_signal(pipe_ctx))
pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->dp_audio_setup(
pipe_ctx->stream_res.hpo_dp_stream_enc,
@@ -1546,12 +1486,6 @@ static enum dc_status apply_single_controller_ctx_to_hw(
pipe_ctx->stream_res.stream_enc,
pipe_ctx->stream_res.audio->inst,
&pipe_ctx->stream->audio_info);
-#else
- pipe_ctx->stream_res.stream_enc->funcs->dp_audio_setup(
- pipe_ctx->stream_res.stream_enc,
- pipe_ctx->stream_res.audio->inst,
- &pipe_ctx->stream->audio_info);
-#endif
else
pipe_ctx->stream_res.stream_enc->funcs->hdmi_audio_setup(
pipe_ctx->stream_res.stream_enc,
@@ -1570,14 +1504,37 @@ static enum dc_status apply_single_controller_ctx_to_hw(
if (!pipe_ctx->stream->apply_seamless_boot_optimization && dc->config.use_pipe_ctx_sync_logic)
check_syncd_pipes_for_disabled_master_pipe(dc, context, pipe_ctx->pipe_idx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+ pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
+ pipe_ctx->stream_res.opp,
+ &stream->bit_depth_params,
+ &stream->clamping);
+
+ pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
+ pipe_ctx->stream_res.opp,
+ COLOR_SPACE_YCBCR601,
+ stream->timing.display_color_depth,
+ stream->signal);
+
+ while (odm_pipe) {
+ odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion(
+ odm_pipe->stream_res.opp,
+ COLOR_SPACE_YCBCR601,
+ stream->timing.display_color_depth,
+ stream->signal);
+
+ odm_pipe->stream_res.opp->funcs->opp_program_fmt(
+ odm_pipe->stream_res.opp,
+ &stream->bit_depth_params,
+ &stream->clamping);
+ odm_pipe = odm_pipe->next_odm_pipe;
+ }
+
/* DCN3.1 FPGA Workaround
* Need to enable HPO DP Stream Encoder before setting OTG master enable.
* To do so, move calling function enable_stream_timing to only be done AFTER calling
* function core_link_enable_stream
*/
if (!(hws->wa.dp_hpo_and_otg_sequence && is_dp_128b_132b_signal(pipe_ctx)))
-#endif
/* */
/* Do not touch stream timing on seamless boot optimization. */
if (!pipe_ctx->stream->apply_seamless_boot_optimization)
@@ -1611,34 +1568,9 @@ static enum dc_status apply_single_controller_ctx_to_hw(
if (dc_is_dp_signal(pipe_ctx->stream->signal))
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_OTG);
- pipe_ctx->stream_res.opp->funcs->opp_set_dyn_expansion(
- pipe_ctx->stream_res.opp,
- COLOR_SPACE_YCBCR601,
- stream->timing.display_color_depth,
- stream->signal);
-
- pipe_ctx->stream_res.opp->funcs->opp_program_fmt(
- pipe_ctx->stream_res.opp,
- &stream->bit_depth_params,
- &stream->clamping);
- while (odm_pipe) {
- odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion(
- odm_pipe->stream_res.opp,
- COLOR_SPACE_YCBCR601,
- stream->timing.display_color_depth,
- stream->signal);
-
- odm_pipe->stream_res.opp->funcs->opp_program_fmt(
- odm_pipe->stream_res.opp,
- &stream->bit_depth_params,
- &stream->clamping);
- odm_pipe = odm_pipe->next_odm_pipe;
- }
-
if (!stream->dpms_off)
core_link_enable_stream(context, pipe_ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* DCN3.1 FPGA Workaround
* Need to enable HPO DP Stream Encoder before setting OTG master enable.
* To do so, move calling function enable_stream_timing to only be done AFTER calling
@@ -1648,9 +1580,8 @@ static enum dc_status apply_single_controller_ctx_to_hw(
if (!pipe_ctx->stream->apply_seamless_boot_optimization)
hws->funcs.enable_stream_timing(pipe_ctx, context, dc);
}
-#endif
- pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
+ pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL;
pipe_ctx->stream->link->psr_settings.psr_feature_enabled = false;
@@ -1826,7 +1757,8 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
edp_link->link_status.link_active) {
struct dc_stream_state *edp_stream = edp_streams[0];
- can_apply_edp_fast_boot = !is_edp_ilr_optimization_required(edp_stream->link, &edp_stream->timing);
+ can_apply_edp_fast_boot = dc_validate_boot_timing(dc,
+ edp_stream->sink, &edp_stream->timing);
edp_stream->apply_edp_fast_boot_optimization = can_apply_edp_fast_boot;
if (can_apply_edp_fast_boot)
DC_LOG_EVENT_LINK_TRAINING("eDP fast boot disabled to optimize link rate\n");
@@ -1834,29 +1766,9 @@ void dce110_enable_accelerated_mode(struct dc *dc, struct dc_state *context)
break;
}
}
-
- /*
- * TO-DO: So far the code logic below only addresses single eDP case.
- * For dual eDP case, there are a few things that need to be
- * implemented first:
- *
- * 1. Change the fastboot logic above, so eDP link[0 or 1]'s
- * stream[0 or 1] will all be checked.
- *
- * 2. Change keep_edp_vdd_on to an array, and maintain keep_edp_vdd_on
- * for each eDP.
- *
- * Once above 2 things are completed, we can then change the logic below
- * correspondingly, so dual eDP case will be fully covered.
- */
-
- // We are trying to enable eDP, don't power down VDD if eDP stream is existing
- if ((edp_stream_num == 1 && edp_streams[0] != NULL) || can_apply_edp_fast_boot) {
+ // We are trying to enable eDP, don't power down VDD
+ if (can_apply_edp_fast_boot)
keep_edp_vdd_on = true;
- DC_LOG_EVENT_LINK_TRAINING("Keep eDP Vdd on\n");
- } else {
- DC_LOG_EVENT_LINK_TRAINING("No eDP stream enabled, turn eDP Vdd off\n");
- }
}
// Check seamless boot support
@@ -2248,8 +2160,6 @@ static void dce110_setup_audio_dto(
build_audio_output(context, pipe_ctx, &audio_output);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
- /* For DCN3.1, audio to HPO FRL encoder is using audio DTBCLK DTO */
if (dc->res_pool->dccg && dc->res_pool->dccg->funcs->set_audio_dtbclk_dto) {
/* disable audio DTBCLK DTO */
dc->res_pool->dccg->funcs->set_audio_dtbclk_dto(
@@ -2266,13 +2176,6 @@ static void dce110_setup_audio_dto(
pipe_ctx->stream->signal,
&audio_output.crtc_info,
&audio_output.pll_info);
-#else
- pipe_ctx->stream_res.audio->funcs->wall_dto_setup(
- pipe_ctx->stream_res.audio,
- pipe_ctx->stream->signal,
- &audio_output.crtc_info,
- &audio_output.pll_info);
-#endif
break;
}
}
@@ -2795,7 +2698,7 @@ static void dce110_program_front_end_for_pipe(
pipe_ctx->plane_res.xfm->funcs->transform_set_gamut_remap(pipe_ctx->plane_res.xfm, &adjust);
- pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != 0;
+ pipe_ctx->plane_res.scl_data.lb_params.alpha_en = pipe_ctx->bottom_pipe != NULL;
program_scaler(dc, pipe_ctx);
diff --git a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
index ee55cda854bf..560da6cbcaa3 100644
--- a/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
@@ -862,7 +862,7 @@ static struct clock_source *find_matching_pll(
return NULL;
}
- return 0;
+ return NULL;
}
static enum dc_status build_mapped_resource(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
index f4f423d0b8c3..80595d7f060c 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
@@ -940,6 +940,7 @@ static const struct hubbub_funcs hubbub1_funcs = {
.program_watermarks = hubbub1_program_watermarks,
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
+ .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
};
void hubbub1_construct(struct hubbub *hubbub,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
index ea185c877323..3a7f76e2c598 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.c
@@ -1311,6 +1311,20 @@ void hubp1_set_flip_int(struct hubp *hubp)
return;
}
+/**
+ * hubp1_wait_pipe_read_start - wait for hubp ret path starting read.
+ *
+ * @hubp: hubp struct reference.
+ */
+static void hubp1_wait_pipe_read_start(struct hubp *hubp)
+{
+ struct dcn10_hubp *hubp1 = TO_DCN10_HUBP(hubp);
+
+ REG_WAIT(HUBPRET_READ_LINE_STATUS,
+ PIPE_READ_VBLANK, 0,
+ 1, 1000);
+}
+
void hubp1_init(struct hubp *hubp)
{
//do nothing
@@ -1345,6 +1359,7 @@ static const struct hubp_funcs dcn10_hubp_funcs = {
.hubp_soft_reset = hubp1_soft_reset,
.hubp_in_blank = hubp1_in_blank,
.hubp_set_flip_int = hubp1_set_flip_int,
+ .hubp_wait_pipe_read_start = hubp1_wait_pipe_read_start,
};
/*****************************************/
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h
index 9cb8c383d673..0b17c2993ca5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubp.h
@@ -76,6 +76,7 @@
SRI(DCSURF_SURFACE_CONTROL, HUBPREQ, id),\
SRI(DCSURF_SURFACE_FLIP_INTERRUPT, HUBPREQ, id),\
SRI(HUBPRET_CONTROL, HUBPRET, id),\
+ SRI(HUBPRET_READ_LINE_STATUS, HUBPRET, id),\
SRI(DCN_EXPANSION_MODE, HUBPREQ, id),\
SRI(DCHUBP_REQ_SIZE_CONFIG, HUBP, id),\
SRI(DCHUBP_REQ_SIZE_CONFIG_C, HUBP, id),\
@@ -186,6 +187,7 @@
uint32_t DCSURF_SURFACE_CONTROL; \
uint32_t DCSURF_SURFACE_FLIP_INTERRUPT; \
uint32_t HUBPRET_CONTROL; \
+ uint32_t HUBPRET_READ_LINE_STATUS; \
uint32_t DCN_EXPANSION_MODE; \
uint32_t DCHUBP_REQ_SIZE_CONFIG; \
uint32_t DCHUBP_REQ_SIZE_CONFIG_C; \
@@ -338,6 +340,7 @@
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, DET_BUF_PLANE1_BASE_ADDRESS, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CB_B, mask_sh),\
HUBP_SF(HUBPRET0_HUBPRET_CONTROL, CROSSBAR_SRC_CR_R, mask_sh),\
+ HUBP_SF(HUBPRET0_HUBPRET_READ_LINE_STATUS, PIPE_READ_VBLANK, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, DRQ_EXPANSION_MODE, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, PRQ_EXPANSION_MODE, mask_sh),\
HUBP_SF(HUBPREQ0_DCN_EXPANSION_MODE, MRQ_EXPANSION_MODE, mask_sh),\
@@ -538,6 +541,7 @@
type DET_BUF_PLANE1_BASE_ADDRESS;\
type CROSSBAR_SRC_CB_B;\
type CROSSBAR_SRC_CR_R;\
+ type PIPE_READ_VBLANK;\
type DRQ_EXPANSION_MODE;\
type PRQ_EXPANSION_MODE;\
type MRQ_EXPANSION_MODE;\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
index 530a72e3eefe..e3a62873c0e7 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
@@ -107,7 +107,7 @@ void dcn10_lock_all_pipes(struct dc *dc,
* (un)locking. Also skip if pipe is disabled.
*/
if (pipe_ctx->top_pipe ||
- !pipe_ctx->stream || !pipe_ctx->plane_state ||
+ !pipe_ctx->stream ||
!tg->funcs->is_tg_enabled(tg))
continue;
@@ -1112,9 +1112,13 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
void dcn10_verify_allow_pstate_change_high(struct dc *dc)
{
+ struct hubbub *hubbub = dc->res_pool->hubbub;
static bool should_log_hw_state; /* prevent hw state log by default */
- if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) {
+ if (!hubbub->funcs->verify_allow_pstate_change_high)
+ return;
+
+ if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) {
int i = 0;
if (should_log_hw_state)
@@ -1123,8 +1127,8 @@ void dcn10_verify_allow_pstate_change_high(struct dc *dc)
TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES);
BREAK_TO_DEBUGGER();
if (dcn10_hw_wa_force_recovery(dc)) {
- /*check again*/
- if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub))
+ /*check again*/
+ if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub))
BREAK_TO_DEBUGGER();
}
}
@@ -1255,6 +1259,7 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
{
int i;
struct dce_hwseq *hws = dc->hwseq;
+ struct hubbub *hubbub = dc->res_pool->hubbub;
bool can_apply_seamless_boot = false;
for (i = 0; i < context->stream_count; i++) {
@@ -1290,6 +1295,21 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
}
}
+ /* Reset det size */
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+ struct hubp *hubp = dc->res_pool->hubps[i];
+
+ /* Do not need to reset for seamless boot */
+ if (pipe_ctx->stream != NULL && can_apply_seamless_boot)
+ continue;
+
+ if (hubbub && hubp) {
+ if (hubbub->funcs->program_det_size)
+ hubbub->funcs->program_det_size(hubbub, hubp->inst, 0);
+ }
+ }
+
/* num_opp will be equal to number of mpcc */
for (i = 0; i < dc->res_pool->res_cap->num_opp; i++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
@@ -1355,6 +1375,11 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
pipe_ctx->stream_res.tg = NULL;
pipe_ctx->plane_res.hubp = NULL;
+ if (tg->funcs->is_tg_enabled(tg)) {
+ if (tg->funcs->init_odm)
+ tg->funcs->init_odm(tg);
+ }
+
tg->funcs->tg_init(tg);
}
@@ -1489,24 +1514,19 @@ void dcn10_init_hw(struct dc *dc)
/* Check for enabled DIG to identify enabled display */
if (link->link_enc->funcs->is_dig_enabled &&
- link->link_enc->funcs->is_dig_enabled(link->link_enc))
+ link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
link->link_status.link_active = true;
+ if (link->link_enc->funcs->fec_is_active &&
+ link->link_enc->funcs->fec_is_active(link->link_enc))
+ link->fec_state = dc_link_fec_enabled;
+ }
}
- /* Power gate DSCs */
- if (!is_optimized_init_done) {
- for (i = 0; i < res_pool->res_cap->num_dsc; i++)
- if (hws->funcs.dsc_pg_control != NULL)
- hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
- }
-
- /* Enable outbox notification feature of dmub */
- if (dc->debug.enable_dmub_aux_for_legacy_ddc)
- dmub_enable_outbox_notification(dc);
-
/* we want to turn off all dp displays before doing detection */
- if (dc->config.power_down_display_on_boot)
- dc_link_blank_all_dp_displays(dc);
+ dc_link_blank_all_dp_displays(dc);
+
+ if (hws->funcs.enable_power_gating_plane)
+ hws->funcs.enable_power_gating_plane(dc->hwseq, true);
/* If taking control over from VBIOS, we may want to optimize our first
* mode set, so we need to skip powering down pipes until we know which
@@ -1514,7 +1534,7 @@ void dcn10_init_hw(struct dc *dc)
* Otherwise, if taking control is not possible, we need to power
* everything down.
*/
- if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) {
+ if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
if (!is_optimized_init_done) {
hws->funcs.init_pipes(dc, dc->current_state);
if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
@@ -1560,8 +1580,6 @@ void dcn10_init_hw(struct dc *dc)
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
}
- if (hws->funcs.enable_power_gating_plane)
- hws->funcs.enable_power_gating_plane(dc->hwseq, true);
if (dc->clk_mgr->funcs->notify_wm_ranges)
dc->clk_mgr->funcs->notify_wm_ranges(dc->clk_mgr);
@@ -2057,7 +2075,7 @@ static int dcn10_align_pixel_clocks(struct dc *dc, int group_size,
{
struct dc_context *dc_ctx = dc->ctx;
int i, master = -1, embedded = -1;
- struct dc_crtc_timing hw_crtc_timing[MAX_PIPES] = {0};
+ struct dc_crtc_timing *hw_crtc_timing;
uint64_t phase[MAX_PIPES];
uint64_t modulo[MAX_PIPES];
unsigned int pclk;
@@ -2065,14 +2083,15 @@ static int dcn10_align_pixel_clocks(struct dc *dc, int group_size,
uint32_t embedded_pix_clk_100hz;
uint16_t embedded_h_total;
uint16_t embedded_v_total;
- bool clamshell_closed = false;
uint32_t dp_ref_clk_100hz =
dc->res_pool->dp_clock_source->ctx->dc->clk_mgr->dprefclk_khz*10;
+ hw_crtc_timing = kcalloc(MAX_PIPES, sizeof(*hw_crtc_timing), GFP_KERNEL);
+ if (!hw_crtc_timing)
+ return master;
+
if (dc->config.vblank_alignment_dto_params &&
dc->res_pool->dp_clock_source->funcs->override_dp_pix_clk) {
- clamshell_closed =
- (dc->config.vblank_alignment_dto_params >> 63);
embedded_h_total =
(dc->config.vblank_alignment_dto_params >> 32) & 0x7FFF;
embedded_v_total =
@@ -2134,6 +2153,8 @@ static int dcn10_align_pixel_clocks(struct dc *dc, int group_size,
}
}
+
+ kfree(hw_crtc_timing);
return master;
}
@@ -2526,27 +2547,32 @@ void dcn10_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
struct mpc *mpc = dc->res_pool->mpc;
struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
- if (per_pixel_alpha)
- blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
- else
- blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
-
blnd_cfg.overlap_only = false;
blnd_cfg.global_gain = 0xff;
+ if (per_pixel_alpha) {
+ /* DCN1.0 has output CM before MPC which seems to screw with
+ * pre-multiplied alpha.
+ */
+ blnd_cfg.pre_multiplied_alpha = (is_rgb_cspace(
+ pipe_ctx->stream->output_color_space)
+ && pipe_ctx->plane_state->pre_multiplied_alpha);
+ if (pipe_ctx->plane_state->global_alpha) {
+ blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
+ blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
+ } else {
+ blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
+ }
+ } else {
+ blnd_cfg.pre_multiplied_alpha = false;
+ blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
+ }
+
if (pipe_ctx->plane_state->global_alpha)
blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
else
blnd_cfg.global_alpha = 0xff;
- /* DCN1.0 has output CM before MPC which seems to screw with
- * pre-multiplied alpha.
- */
- blnd_cfg.pre_multiplied_alpha = is_rgb_cspace(
- pipe_ctx->stream->output_color_space)
- && per_pixel_alpha;
-
-
/*
* TODO: remove hack
* Note: currently there is a bug in init_hw such that
@@ -2983,8 +3009,11 @@ void dcn10_prepare_bandwidth(
true);
dcn10_stereo_hw_frame_pack_wa(dc, context);
- if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
+ if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) {
+ DC_FP_START();
dcn_bw_notify_pplib_of_wm_ranges(dc);
+ DC_FP_END();
+ }
if (dc->debug.sanity_checks)
hws->funcs.verify_allow_pstate_change_high(dc);
@@ -3017,8 +3046,11 @@ void dcn10_optimize_bandwidth(
dcn10_stereo_hw_frame_pack_wa(dc, context);
- if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE)
+ if (dc->debug.pplib_wm_report_mode == WM_REPORT_OVERRIDE) {
+ DC_FP_START();
dcn_bw_notify_pplib_of_wm_ranges(dc);
+ DC_FP_END();
+ }
if (dc->debug.sanity_checks)
hws->funcs.verify_allow_pstate_change_high(dc);
@@ -3043,12 +3075,16 @@ void dcn10_set_drr(struct pipe_ctx **pipe_ctx,
* as well.
*/
for (i = 0; i < num_pipes; i++) {
- pipe_ctx[i]->stream_res.tg->funcs->set_drr(
- pipe_ctx[i]->stream_res.tg, &params);
- if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
- pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
- pipe_ctx[i]->stream_res.tg,
- event_triggers, num_frames);
+ if ((pipe_ctx[i]->stream_res.tg != NULL) && pipe_ctx[i]->stream_res.tg->funcs) {
+ if (pipe_ctx[i]->stream_res.tg->funcs->set_drr)
+ pipe_ctx[i]->stream_res.tg->funcs->set_drr(
+ pipe_ctx[i]->stream_res.tg, &params);
+ if (adjust.v_total_max != 0 && adjust.v_total_min != 0)
+ if (pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control)
+ pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
+ pipe_ctx[i]->stream_res.tg,
+ event_triggers, num_frames);
+ }
}
}
@@ -3101,7 +3137,8 @@ static void dcn10_config_stereo_parameters(
flags->PROGRAM_STEREO = 1;
flags->PROGRAM_POLARITY = 1;
- if (timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
+ if (timing_3d_format == TIMING_3D_FORMAT_FRAME_ALTERNATE ||
+ timing_3d_format == TIMING_3D_FORMAT_INBAND_FA ||
timing_3d_format == TIMING_3D_FORMAT_DP_HDMI_INBAND_FA ||
timing_3d_format == TIMING_3D_FORMAT_SIDEBAND_FA) {
enum display_dongle_type dongle = \
@@ -3178,7 +3215,8 @@ void dcn10_wait_for_mpcc_disconnect(
if (pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst]) {
struct hubp *hubp = get_hubp_by_inst(res_pool, mpcc_inst);
- res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst);
+ if (pipe_ctx->stream_res.tg->funcs->is_tg_enabled(pipe_ctx->stream_res.tg))
+ res_pool->mpc->funcs->wait_for_idle(res_pool->mpc, mpcc_inst);
pipe_ctx->stream_res.opp->mpcc_disconnect_pending[mpcc_inst] = false;
hubp->funcs->set_blank(hubp, true);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
index f4b34c110eae..ca39361f71c8 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.c
@@ -1101,7 +1101,8 @@ void dcn10_link_encoder_disable_output(
void dcn10_link_encoder_dp_set_lane_settings(
struct link_encoder *enc,
- const struct link_training_settings *link_settings)
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
{
struct dcn10_link_encoder *enc10 = TO_DCN10_LINK_ENC(enc);
union dpcd_training_lane_set training_lane_set = { { 0 } };
@@ -1116,26 +1117,25 @@ void dcn10_link_encoder_dp_set_lane_settings(
cntl.action = TRANSMITTER_CONTROL_SET_VOLTAGE_AND_PREEMPASIS;
cntl.transmitter = enc10->base.transmitter;
cntl.connector_obj_id = enc10->base.connector;
- cntl.lanes_number = link_settings->link_settings.lane_count;
+ cntl.lanes_number = link_settings->lane_count;
cntl.hpd_sel = enc10->base.hpd_source;
- cntl.pixel_clock = link_settings->link_settings.link_rate *
- LINK_RATE_REF_FREQ_IN_KHZ;
+ cntl.pixel_clock = link_settings->link_rate * LINK_RATE_REF_FREQ_IN_KHZ;
- for (lane = 0; lane < link_settings->link_settings.lane_count; lane++) {
+ for (lane = 0; lane < link_settings->lane_count; lane++) {
/* translate lane settings */
training_lane_set.bits.VOLTAGE_SWING_SET =
- link_settings->lane_settings[lane].VOLTAGE_SWING;
+ lane_settings[lane].VOLTAGE_SWING;
training_lane_set.bits.PRE_EMPHASIS_SET =
- link_settings->lane_settings[lane].PRE_EMPHASIS;
+ lane_settings[lane].PRE_EMPHASIS;
/* post cursor 2 setting only applies to HBR2 link rate */
- if (link_settings->link_settings.link_rate == LINK_RATE_HIGH2) {
+ if (link_settings->link_rate == LINK_RATE_HIGH2) {
/* this is passed to VBIOS
* to program post cursor 2 level
*/
training_lane_set.bits.POST_CURSOR2_SET =
- link_settings->lane_settings[lane].POST_CURSOR2;
+ lane_settings[lane].POST_CURSOR2;
}
cntl.lane_select = lane;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h
index c337588231ff..663aac0a164a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_link_encoder.h
@@ -581,7 +581,8 @@ void dcn10_link_encoder_disable_output(
/* set DP lane settings */
void dcn10_link_encoder_dp_set_lane_settings(
struct link_encoder *enc,
- const struct link_training_settings *link_settings);
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
void dcn10_link_encoder_dp_set_phy_pattern(
struct link_encoder *enc,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
index 858b72149897..bca049b2f867 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
@@ -70,68 +70,6 @@
#include "dce/dce_aux.h"
#include "dce/dce_i2c.h"
-const struct _vcs_dpi_ip_params_st dcn1_0_ip = {
- .rob_buffer_size_kbytes = 64,
- .det_buffer_size_kbytes = 164,
- .dpte_buffer_size_in_pte_reqs_luma = 42,
- .dpp_output_buffer_pixels = 2560,
- .opp_output_buffer_lines = 1,
- .pixel_chunk_size_kbytes = 8,
- .pte_enable = 1,
- .pte_chunk_size_kbytes = 2,
- .meta_chunk_size_kbytes = 2,
- .writeback_chunk_size_kbytes = 2,
- .line_buffer_size_bits = 589824,
- .max_line_buffer_lines = 12,
- .IsLineBufferBppFixed = 0,
- .LineBufferFixedBpp = -1,
- .writeback_luma_buffer_size_kbytes = 12,
- .writeback_chroma_buffer_size_kbytes = 8,
- .max_num_dpp = 4,
- .max_num_wb = 2,
- .max_dchub_pscl_bw_pix_per_clk = 4,
- .max_pscl_lb_bw_pix_per_clk = 2,
- .max_lb_vscl_bw_pix_per_clk = 4,
- .max_vscl_hscl_bw_pix_per_clk = 4,
- .max_hscl_ratio = 4,
- .max_vscl_ratio = 4,
- .hscl_mults = 4,
- .vscl_mults = 4,
- .max_hscl_taps = 8,
- .max_vscl_taps = 8,
- .dispclk_ramp_margin_percent = 1,
- .underscan_factor = 1.10,
- .min_vblank_lines = 14,
- .dppclk_delay_subtotal = 90,
- .dispclk_delay_subtotal = 42,
- .dcfclk_cstate_latency = 10,
- .max_inter_dcn_tile_repeaters = 8,
- .can_vstartup_lines_exceed_vsync_plus_back_porch_lines_minus_one = 0,
- .bug_forcing_LC_req_same_size_fixed = 0,
-};
-
-const struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = {
- .sr_exit_time_us = 9.0,
- .sr_enter_plus_exit_time_us = 11.0,
- .urgent_latency_us = 4.0,
- .writeback_latency_us = 12.0,
- .ideal_dram_bw_after_urgent_percent = 80.0,
- .max_request_size_bytes = 256,
- .downspread_percent = 0.5,
- .dram_page_open_time_ns = 50.0,
- .dram_rw_turnaround_time_ns = 17.5,
- .dram_return_buffer_per_channel_bytes = 8192,
- .round_trip_ping_latency_dcfclk_cycles = 128,
- .urgent_out_of_order_return_per_channel_bytes = 256,
- .channel_interleave_bytes = 256,
- .num_banks = 8,
- .num_chans = 2,
- .vmm_page_size_bytes = 4096,
- .dram_clock_change_latency_us = 17.0,
- .writeback_dram_clock_change_latency_us = 23.0,
- .return_bus_width_bytes = 64,
-};
-
#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL
#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f
#define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2
@@ -925,6 +863,21 @@ static struct dce_hwseq *dcn10_hwseq_create(
hws->wa.DEGVIDCN10_253 = true;
hws->wa.false_optc_underflow = true;
hws->wa.DEGVIDCN10_254 = true;
+
+ if ((ctx->asic_id.chip_family == FAMILY_RV) &&
+ ASICREV_IS_RAVEN2(ctx->asic_id.hw_internal_rev))
+ switch (ctx->asic_id.pci_revision_id) {
+ case PRID_POLLOCK_94:
+ case PRID_POLLOCK_95:
+ case PRID_POLLOCK_E9:
+ case PRID_POLLOCK_EA:
+ case PRID_POLLOCK_EB:
+ hws->wa.wait_hubpret_read_start_during_mpo_transition = true;
+ break;
+ default:
+ hws->wa.wait_hubpret_read_start_during_mpo_transition = false;
+ break;
+ }
}
return hws;
}
@@ -1188,6 +1141,20 @@ static void dcn10_destroy_resource_pool(struct resource_pool **pool)
*pool = NULL;
}
+static bool dcn10_validate_bandwidth(
+ struct dc *dc,
+ struct dc_state *context,
+ bool fast_validate)
+{
+ bool voltage_supported;
+
+ DC_FP_START();
+ voltage_supported = dcn_validate_bandwidth(dc, context, fast_validate);
+ DC_FP_END();
+
+ return voltage_supported;
+}
+
static enum dc_status dcn10_validate_plane(const struct dc_plane_state *plane_state, struct dc_caps *caps)
{
if (plane_state->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN
@@ -1539,6 +1506,7 @@ static bool dcn10_resource_construct(
&& pool->base.pp_smu->rv_funcs.set_pme_wa_enable != NULL)
dc->debug.az_endpoint_mute_only = false;
+ DC_FP_START();
if (!dc->debug.disable_pplib_clock_request)
dcn_bw_update_from_pplib(dc);
dcn_bw_sync_calcs_and_dml(dc);
@@ -1546,6 +1514,7 @@ static bool dcn10_resource_construct(
dc->res_pool = &pool->base;
dcn_bw_notify_pplib_of_wm_ranges(dc);
}
+ DC_FP_END();
{
struct irq_service_init_data init_data;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h
index 633025ccb870..bf8e33cd8147 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.h
@@ -27,6 +27,7 @@
#define __DC_RESOURCE_DCN10_H__
#include "core_types.h"
+#include "dml/dcn10/dcn10_fpu.h"
#define TO_DCN10_RES_POOL(pool)\
container_of(pool, struct dcn10_resource_pool, base)
@@ -35,6 +36,9 @@ struct dc;
struct resource_pool;
struct _vcs_dpi_display_pipe_params_st;
+extern struct _vcs_dpi_ip_params_st dcn1_0_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc;
+
struct dcn10_resource_pool {
struct resource_pool base;
};
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
index b0c08ee6bc2c..7608187751c8 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
+#include "dm_services.h"
#include "dc_bios_types.h"
#include "dcn10_stream_encoder.h"
#include "reg_helper.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
index 687d7e4bf7ca..293595a33982 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_stream_encoder.h
@@ -92,6 +92,8 @@
SRI(DP_VID_STREAM_CNTL, DP, id), \
SRI(DP_VID_TIMING, DP, id), \
SRI(DP_SEC_AUD_N, DP, id), \
+ SRI(DP_SEC_AUD_N_READBACK, DP, id), \
+ SRI(DP_SEC_AUD_M_READBACK, DP, id), \
SRI(DP_SEC_TIMESTAMP, DP, id), \
SRI(DIG_CLOCK_PATTERN, DIG, id)
@@ -140,6 +142,8 @@ struct dcn10_stream_enc_registers {
uint32_t DP_VID_STREAM_CNTL;
uint32_t DP_VID_TIMING;
uint32_t DP_SEC_AUD_N;
+ uint32_t DP_SEC_AUD_N_READBACK;
+ uint32_t DP_SEC_AUD_M_READBACK;
uint32_t DP_SEC_TIMESTAMP;
uint32_t HDMI_CONTROL;
uint32_t HDMI_GC;
@@ -256,6 +260,8 @@ struct dcn10_stream_enc_registers {
SE_SF(DIG0_AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_6, mask_sh),\
SE_SF(DIG0_AFMT_60958_2, AFMT_60958_CS_CHANNEL_NUMBER_7, mask_sh),\
SE_SF(DP0_DP_SEC_AUD_N, DP_SEC_AUD_N, mask_sh),\
+ SE_SF(DP0_DP_SEC_AUD_N_READBACK, DP_SEC_AUD_N_READBACK, mask_sh),\
+ SE_SF(DP0_DP_SEC_AUD_M_READBACK, DP_SEC_AUD_M_READBACK, mask_sh),\
SE_SF(DP0_DP_SEC_TIMESTAMP, DP_SEC_TIMESTAMP_MODE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ASP_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ATP_ENABLE, mask_sh),\
@@ -473,6 +479,8 @@ struct dcn10_stream_enc_registers {
type AFMT_60958_CS_CHANNEL_NUMBER_6;\
type AFMT_60958_CS_CHANNEL_NUMBER_7;\
type DP_SEC_AUD_N;\
+ type DP_SEC_AUD_N_READBACK;\
+ type DP_SEC_AUD_M_READBACK;\
type DP_SEC_TIMESTAMP_MODE;\
type DP_SEC_ASP_ENABLE;\
type DP_SEC_ATP_ENABLE;\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile
index 5fcaf78334ff..abaed2121feb 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/Makefile
@@ -9,31 +9,6 @@ DCN20 = dcn20_resource.o dcn20_init.o dcn20_hwseq.o dcn20_dpp.o dcn20_dpp_cm.o d
DCN20 += dcn20_dsc.o
-ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mhard-float -msse
-endif
-
-ifdef CONFIG_PPC64
-CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o += -mpreferred-stack-boundary=4
-else
-CFLAGS_$(AMDDALPATH)/dc/dcn20/dcn20_resource.o += -msse2
-endif
-endif
-
AMD_DAL_DCN20 = $(addprefix $(AMDDALPATH)/dc/dcn20/,$(DCN20))
AMD_DISPLAY_FILES += $(AMD_DAL_DCN20)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h
index f98aba308028..b3c9a9724efd 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dccg.h
@@ -183,15 +183,25 @@
type SYMCLK32_ROOT_SE1_GATE_DISABLE;\
type SYMCLK32_ROOT_SE2_GATE_DISABLE;\
type SYMCLK32_ROOT_SE3_GATE_DISABLE;\
+ type SYMCLK32_SE0_GATE_DISABLE;\
+ type SYMCLK32_SE1_GATE_DISABLE;\
+ type SYMCLK32_SE2_GATE_DISABLE;\
+ type SYMCLK32_SE3_GATE_DISABLE;\
type SYMCLK32_ROOT_LE0_GATE_DISABLE;\
type SYMCLK32_ROOT_LE1_GATE_DISABLE;\
+ type SYMCLK32_LE0_GATE_DISABLE;\
+ type SYMCLK32_LE1_GATE_DISABLE;\
type DPSTREAMCLK_ROOT_GATE_DISABLE;\
type DPSTREAMCLK_GATE_DISABLE;\
type HDMISTREAMCLK0_DTO_PHASE;\
type HDMISTREAMCLK0_DTO_MODULO;\
type HDMICHARCLK0_GATE_DISABLE;\
- type HDMICHARCLK0_ROOT_GATE_DISABLE;
-
+ type HDMICHARCLK0_ROOT_GATE_DISABLE; \
+ type PHYASYMCLK_GATE_DISABLE; \
+ type PHYBSYMCLK_GATE_DISABLE; \
+ type PHYCSYMCLK_GATE_DISABLE; \
+ type PHYDSYMCLK_GATE_DISABLE; \
+ type PHYESYMCLK_GATE_DISABLE;
struct dccg_shift {
DCCG_REG_FIELD_LIST(uint8_t)
@@ -233,6 +243,7 @@ struct dccg_registers {
uint32_t DSCCLK2_DTO_PARAM;
uint32_t DPSTREAMCLK_ROOT_GATE_DISABLE;
uint32_t DPSTREAMCLK_GATE_DISABLE;
+ uint32_t DCCG_GATE_DISABLE_CNTL2;
uint32_t DCCG_GATE_DISABLE_CNTL3;
uint32_t HDMISTREAMCLK0_DTO_PARAM;
uint32_t DCCG_GATE_DISABLE_CNTL4;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c
index 970b65efeac1..eaa7032f0f1a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dpp.c
@@ -212,6 +212,9 @@ static void dpp2_cnv_setup (
break;
}
+ /* Set default color space based on format if none is given. */
+ color_space = input_color_space ? input_color_space : color_space;
+
if (is_2bit == 1 && alpha_2bit_lut != NULL) {
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT0, alpha_2bit_lut->lut0);
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT1, alpha_2bit_lut->lut1);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
index ef5c4c0f4d6c..136a9dc062bc 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
@@ -23,6 +23,8 @@
*
*/
+#include <drm/display/drm_dsc_helper.h>
+
#include "reg_helper.h"
#include "dcn20_dsc.h"
#include "dsc/dscc_types.h"
@@ -45,6 +47,7 @@ static void dsc2_set_config(struct display_stream_compressor *dsc, const struct
static bool dsc2_get_packed_pps(struct display_stream_compressor *dsc, const struct dsc_config *dsc_cfg, uint8_t *dsc_packed_pps);
static void dsc2_enable(struct display_stream_compressor *dsc, int opp_pipe);
static void dsc2_disable(struct display_stream_compressor *dsc);
+static void dsc2_disconnect(struct display_stream_compressor *dsc);
const struct dsc_funcs dcn20_dsc_funcs = {
.dsc_get_enc_caps = dsc2_get_enc_caps,
@@ -54,6 +57,7 @@ const struct dsc_funcs dcn20_dsc_funcs = {
.dsc_get_packed_pps = dsc2_get_packed_pps,
.dsc_enable = dsc2_enable,
.dsc_disable = dsc2_disable,
+ .dsc_disconnect = dsc2_disconnect,
};
/* Macro definitios for REG_SET macros*/
@@ -276,6 +280,15 @@ static void dsc2_disable(struct display_stream_compressor *dsc)
DSC_CLOCK_EN, 0);
}
+static void dsc2_disconnect(struct display_stream_compressor *dsc)
+{
+ struct dcn20_dsc *dsc20 = TO_DCN20_DSC(dsc);
+
+ DC_LOG_DSC("disconnect DSC %d", dsc->inst);
+
+ REG_UPDATE(DSCRM_DSC_FORWARD_CONFIG,
+ DSCRM_DSC_FORWARD_EN, 0);
+}
/* This module's internal functions */
static void dsc_log_pps(struct display_stream_compressor *dsc, struct drm_dsc_config *pps)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h
index 1118e33aaa2c..c21ecedc4692 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.h
@@ -26,7 +26,7 @@
#include "dsc.h"
#include "dsc/dscc_types.h"
-#include <drm/drm_dsc.h>
+#include <drm/display/drm_dsc.h>
#define TO_DCN20_DSC(dsc)\
container_of(dsc, struct dcn20_dsc, base)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
index dc1752e9f461..a665af19f201 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hubp.c
@@ -707,17 +707,6 @@ bool hubp2_program_surface_flip_and_addr(
REG_UPDATE(VMID_SETTINGS_0,
VMID, address->vmid);
- if (address->type == PLN_ADDR_TYPE_GRPH_STEREO) {
- REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, 0x1);
- REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, 0x1);
-
- } else {
- // turn off stereo if not in stereo
- REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_MODE_FOR_STEREOSYNC, 0x0);
- REG_UPDATE(DCSURF_FLIP_CONTROL, SURFACE_FLIP_IN_STEREOSYNC, 0x0);
- }
-
-
/* HW automatically latch rest of address register on write to
* DCSURF_PRIMARY_SURFACE_ADDRESS if SURFACE_UPDATE_LOCK is not used
@@ -942,10 +931,6 @@ void hubp2_set_blank_regs(struct hubp *hubp, bool blank)
struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
uint32_t blank_en = blank ? 1 : 0;
- REG_UPDATE_2(DCHUBP_CNTL,
- HUBP_BLANK_EN, blank_en,
- HUBP_TTU_DISABLE, blank_en);
-
if (blank) {
uint32_t reg_val = REG_READ(DCHUBP_CNTL);
@@ -958,9 +943,13 @@ void hubp2_set_blank_regs(struct hubp *hubp, bool blank)
*/
REG_WAIT(DCHUBP_CNTL,
HUBP_NO_OUTSTANDING_REQ, 1,
- 1, 200);
+ 1, 100000);
}
}
+
+ REG_UPDATE_2(DCHUBP_CNTL,
+ HUBP_BLANK_EN, blank_en,
+ HUBP_TTU_DISABLE, 0);
}
void hubp2_cursor_set_position(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
index 4991e93e5308..ec6aa8d8b251 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
@@ -55,6 +55,7 @@
#include "inc/link_dpcd.h"
#include "dpcd_defs.h"
#include "inc/link_enc_cfg.h"
+#include "link_hwss.h"
#define DC_LOGGER_INIT(logger)
@@ -1592,7 +1593,6 @@ static void dcn20_program_pipe(
pipe_ctx->pipe_dlg_param.vupdate_offset,
pipe_ctx->pipe_dlg_param.vupdate_width);
- pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VBLANK);
pipe_ctx->stream_res.tg->funcs->wait_for_state(pipe_ctx->stream_res.tg, CRTC_STATE_VACTIVE);
pipe_ctx->stream_res.tg->funcs->set_vtg_params(
@@ -1738,6 +1738,16 @@ void dcn20_program_front_end_for_ctx(
|| pipe->stream->update_flags.raw)
&& hws->funcs.program_all_writeback_pipes_in_tree)
hws->funcs.program_all_writeback_pipes_in_tree(dc, pipe->stream, context);
+
+ /* Avoid underflow by check of pipe line read when adding 2nd plane. */
+ if (hws->wa.wait_hubpret_read_start_during_mpo_transition &&
+ !pipe->top_pipe &&
+ pipe->stream &&
+ pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start &&
+ dc->current_state->stream_status[0].plane_count == 1 &&
+ context->stream_status[0].plane_count > 1) {
+ pipe->plane_res.hubp->funcs->hubp_wait_pipe_read_start(pipe->plane_res.hubp);
+ }
}
}
@@ -1763,7 +1773,6 @@ void dcn20_post_unlock_program_front_end(
*/
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-
if (pipe->plane_state && !pipe->top_pipe && pipe->update_flags.bits.enable) {
struct hubp *hubp = pipe->plane_res.hubp;
int j = 0;
@@ -1817,6 +1826,7 @@ void dcn20_prepare_bandwidth(
struct dc_state *context)
{
struct hubbub *hubbub = dc->res_pool->hubbub;
+ unsigned int compbuf_size_kb = 0;
dc->clk_mgr->funcs->update_clocks(
dc->clk_mgr,
@@ -1828,9 +1838,16 @@ void dcn20_prepare_bandwidth(
&context->bw_ctx.bw.dcn.watermarks,
dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000,
false);
+
/* decrease compbuf size */
- if (hubbub->funcs->program_compbuf_size)
- hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, false);
+ if (hubbub->funcs->program_compbuf_size) {
+ if (context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes)
+ compbuf_size_kb = context->bw_ctx.dml.ip.min_comp_buffer_size_kbytes;
+ else
+ compbuf_size_kb = context->bw_ctx.bw.dcn.compbuf_size_kb;
+
+ hubbub->funcs->program_compbuf_size(hubbub, compbuf_size_kb, false);
+ }
}
void dcn20_optimize_bandwidth(
@@ -1838,6 +1855,7 @@ void dcn20_optimize_bandwidth(
struct dc_state *context)
{
struct hubbub *hubbub = dc->res_pool->hubbub;
+ int i;
/* program dchubbub watermarks */
hubbub->funcs->program_watermarks(hubbub,
@@ -1854,6 +1872,17 @@ void dcn20_optimize_bandwidth(
dc->clk_mgr,
context,
true);
+ if (dc_extended_blank_supported(dc) && context->bw_ctx.bw.dcn.clk.zstate_support == DCN_ZSTATE_SUPPORT_ALLOW) {
+ for (i = 0; i < dc->res_pool->pipe_count; ++i) {
+ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
+
+ if (pipe_ctx->stream && pipe_ctx->plane_res.hubp->funcs->program_extended_blank
+ && pipe_ctx->stream->adjust.v_total_min == pipe_ctx->stream->adjust.v_total_max
+ && pipe_ctx->stream->adjust.v_total_max > pipe_ctx->stream->timing.v_total)
+ pipe_ctx->plane_res.hubp->funcs->program_extended_blank(pipe_ctx->plane_res.hubp,
+ pipe_ctx->dlg_regs.optimized_min_dst_y_next_start);
+ }
+ }
/* increase compbuf size */
if (hubbub->funcs->program_compbuf_size)
hubbub->funcs->program_compbuf_size(hubbub, context->bw_ctx.bw.dcn.compbuf_size_kb, true);
@@ -2313,14 +2342,22 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
struct mpc *mpc = dc->res_pool->mpc;
struct mpc_tree *mpc_tree_params = &(pipe_ctx->stream_res.opp->mpc_tree_params);
- if (per_pixel_alpha)
- blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
- else
- blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
-
blnd_cfg.overlap_only = false;
blnd_cfg.global_gain = 0xff;
+ if (per_pixel_alpha) {
+ blnd_cfg.pre_multiplied_alpha = pipe_ctx->plane_state->pre_multiplied_alpha;
+ if (pipe_ctx->plane_state->global_alpha) {
+ blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA_COMBINED_GLOBAL_GAIN;
+ blnd_cfg.global_gain = pipe_ctx->plane_state->global_alpha_value;
+ } else {
+ blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_PER_PIXEL_ALPHA;
+ }
+ } else {
+ blnd_cfg.pre_multiplied_alpha = false;
+ blnd_cfg.alpha_mode = MPCC_ALPHA_BLEND_MODE_GLOBAL_ALPHA;
+ }
+
if (pipe_ctx->plane_state->global_alpha)
blnd_cfg.global_alpha = pipe_ctx->plane_state->global_alpha_value;
else
@@ -2331,7 +2368,7 @@ void dcn20_update_mpcc(struct dc *dc, struct pipe_ctx *pipe_ctx)
blnd_cfg.top_gain = 0x1f000;
blnd_cfg.bottom_inside_gain = 0x1f000;
blnd_cfg.bottom_outside_gain = 0x1f000;
- blnd_cfg.pre_multiplied_alpha = per_pixel_alpha;
+
if (pipe_ctx->plane_state->format
== SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA)
blnd_cfg.pre_multiplied_alpha = false;
@@ -2390,46 +2427,22 @@ void dcn20_enable_stream(struct pipe_ctx *pipe_ctx)
uint32_t active_total_with_borders;
uint32_t early_control = 0;
struct timing_generator *tg = pipe_ctx->stream_res.tg;
- struct link_encoder *link_enc;
-
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign)
- link_enc = link_enc_cfg_get_link_enc_used_by_stream(link->ctx->dc, pipe_ctx->stream);
- else
- link_enc = link->link_enc;
- ASSERT(link_enc);
+ const struct link_hwss *link_hwss = get_link_hwss(link, &pipe_ctx->link_res);
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
- /* For MST, there are multiply stream go to only one link.
- * connect DIG back_end to front_end while enable_stream and
- * disconnect them during disable_stream
- * BY this, it is logic clean to separate stream and link
- */
if (is_dp_128b_132b_signal(pipe_ctx)) {
- if (pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control)
- pipe_ctx->stream->ctx->dc->hwseq->funcs.setup_hpo_hw_control(
- pipe_ctx->stream->ctx->dc->hwseq, true);
- setup_dp_hpo_stream(pipe_ctx, true);
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->enable_stream(
- pipe_ctx->stream_res.hpo_dp_stream_enc);
- pipe_ctx->stream_res.hpo_dp_stream_enc->funcs->map_stream_to_link(
- pipe_ctx->stream_res.hpo_dp_stream_enc,
- pipe_ctx->stream_res.hpo_dp_stream_enc->inst,
- pipe_ctx->link_res.hpo_dp_link_enc->inst);
+ if (dc->hwseq->funcs.setup_hpo_hw_control)
+ dc->hwseq->funcs.setup_hpo_hw_control(dc->hwseq, true);
}
- if (!is_dp_128b_132b_signal(pipe_ctx) && link_enc)
- link_enc->funcs->connect_dig_be_to_fe(
- link_enc, pipe_ctx->stream_res.stream_enc->id, true);
-
- if (dc_is_dp_signal(pipe_ctx->stream->signal))
- dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
+ link_hwss->setup_stream_encoder(pipe_ctx);
if (pipe_ctx->plane_state && pipe_ctx->plane_state->flip_immediate != 1) {
- if (link->dc->hwss.program_dmdata_engine)
- link->dc->hwss.program_dmdata_engine(pipe_ctx);
+ if (dc->hwss.program_dmdata_engine)
+ dc->hwss.program_dmdata_engine(pipe_ctx);
}
- link->dc->hwss.update_info_frame(pipe_ctx);
+ dc->hwss.update_info_frame(pipe_ctx);
if (dc_is_dp_signal(pipe_ctx->stream->signal))
dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_UPDATE_INFO_FRAME);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
index 2a72517e2b28..7802d603f796 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
@@ -63,7 +63,6 @@
#include "dcn20_dccg.h"
#include "dcn20_vmid.h"
#include "dc_link_ddc.h"
-#include "dc_link_dp.h"
#include "dce/dce_panel_cntl.h"
#include "navi10_ip_offset.h"
@@ -93,367 +92,6 @@
#define DC_LOGGER_INIT(logger)
-struct _vcs_dpi_ip_params_st dcn2_0_ip = {
- .odm_capable = 1,
- .gpuvm_enable = 0,
- .hostvm_enable = 0,
- .gpuvm_max_page_table_levels = 4,
- .hostvm_max_page_table_levels = 4,
- .hostvm_cached_page_table_levels = 0,
- .pte_group_size_bytes = 2048,
- .num_dsc = 6,
- .rob_buffer_size_kbytes = 168,
- .det_buffer_size_kbytes = 164,
- .dpte_buffer_size_in_pte_reqs_luma = 84,
- .pde_proc_buffer_size_64k_reqs = 48,
- .dpp_output_buffer_pixels = 2560,
- .opp_output_buffer_lines = 1,
- .pixel_chunk_size_kbytes = 8,
- .pte_chunk_size_kbytes = 2,
- .meta_chunk_size_kbytes = 2,
- .writeback_chunk_size_kbytes = 2,
- .line_buffer_size_bits = 789504,
- .is_line_buffer_bpp_fixed = 0,
- .line_buffer_fixed_bpp = 0,
- .dcc_supported = true,
- .max_line_buffer_lines = 12,
- .writeback_luma_buffer_size_kbytes = 12,
- .writeback_chroma_buffer_size_kbytes = 8,
- .writeback_chroma_line_buffer_width_pixels = 4,
- .writeback_max_hscl_ratio = 1,
- .writeback_max_vscl_ratio = 1,
- .writeback_min_hscl_ratio = 1,
- .writeback_min_vscl_ratio = 1,
- .writeback_max_hscl_taps = 12,
- .writeback_max_vscl_taps = 12,
- .writeback_line_buffer_luma_buffer_size = 0,
- .writeback_line_buffer_chroma_buffer_size = 14643,
- .cursor_buffer_size = 8,
- .cursor_chunk_size = 2,
- .max_num_otg = 6,
- .max_num_dpp = 6,
- .max_num_wb = 1,
- .max_dchub_pscl_bw_pix_per_clk = 4,
- .max_pscl_lb_bw_pix_per_clk = 2,
- .max_lb_vscl_bw_pix_per_clk = 4,
- .max_vscl_hscl_bw_pix_per_clk = 4,
- .max_hscl_ratio = 8,
- .max_vscl_ratio = 8,
- .hscl_mults = 4,
- .vscl_mults = 4,
- .max_hscl_taps = 8,
- .max_vscl_taps = 8,
- .dispclk_ramp_margin_percent = 1,
- .underscan_factor = 1.10,
- .min_vblank_lines = 32, //
- .dppclk_delay_subtotal = 77, //
- .dppclk_delay_scl_lb_only = 16,
- .dppclk_delay_scl = 50,
- .dppclk_delay_cnvc_formatter = 8,
- .dppclk_delay_cnvc_cursor = 6,
- .dispclk_delay_subtotal = 87, //
- .dcfclk_cstate_latency = 10, // SRExitTime
- .max_inter_dcn_tile_repeaters = 8,
- .xfc_supported = true,
- .xfc_fill_bw_overhead_percent = 10.0,
- .xfc_fill_constant_bytes = 0,
- .number_of_cursors = 1,
-};
-
-static struct _vcs_dpi_ip_params_st dcn2_0_nv14_ip = {
- .odm_capable = 1,
- .gpuvm_enable = 0,
- .hostvm_enable = 0,
- .gpuvm_max_page_table_levels = 4,
- .hostvm_max_page_table_levels = 4,
- .hostvm_cached_page_table_levels = 0,
- .num_dsc = 5,
- .rob_buffer_size_kbytes = 168,
- .det_buffer_size_kbytes = 164,
- .dpte_buffer_size_in_pte_reqs_luma = 84,
- .dpte_buffer_size_in_pte_reqs_chroma = 42,//todo
- .dpp_output_buffer_pixels = 2560,
- .opp_output_buffer_lines = 1,
- .pixel_chunk_size_kbytes = 8,
- .pte_enable = 1,
- .max_page_table_levels = 4,
- .pte_chunk_size_kbytes = 2,
- .meta_chunk_size_kbytes = 2,
- .writeback_chunk_size_kbytes = 2,
- .line_buffer_size_bits = 789504,
- .is_line_buffer_bpp_fixed = 0,
- .line_buffer_fixed_bpp = 0,
- .dcc_supported = true,
- .max_line_buffer_lines = 12,
- .writeback_luma_buffer_size_kbytes = 12,
- .writeback_chroma_buffer_size_kbytes = 8,
- .writeback_chroma_line_buffer_width_pixels = 4,
- .writeback_max_hscl_ratio = 1,
- .writeback_max_vscl_ratio = 1,
- .writeback_min_hscl_ratio = 1,
- .writeback_min_vscl_ratio = 1,
- .writeback_max_hscl_taps = 12,
- .writeback_max_vscl_taps = 12,
- .writeback_line_buffer_luma_buffer_size = 0,
- .writeback_line_buffer_chroma_buffer_size = 14643,
- .cursor_buffer_size = 8,
- .cursor_chunk_size = 2,
- .max_num_otg = 5,
- .max_num_dpp = 5,
- .max_num_wb = 1,
- .max_dchub_pscl_bw_pix_per_clk = 4,
- .max_pscl_lb_bw_pix_per_clk = 2,
- .max_lb_vscl_bw_pix_per_clk = 4,
- .max_vscl_hscl_bw_pix_per_clk = 4,
- .max_hscl_ratio = 8,
- .max_vscl_ratio = 8,
- .hscl_mults = 4,
- .vscl_mults = 4,
- .max_hscl_taps = 8,
- .max_vscl_taps = 8,
- .dispclk_ramp_margin_percent = 1,
- .underscan_factor = 1.10,
- .min_vblank_lines = 32, //
- .dppclk_delay_subtotal = 77, //
- .dppclk_delay_scl_lb_only = 16,
- .dppclk_delay_scl = 50,
- .dppclk_delay_cnvc_formatter = 8,
- .dppclk_delay_cnvc_cursor = 6,
- .dispclk_delay_subtotal = 87, //
- .dcfclk_cstate_latency = 10, // SRExitTime
- .max_inter_dcn_tile_repeaters = 8,
- .xfc_supported = true,
- .xfc_fill_bw_overhead_percent = 10.0,
- .xfc_fill_constant_bytes = 0,
- .ptoi_supported = 0,
- .number_of_cursors = 1,
-};
-
-static struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = {
- /* Defaults that get patched on driver load from firmware. */
- .clock_limits = {
- {
- .state = 0,
- .dcfclk_mhz = 560.0,
- .fabricclk_mhz = 560.0,
- .dispclk_mhz = 513.0,
- .dppclk_mhz = 513.0,
- .phyclk_mhz = 540.0,
- .socclk_mhz = 560.0,
- .dscclk_mhz = 171.0,
- .dram_speed_mts = 8960.0,
- },
- {
- .state = 1,
- .dcfclk_mhz = 694.0,
- .fabricclk_mhz = 694.0,
- .dispclk_mhz = 642.0,
- .dppclk_mhz = 642.0,
- .phyclk_mhz = 600.0,
- .socclk_mhz = 694.0,
- .dscclk_mhz = 214.0,
- .dram_speed_mts = 11104.0,
- },
- {
- .state = 2,
- .dcfclk_mhz = 875.0,
- .fabricclk_mhz = 875.0,
- .dispclk_mhz = 734.0,
- .dppclk_mhz = 734.0,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 875.0,
- .dscclk_mhz = 245.0,
- .dram_speed_mts = 14000.0,
- },
- {
- .state = 3,
- .dcfclk_mhz = 1000.0,
- .fabricclk_mhz = 1000.0,
- .dispclk_mhz = 1100.0,
- .dppclk_mhz = 1100.0,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 1000.0,
- .dscclk_mhz = 367.0,
- .dram_speed_mts = 16000.0,
- },
- {
- .state = 4,
- .dcfclk_mhz = 1200.0,
- .fabricclk_mhz = 1200.0,
- .dispclk_mhz = 1284.0,
- .dppclk_mhz = 1284.0,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 1200.0,
- .dscclk_mhz = 428.0,
- .dram_speed_mts = 16000.0,
- },
- /*Extra state, no dispclk ramping*/
- {
- .state = 5,
- .dcfclk_mhz = 1200.0,
- .fabricclk_mhz = 1200.0,
- .dispclk_mhz = 1284.0,
- .dppclk_mhz = 1284.0,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 1200.0,
- .dscclk_mhz = 428.0,
- .dram_speed_mts = 16000.0,
- },
- },
- .num_states = 5,
- .sr_exit_time_us = 8.6,
- .sr_enter_plus_exit_time_us = 10.9,
- .urgent_latency_us = 4.0,
- .urgent_latency_pixel_data_only_us = 4.0,
- .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
- .urgent_latency_vm_data_only_us = 4.0,
- .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
- .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
- .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0,
- .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
- .max_avg_sdp_bw_use_normal_percent = 40.0,
- .max_avg_dram_bw_use_normal_percent = 40.0,
- .writeback_latency_us = 12.0,
- .ideal_dram_bw_after_urgent_percent = 40.0,
- .max_request_size_bytes = 256,
- .dram_channel_width_bytes = 2,
- .fabric_datapath_to_dcn_data_return_bytes = 64,
- .dcn_downspread_percent = 0.5,
- .downspread_percent = 0.38,
- .dram_page_open_time_ns = 50.0,
- .dram_rw_turnaround_time_ns = 17.5,
- .dram_return_buffer_per_channel_bytes = 8192,
- .round_trip_ping_latency_dcfclk_cycles = 131,
- .urgent_out_of_order_return_per_channel_bytes = 256,
- .channel_interleave_bytes = 256,
- .num_banks = 8,
- .num_chans = 16,
- .vmm_page_size_bytes = 4096,
- .dram_clock_change_latency_us = 404.0,
- .dummy_pstate_latency_us = 5.0,
- .writeback_dram_clock_change_latency_us = 23.0,
- .return_bus_width_bytes = 64,
- .dispclk_dppclk_vco_speed_mhz = 3850,
- .xfc_bus_transport_time_us = 20,
- .xfc_xbuf_latency_tolerance_us = 4,
- .use_urgent_burst_bw = 0
-};
-
-static struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc = {
- .clock_limits = {
- {
- .state = 0,
- .dcfclk_mhz = 560.0,
- .fabricclk_mhz = 560.0,
- .dispclk_mhz = 513.0,
- .dppclk_mhz = 513.0,
- .phyclk_mhz = 540.0,
- .socclk_mhz = 560.0,
- .dscclk_mhz = 171.0,
- .dram_speed_mts = 8960.0,
- },
- {
- .state = 1,
- .dcfclk_mhz = 694.0,
- .fabricclk_mhz = 694.0,
- .dispclk_mhz = 642.0,
- .dppclk_mhz = 642.0,
- .phyclk_mhz = 600.0,
- .socclk_mhz = 694.0,
- .dscclk_mhz = 214.0,
- .dram_speed_mts = 11104.0,
- },
- {
- .state = 2,
- .dcfclk_mhz = 875.0,
- .fabricclk_mhz = 875.0,
- .dispclk_mhz = 734.0,
- .dppclk_mhz = 734.0,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 875.0,
- .dscclk_mhz = 245.0,
- .dram_speed_mts = 14000.0,
- },
- {
- .state = 3,
- .dcfclk_mhz = 1000.0,
- .fabricclk_mhz = 1000.0,
- .dispclk_mhz = 1100.0,
- .dppclk_mhz = 1100.0,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 1000.0,
- .dscclk_mhz = 367.0,
- .dram_speed_mts = 16000.0,
- },
- {
- .state = 4,
- .dcfclk_mhz = 1200.0,
- .fabricclk_mhz = 1200.0,
- .dispclk_mhz = 1284.0,
- .dppclk_mhz = 1284.0,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 1200.0,
- .dscclk_mhz = 428.0,
- .dram_speed_mts = 16000.0,
- },
- /*Extra state, no dispclk ramping*/
- {
- .state = 5,
- .dcfclk_mhz = 1200.0,
- .fabricclk_mhz = 1200.0,
- .dispclk_mhz = 1284.0,
- .dppclk_mhz = 1284.0,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 1200.0,
- .dscclk_mhz = 428.0,
- .dram_speed_mts = 16000.0,
- },
- },
- .num_states = 5,
- .sr_exit_time_us = 11.6,
- .sr_enter_plus_exit_time_us = 13.9,
- .urgent_latency_us = 4.0,
- .urgent_latency_pixel_data_only_us = 4.0,
- .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
- .urgent_latency_vm_data_only_us = 4.0,
- .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
- .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
- .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0,
- .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
- .max_avg_sdp_bw_use_normal_percent = 40.0,
- .max_avg_dram_bw_use_normal_percent = 40.0,
- .writeback_latency_us = 12.0,
- .ideal_dram_bw_after_urgent_percent = 40.0,
- .max_request_size_bytes = 256,
- .dram_channel_width_bytes = 2,
- .fabric_datapath_to_dcn_data_return_bytes = 64,
- .dcn_downspread_percent = 0.5,
- .downspread_percent = 0.38,
- .dram_page_open_time_ns = 50.0,
- .dram_rw_turnaround_time_ns = 17.5,
- .dram_return_buffer_per_channel_bytes = 8192,
- .round_trip_ping_latency_dcfclk_cycles = 131,
- .urgent_out_of_order_return_per_channel_bytes = 256,
- .channel_interleave_bytes = 256,
- .num_banks = 8,
- .num_chans = 8,
- .vmm_page_size_bytes = 4096,
- .dram_clock_change_latency_us = 404.0,
- .dummy_pstate_latency_us = 5.0,
- .writeback_dram_clock_change_latency_us = 23.0,
- .return_bus_width_bytes = 64,
- .dispclk_dppclk_vco_speed_mhz = 3850,
- .xfc_bus_transport_time_us = 20,
- .xfc_xbuf_latency_tolerance_us = 4,
- .use_urgent_burst_bw = 0
-};
-
-static struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc = { 0 };
-
#ifndef mmDP0_DP_DPHY_INTERNAL_CTRL
#define mmDP0_DP_DPHY_INTERNAL_CTRL 0x210f
#define mmDP0_DP_DPHY_INTERNAL_CTRL_BASE_IDX 2
@@ -1605,16 +1243,7 @@ static void get_pixel_clock_parameters(
pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz;
- /* Links supporting dynamically assigned link encoder will be assigned next
- * available encoder if one not already assigned.
- */
- if (link->is_dig_mapping_flexible &&
- link->dc->res_pool->funcs->link_encs_assign) {
- link_enc = link_enc_cfg_get_link_enc_used_by_stream(stream->ctx->dc, stream);
- if (link_enc == NULL)
- link_enc = link_enc_cfg_get_next_avail_link_enc(stream->ctx->dc);
- } else
- link_enc = stream->link->link_enc;
+ link_enc = link_enc_cfg_get_link_enc(link);
ASSERT(link_enc);
if (link_enc)
@@ -1819,69 +1448,6 @@ enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_
return result;
}
-
-static void swizzle_to_dml_params(
- enum swizzle_mode_values swizzle,
- unsigned int *sw_mode)
-{
- switch (swizzle) {
- case DC_SW_LINEAR:
- *sw_mode = dm_sw_linear;
- break;
- case DC_SW_4KB_S:
- *sw_mode = dm_sw_4kb_s;
- break;
- case DC_SW_4KB_S_X:
- *sw_mode = dm_sw_4kb_s_x;
- break;
- case DC_SW_4KB_D:
- *sw_mode = dm_sw_4kb_d;
- break;
- case DC_SW_4KB_D_X:
- *sw_mode = dm_sw_4kb_d_x;
- break;
- case DC_SW_64KB_S:
- *sw_mode = dm_sw_64kb_s;
- break;
- case DC_SW_64KB_S_X:
- *sw_mode = dm_sw_64kb_s_x;
- break;
- case DC_SW_64KB_S_T:
- *sw_mode = dm_sw_64kb_s_t;
- break;
- case DC_SW_64KB_D:
- *sw_mode = dm_sw_64kb_d;
- break;
- case DC_SW_64KB_D_X:
- *sw_mode = dm_sw_64kb_d_x;
- break;
- case DC_SW_64KB_D_T:
- *sw_mode = dm_sw_64kb_d_t;
- break;
- case DC_SW_64KB_R_X:
- *sw_mode = dm_sw_64kb_r_x;
- break;
- case DC_SW_VAR_S:
- *sw_mode = dm_sw_var_s;
- break;
- case DC_SW_VAR_S_X:
- *sw_mode = dm_sw_var_s_x;
- break;
- case DC_SW_VAR_D:
- *sw_mode = dm_sw_var_d;
- break;
- case DC_SW_VAR_D_X:
- *sw_mode = dm_sw_var_d_x;
- break;
- case DC_SW_VAR_R_X:
- *sw_mode = dm_sw_var_r_x;
- break;
- default:
- ASSERT(0); /* Not supported */
- break;
- }
-}
-
bool dcn20_split_stream_for_odm(
const struct dc *dc,
struct resource_context *res_ctx,
@@ -1997,394 +1563,6 @@ void dcn20_split_stream_for_mpc(
ASSERT(primary_pipe->plane_state);
}
-int dcn20_populate_dml_pipes_from_context(
- struct dc *dc,
- struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- bool fast_validate)
-{
- int pipe_cnt, i;
- bool synchronized_vblank = true;
- struct resource_context *res_ctx = &context->res_ctx;
-
- for (i = 0, pipe_cnt = -1; i < dc->res_pool->pipe_count; i++) {
- if (!res_ctx->pipe_ctx[i].stream)
- continue;
-
- if (pipe_cnt < 0) {
- pipe_cnt = i;
- continue;
- }
-
- if (res_ctx->pipe_ctx[pipe_cnt].stream == res_ctx->pipe_ctx[i].stream)
- continue;
-
- if (dc->debug.disable_timing_sync ||
- (!resource_are_streams_timing_synchronizable(
- res_ctx->pipe_ctx[pipe_cnt].stream,
- res_ctx->pipe_ctx[i].stream) &&
- !resource_are_vblanks_synchronizable(
- res_ctx->pipe_ctx[pipe_cnt].stream,
- res_ctx->pipe_ctx[i].stream))) {
- synchronized_vblank = false;
- break;
- }
- }
-
- for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
- struct dc_crtc_timing *timing = &res_ctx->pipe_ctx[i].stream->timing;
- unsigned int v_total;
- unsigned int front_porch;
- int output_bpc;
- struct audio_check aud_check = {0};
-
- if (!res_ctx->pipe_ctx[i].stream)
- continue;
-
- v_total = timing->v_total;
- front_porch = timing->v_front_porch;
-
- /* todo:
- pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = 0;
- pipes[pipe_cnt].pipe.src.dcc = 0;
- pipes[pipe_cnt].pipe.src.vm = 0;*/
-
- pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0;
-
- pipes[pipe_cnt].dout.dsc_enable = res_ctx->pipe_ctx[i].stream->timing.flags.DSC;
- /* todo: rotation?*/
- pipes[pipe_cnt].dout.dsc_slices = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.num_slices_h;
- if (res_ctx->pipe_ctx[i].stream->use_dynamic_meta) {
- pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = true;
- /* 1/2 vblank */
- pipes[pipe_cnt].pipe.src.dynamic_metadata_lines_before_active =
- (v_total - timing->v_addressable
- - timing->v_border_top - timing->v_border_bottom) / 2;
- /* 36 bytes dp, 32 hdmi */
- pipes[pipe_cnt].pipe.src.dynamic_metadata_xmit_bytes =
- dc_is_dp_signal(res_ctx->pipe_ctx[i].stream->signal) ? 36 : 32;
- }
- pipes[pipe_cnt].pipe.src.dcc = false;
- pipes[pipe_cnt].pipe.src.dcc_rate = 1;
- pipes[pipe_cnt].pipe.dest.synchronized_vblank_all_planes = synchronized_vblank;
- pipes[pipe_cnt].pipe.dest.hblank_start = timing->h_total - timing->h_front_porch;
- pipes[pipe_cnt].pipe.dest.hblank_end = pipes[pipe_cnt].pipe.dest.hblank_start
- - timing->h_addressable
- - timing->h_border_left
- - timing->h_border_right;
- pipes[pipe_cnt].pipe.dest.vblank_start = v_total - front_porch;
- pipes[pipe_cnt].pipe.dest.vblank_end = pipes[pipe_cnt].pipe.dest.vblank_start
- - timing->v_addressable
- - timing->v_border_top
- - timing->v_border_bottom;
- pipes[pipe_cnt].pipe.dest.htotal = timing->h_total;
- pipes[pipe_cnt].pipe.dest.vtotal = v_total;
- pipes[pipe_cnt].pipe.dest.hactive =
- timing->h_addressable + timing->h_border_left + timing->h_border_right;
- pipes[pipe_cnt].pipe.dest.vactive =
- timing->v_addressable + timing->v_border_top + timing->v_border_bottom;
- pipes[pipe_cnt].pipe.dest.interlaced = timing->flags.INTERLACE;
- pipes[pipe_cnt].pipe.dest.pixel_rate_mhz = timing->pix_clk_100hz/10000.0;
- if (timing->timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
- pipes[pipe_cnt].pipe.dest.pixel_rate_mhz *= 2;
- pipes[pipe_cnt].pipe.dest.otg_inst = res_ctx->pipe_ctx[i].stream_res.tg->inst;
- pipes[pipe_cnt].dout.dp_lanes = 4;
- pipes[pipe_cnt].dout.is_virtual = 0;
- pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min;
- pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max;
- switch (get_num_odm_splits(&res_ctx->pipe_ctx[i])) {
- case 1:
- pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_2to1;
- break;
- case 3:
- pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_4to1;
- break;
- default:
- pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_disabled;
- }
- pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx;
- if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state
- == res_ctx->pipe_ctx[i].plane_state) {
- struct pipe_ctx *first_pipe = res_ctx->pipe_ctx[i].top_pipe;
- int split_idx = 0;
-
- while (first_pipe->top_pipe && first_pipe->top_pipe->plane_state
- == res_ctx->pipe_ctx[i].plane_state) {
- first_pipe = first_pipe->top_pipe;
- split_idx++;
- }
- /* Treat 4to1 mpc combine as an mpo of 2 2-to-1 combines */
- if (split_idx == 0)
- pipes[pipe_cnt].pipe.src.hsplit_grp = first_pipe->pipe_idx;
- else if (split_idx == 1)
- pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx;
- else if (split_idx == 2)
- pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].top_pipe->pipe_idx;
- } else if (res_ctx->pipe_ctx[i].prev_odm_pipe) {
- struct pipe_ctx *first_pipe = res_ctx->pipe_ctx[i].prev_odm_pipe;
-
- while (first_pipe->prev_odm_pipe)
- first_pipe = first_pipe->prev_odm_pipe;
- pipes[pipe_cnt].pipe.src.hsplit_grp = first_pipe->pipe_idx;
- }
-
- switch (res_ctx->pipe_ctx[i].stream->signal) {
- case SIGNAL_TYPE_DISPLAY_PORT_MST:
- case SIGNAL_TYPE_DISPLAY_PORT:
- pipes[pipe_cnt].dout.output_type = dm_dp;
- break;
- case SIGNAL_TYPE_EDP:
- pipes[pipe_cnt].dout.output_type = dm_edp;
- break;
- case SIGNAL_TYPE_HDMI_TYPE_A:
- case SIGNAL_TYPE_DVI_SINGLE_LINK:
- case SIGNAL_TYPE_DVI_DUAL_LINK:
- pipes[pipe_cnt].dout.output_type = dm_hdmi;
- break;
- default:
- /* In case there is no signal, set dp with 4 lanes to allow max config */
- pipes[pipe_cnt].dout.is_virtual = 1;
- pipes[pipe_cnt].dout.output_type = dm_dp;
- pipes[pipe_cnt].dout.dp_lanes = 4;
- }
-
- switch (res_ctx->pipe_ctx[i].stream->timing.display_color_depth) {
- case COLOR_DEPTH_666:
- output_bpc = 6;
- break;
- case COLOR_DEPTH_888:
- output_bpc = 8;
- break;
- case COLOR_DEPTH_101010:
- output_bpc = 10;
- break;
- case COLOR_DEPTH_121212:
- output_bpc = 12;
- break;
- case COLOR_DEPTH_141414:
- output_bpc = 14;
- break;
- case COLOR_DEPTH_161616:
- output_bpc = 16;
- break;
- case COLOR_DEPTH_999:
- output_bpc = 9;
- break;
- case COLOR_DEPTH_111111:
- output_bpc = 11;
- break;
- default:
- output_bpc = 8;
- break;
- }
-
- switch (res_ctx->pipe_ctx[i].stream->timing.pixel_encoding) {
- case PIXEL_ENCODING_RGB:
- case PIXEL_ENCODING_YCBCR444:
- pipes[pipe_cnt].dout.output_format = dm_444;
- pipes[pipe_cnt].dout.output_bpp = output_bpc * 3;
- break;
- case PIXEL_ENCODING_YCBCR420:
- pipes[pipe_cnt].dout.output_format = dm_420;
- pipes[pipe_cnt].dout.output_bpp = (output_bpc * 3.0) / 2;
- break;
- case PIXEL_ENCODING_YCBCR422:
- if (res_ctx->pipe_ctx[i].stream->timing.flags.DSC &&
- !res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.ycbcr422_simple)
- pipes[pipe_cnt].dout.output_format = dm_n422;
- else
- pipes[pipe_cnt].dout.output_format = dm_s422;
- pipes[pipe_cnt].dout.output_bpp = output_bpc * 2;
- break;
- default:
- pipes[pipe_cnt].dout.output_format = dm_444;
- pipes[pipe_cnt].dout.output_bpp = output_bpc * 3;
- }
-
- if (res_ctx->pipe_ctx[i].stream->timing.flags.DSC)
- pipes[pipe_cnt].dout.output_bpp = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.bits_per_pixel / 16.0;
-
- /* todo: default max for now, until there is logic reflecting this in dc*/
- pipes[pipe_cnt].dout.dsc_input_bpc = 12;
- /*fill up the audio sample rate (unit in kHz)*/
- get_audio_check(&res_ctx->pipe_ctx[i].stream->audio_info, &aud_check);
- pipes[pipe_cnt].dout.max_audio_sample_rate = aud_check.max_audiosample_rate / 1000;
- /*
- * For graphic plane, cursor number is 1, nv12 is 0
- * bw calculations due to cursor on/off
- */
- if (res_ctx->pipe_ctx[i].plane_state &&
- res_ctx->pipe_ctx[i].plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
- pipes[pipe_cnt].pipe.src.num_cursors = 0;
- else
- pipes[pipe_cnt].pipe.src.num_cursors = dc->dml.ip.number_of_cursors;
-
- pipes[pipe_cnt].pipe.src.cur0_src_width = 256;
- pipes[pipe_cnt].pipe.src.cur0_bpp = dm_cur_32bit;
-
- if (!res_ctx->pipe_ctx[i].plane_state) {
- pipes[pipe_cnt].pipe.src.is_hsplit = pipes[pipe_cnt].pipe.dest.odm_combine != dm_odm_combine_mode_disabled;
- pipes[pipe_cnt].pipe.src.source_scan = dm_horz;
- pipes[pipe_cnt].pipe.src.sw_mode = dm_sw_4kb_s;
- pipes[pipe_cnt].pipe.src.macro_tile_size = dm_64k_tile;
- pipes[pipe_cnt].pipe.src.viewport_width = timing->h_addressable;
- if (pipes[pipe_cnt].pipe.src.viewport_width > 1920)
- pipes[pipe_cnt].pipe.src.viewport_width = 1920;
- pipes[pipe_cnt].pipe.src.viewport_height = timing->v_addressable;
- if (pipes[pipe_cnt].pipe.src.viewport_height > 1080)
- pipes[pipe_cnt].pipe.src.viewport_height = 1080;
- pipes[pipe_cnt].pipe.src.surface_height_y = pipes[pipe_cnt].pipe.src.viewport_height;
- pipes[pipe_cnt].pipe.src.surface_width_y = pipes[pipe_cnt].pipe.src.viewport_width;
- pipes[pipe_cnt].pipe.src.surface_height_c = pipes[pipe_cnt].pipe.src.viewport_height;
- pipes[pipe_cnt].pipe.src.surface_width_c = pipes[pipe_cnt].pipe.src.viewport_width;
- pipes[pipe_cnt].pipe.src.data_pitch = ((pipes[pipe_cnt].pipe.src.viewport_width + 255) / 256) * 256;
- pipes[pipe_cnt].pipe.src.source_format = dm_444_32;
- pipes[pipe_cnt].pipe.dest.recout_width = pipes[pipe_cnt].pipe.src.viewport_width; /*vp_width/hratio*/
- pipes[pipe_cnt].pipe.dest.recout_height = pipes[pipe_cnt].pipe.src.viewport_height; /*vp_height/vratio*/
- pipes[pipe_cnt].pipe.dest.full_recout_width = pipes[pipe_cnt].pipe.dest.recout_width; /*when is_hsplit != 1*/
- pipes[pipe_cnt].pipe.dest.full_recout_height = pipes[pipe_cnt].pipe.dest.recout_height; /*when is_hsplit != 1*/
- pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_16;
- pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio = 1.0;
- pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio = 1.0;
- pipes[pipe_cnt].pipe.scale_ratio_depth.scl_enable = 0; /*Lb only or Full scl*/
- pipes[pipe_cnt].pipe.scale_taps.htaps = 1;
- pipes[pipe_cnt].pipe.scale_taps.vtaps = 1;
- pipes[pipe_cnt].pipe.dest.vtotal_min = v_total;
- pipes[pipe_cnt].pipe.dest.vtotal_max = v_total;
-
- if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_2to1) {
- pipes[pipe_cnt].pipe.src.viewport_width /= 2;
- pipes[pipe_cnt].pipe.dest.recout_width /= 2;
- } else if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_4to1) {
- pipes[pipe_cnt].pipe.src.viewport_width /= 4;
- pipes[pipe_cnt].pipe.dest.recout_width /= 4;
- }
- } else {
- struct dc_plane_state *pln = res_ctx->pipe_ctx[i].plane_state;
- struct scaler_data *scl = &res_ctx->pipe_ctx[i].plane_res.scl_data;
-
- pipes[pipe_cnt].pipe.src.immediate_flip = pln->flip_immediate;
- pipes[pipe_cnt].pipe.src.is_hsplit = (res_ctx->pipe_ctx[i].bottom_pipe && res_ctx->pipe_ctx[i].bottom_pipe->plane_state == pln)
- || (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln)
- || pipes[pipe_cnt].pipe.dest.odm_combine != dm_odm_combine_mode_disabled;
-
- /* stereo is not split */
- if (pln->stereo_format == PLANE_STEREO_FORMAT_SIDE_BY_SIDE ||
- pln->stereo_format == PLANE_STEREO_FORMAT_TOP_AND_BOTTOM) {
- pipes[pipe_cnt].pipe.src.is_hsplit = false;
- pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx;
- }
-
- pipes[pipe_cnt].pipe.src.source_scan = pln->rotation == ROTATION_ANGLE_90
- || pln->rotation == ROTATION_ANGLE_270 ? dm_vert : dm_horz;
- pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport.y;
- pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c.y;
- pipes[pipe_cnt].pipe.src.viewport_width = scl->viewport.width;
- pipes[pipe_cnt].pipe.src.viewport_width_c = scl->viewport_c.width;
- pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport.height;
- pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c.height;
- pipes[pipe_cnt].pipe.src.viewport_width_max = pln->src_rect.width;
- pipes[pipe_cnt].pipe.src.viewport_height_max = pln->src_rect.height;
- pipes[pipe_cnt].pipe.src.surface_width_y = pln->plane_size.surface_size.width;
- pipes[pipe_cnt].pipe.src.surface_height_y = pln->plane_size.surface_size.height;
- pipes[pipe_cnt].pipe.src.surface_width_c = pln->plane_size.chroma_size.width;
- pipes[pipe_cnt].pipe.src.surface_height_c = pln->plane_size.chroma_size.height;
- if (pln->format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA
- || pln->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
- pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.surface_pitch;
- pipes[pipe_cnt].pipe.src.data_pitch_c = pln->plane_size.chroma_pitch;
- pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.meta_pitch;
- pipes[pipe_cnt].pipe.src.meta_pitch_c = pln->dcc.meta_pitch_c;
- } else {
- pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.surface_pitch;
- pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.meta_pitch;
- }
- pipes[pipe_cnt].pipe.src.dcc = pln->dcc.enable;
- pipes[pipe_cnt].pipe.dest.recout_width = scl->recout.width;
- pipes[pipe_cnt].pipe.dest.recout_height = scl->recout.height;
- pipes[pipe_cnt].pipe.dest.full_recout_height = scl->recout.height;
- pipes[pipe_cnt].pipe.dest.full_recout_width = scl->recout.width;
- if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_2to1)
- pipes[pipe_cnt].pipe.dest.full_recout_width *= 2;
- else if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_4to1)
- pipes[pipe_cnt].pipe.dest.full_recout_width *= 4;
- else {
- struct pipe_ctx *split_pipe = res_ctx->pipe_ctx[i].bottom_pipe;
-
- while (split_pipe && split_pipe->plane_state == pln) {
- pipes[pipe_cnt].pipe.dest.full_recout_width += split_pipe->plane_res.scl_data.recout.width;
- split_pipe = split_pipe->bottom_pipe;
- }
- split_pipe = res_ctx->pipe_ctx[i].top_pipe;
- while (split_pipe && split_pipe->plane_state == pln) {
- pipes[pipe_cnt].pipe.dest.full_recout_width += split_pipe->plane_res.scl_data.recout.width;
- split_pipe = split_pipe->top_pipe;
- }
- }
-
- pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_16;
- pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio = (double) scl->ratios.horz.value / (1ULL<<32);
- pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio_c = (double) scl->ratios.horz_c.value / (1ULL<<32);
- pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio = (double) scl->ratios.vert.value / (1ULL<<32);
- pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio_c = (double) scl->ratios.vert_c.value / (1ULL<<32);
- pipes[pipe_cnt].pipe.scale_ratio_depth.scl_enable =
- scl->ratios.vert.value != dc_fixpt_one.value
- || scl->ratios.horz.value != dc_fixpt_one.value
- || scl->ratios.vert_c.value != dc_fixpt_one.value
- || scl->ratios.horz_c.value != dc_fixpt_one.value /*Lb only or Full scl*/
- || dc->debug.always_scale; /*support always scale*/
- pipes[pipe_cnt].pipe.scale_taps.htaps = scl->taps.h_taps;
- pipes[pipe_cnt].pipe.scale_taps.htaps_c = scl->taps.h_taps_c;
- pipes[pipe_cnt].pipe.scale_taps.vtaps = scl->taps.v_taps;
- pipes[pipe_cnt].pipe.scale_taps.vtaps_c = scl->taps.v_taps_c;
-
- pipes[pipe_cnt].pipe.src.macro_tile_size =
- swizzle_mode_to_macro_tile_size(pln->tiling_info.gfx9.swizzle);
- swizzle_to_dml_params(pln->tiling_info.gfx9.swizzle,
- &pipes[pipe_cnt].pipe.src.sw_mode);
-
- switch (pln->format) {
- case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
- case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
- pipes[pipe_cnt].pipe.src.source_format = dm_420_8;
- break;
- case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
- case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
- pipes[pipe_cnt].pipe.src.source_format = dm_420_10;
- break;
- case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
- case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
- case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
- case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
- pipes[pipe_cnt].pipe.src.source_format = dm_444_64;
- break;
- case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
- case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
- pipes[pipe_cnt].pipe.src.source_format = dm_444_16;
- break;
- case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
- pipes[pipe_cnt].pipe.src.source_format = dm_444_8;
- break;
- case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
- pipes[pipe_cnt].pipe.src.source_format = dm_rgbe_alpha;
- break;
- default:
- pipes[pipe_cnt].pipe.src.source_format = dm_444_32;
- break;
- }
- }
-
- pipe_cnt++;
- }
-
- /* populate writeback information */
- DC_FP_START();
- dc->res_pool->funcs->populate_dml_writeback_from_context(dc, res_ctx, pipes);
- DC_FP_END();
-
- return pipe_cnt;
-}
-
unsigned int dcn20_calc_max_scaled_time(
unsigned int time_per_pixel,
enum mmhubbub_wbif_mode mode,
@@ -2422,7 +1600,7 @@ void dcn20_set_mcif_arb_params(
{
enum mmhubbub_wbif_mode wbif_mode;
struct mcif_arb_params *wb_arb_params;
- int i, j, k, dwb_pipe;
+ int i, j, dwb_pipe;
/* Writeback MCIF_WB arbitration parameters */
dwb_pipe = 0;
@@ -2446,11 +1624,10 @@ void dcn20_set_mcif_arb_params(
} else
wbif_mode = PACKED_444;
- for (k = 0; k < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); k++) {
- wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- }
- wb_arb_params->time_per_pixel = 16.0 * 1000 / (context->res_ctx.pipe_ctx[i].stream->phy_pix_clk / 1000); /* 4 bit fraction, ms */
+ DC_FP_START();
+ dcn20_fpu_set_wb_arb_params(wb_arb_params, context, pipes, pipe_cnt, i);
+ DC_FP_END();
+
wb_arb_params->slice_lines = 32;
wb_arb_params->arbitration_slice = 2;
wb_arb_params->max_scaled_time = dcn20_calc_max_scaled_time(wb_arb_params->time_per_pixel,
@@ -2799,7 +1976,6 @@ int dcn20_validate_apply_pipe_split_flags(
/*If need split for odm but 4 way split already*/
if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe)
|| !pipe->next_odm_pipe)) {
- ASSERT(0); /* NOT expected yet */
merge[i] = true; /* 4 -> 2 ODM */
} else if (split[i] == 0 && pipe->prev_odm_pipe) {
ASSERT(0); /* NOT expected yet */
@@ -2817,8 +1993,11 @@ int dcn20_validate_apply_pipe_split_flags(
}
/* Adjust dppclk when split is forced, do not bother with dispclk */
- if (split[i] != 0 && v->NoOfDPP[vlevel][max_mpc_comb][pipe_idx] == 1)
- v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] /= 2;
+ if (split[i] != 0 && v->NoOfDPP[vlevel][max_mpc_comb][pipe_idx] == 1) {
+ DC_FP_START();
+ dcn20_fpu_adjust_dppclk(v, vlevel, max_mpc_comb, pipe_idx, false);
+ DC_FP_END();
+ }
pipe_idx++;
}
@@ -2844,7 +2023,9 @@ bool dcn20_fast_validate_bw(
dcn20_merge_pipes_for_validate(dc, context);
+ DC_FP_START();
pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
+ DC_FP_END();
*pipe_cnt_out = pipe_cnt;
@@ -2901,7 +2082,9 @@ bool dcn20_fast_validate_bw(
hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe);
ASSERT(hsplit_pipe);
if (!hsplit_pipe) {
- context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] *= 2;
+ DC_FP_START();
+ dcn20_fpu_adjust_dppclk(&context->bw_ctx.dml.vba, vlevel, context->bw_ctx.dml.vba.maxMpcComb, pipe_idx, true);
+ DC_FP_END();
continue;
}
if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) {
@@ -2943,363 +2126,6 @@ validate_out:
return out;
}
-static void dcn20_calculate_wm(
- struct dc *dc, struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- int *out_pipe_cnt,
- int *pipe_split_from,
- int vlevel,
- bool fast_validate)
-{
- int pipe_cnt, i, pipe_idx;
-
- for (i = 0, pipe_idx = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
- if (!context->res_ctx.pipe_ctx[i].stream)
- continue;
-
- pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0;
- pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.vba.RequiredDISPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
-
- if (pipe_split_from[i] < 0) {
- pipes[pipe_cnt].clks_cfg.dppclk_mhz =
- context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx];
- if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_idx] == pipe_idx)
- pipes[pipe_cnt].pipe.dest.odm_combine =
- context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx];
- else
- pipes[pipe_cnt].pipe.dest.odm_combine = 0;
- pipe_idx++;
- } else {
- pipes[pipe_cnt].clks_cfg.dppclk_mhz =
- context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_split_from[i]];
- if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_split_from[i]] == pipe_split_from[i])
- pipes[pipe_cnt].pipe.dest.odm_combine =
- context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_split_from[i]];
- else
- pipes[pipe_cnt].pipe.dest.odm_combine = 0;
- }
-
- if (dc->config.forced_clocks) {
- pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
- pipes[pipe_cnt].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
- }
- if (dc->debug.min_disp_clk_khz > pipes[pipe_cnt].clks_cfg.dispclk_mhz * 1000)
- pipes[pipe_cnt].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
- if (dc->debug.min_dpp_clk_khz > pipes[pipe_cnt].clks_cfg.dppclk_mhz * 1000)
- pipes[pipe_cnt].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
-
- pipe_cnt++;
- }
-
- if (pipe_cnt != pipe_idx) {
- if (dc->res_pool->funcs->populate_dml_pipes)
- pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc,
- context, pipes, fast_validate);
- else
- pipe_cnt = dcn20_populate_dml_pipes_from_context(dc,
- context, pipes, fast_validate);
- }
-
- *out_pipe_cnt = pipe_cnt;
-
- pipes[0].clks_cfg.voltage = vlevel;
- pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].dcfclk_mhz;
- pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
-
- /* only pipe 0 is read for voltage and dcf/soc clocks */
- if (vlevel < 1) {
- pipes[0].clks_cfg.voltage = 1;
- pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[1].dcfclk_mhz;
- pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[1].socclk_mhz;
- }
- context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
- if (vlevel < 2) {
- pipes[0].clks_cfg.voltage = 2;
- pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].dcfclk_mhz;
- pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].socclk_mhz;
- }
- context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
- if (vlevel < 3) {
- pipes[0].clks_cfg.voltage = 3;
- pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].dcfclk_mhz;
- pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].socclk_mhz;
- }
- context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
- pipes[0].clks_cfg.voltage = vlevel;
- pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].dcfclk_mhz;
- pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
- context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-}
-
-static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
-{
- int i;
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- if (!context->res_ctx.pipe_ctx[i].stream)
- continue;
- if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
- return true;
- }
- return false;
-}
-
-static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struct dc_state *context)
-{
- int plane_count;
- int i;
-
- plane_count = 0;
- for (i = 0; i < dc->res_pool->pipe_count; i++) {
- if (context->res_ctx.pipe_ctx[i].plane_state)
- plane_count++;
- }
-
- /*
- * Zstate is allowed in following scenarios:
- * 1. Single eDP with PSR enabled
- * 2. 0 planes (No memory requests)
- * 3. Single eDP without PSR but > 5ms stutter period
- */
- if (plane_count == 0)
- return DCN_ZSTATE_SUPPORT_ALLOW;
- else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) {
- struct dc_link *link = context->streams[0]->sink->link;
-
- if (link->link_index == 0 && context->bw_ctx.dml.vba.StutterPeriod > 5000.0)
- return DCN_ZSTATE_SUPPORT_ALLOW;
- else
- return DCN_ZSTATE_SUPPORT_DISALLOW;
- } else
- return DCN_ZSTATE_SUPPORT_DISALLOW;
-}
-
-void dcn20_calculate_dlg_params(
- struct dc *dc, struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- int pipe_cnt,
- int vlevel)
-{
- int i, pipe_idx;
-
- /* Writeback MCIF_WB arbitration parameters */
- dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt);
-
- context->bw_ctx.bw.dcn.clk.dispclk_khz = context->bw_ctx.dml.vba.DISPCLK * 1000;
- context->bw_ctx.bw.dcn.clk.dcfclk_khz = context->bw_ctx.dml.vba.DCFCLK * 1000;
- context->bw_ctx.bw.dcn.clk.socclk_khz = context->bw_ctx.dml.vba.SOCCLK * 1000;
- context->bw_ctx.bw.dcn.clk.dramclk_khz = context->bw_ctx.dml.vba.DRAMSpeed * 1000 / 16;
-
- if (dc->debug.min_dram_clk_khz > context->bw_ctx.bw.dcn.clk.dramclk_khz)
- context->bw_ctx.bw.dcn.clk.dramclk_khz = dc->debug.min_dram_clk_khz;
-
- context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = context->bw_ctx.dml.vba.DCFCLKDeepSleep * 1000;
- context->bw_ctx.bw.dcn.clk.fclk_khz = context->bw_ctx.dml.vba.FabricClock * 1000;
- context->bw_ctx.bw.dcn.clk.p_state_change_support =
- context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb]
- != dm_dram_clock_change_unsupported;
- context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
-
- context->bw_ctx.bw.dcn.clk.zstate_support = decide_zstate_support(dc, context);
-
- context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context);
-
- if (context->bw_ctx.bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz)
- context->bw_ctx.bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz;
-
- for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
- if (!context->res_ctx.pipe_ctx[i].stream)
- continue;
- pipes[pipe_idx].pipe.dest.vstartup_start = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
- pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
- pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
- pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
- context->res_ctx.pipe_ctx[i].det_buffer_size_kb = context->bw_ctx.dml.ip.det_buffer_size_kbytes;
- context->res_ctx.pipe_ctx[i].unbounded_req = pipes[pipe_idx].pipe.src.unbounded_req_mode;
-
- if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
- context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
- context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz =
- pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
- context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
- pipe_idx++;
- }
- /*save a original dppclock copy*/
- context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz;
- context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz;
- context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dppclk_mhz * 1000;
- context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz * 1000;
-
- context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes
- - context->bw_ctx.dml.ip.det_buffer_size_kbytes * pipe_idx;
-
- for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
- bool cstate_en = context->bw_ctx.dml.vba.PrefetchMode[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != 2;
-
- if (!context->res_ctx.pipe_ctx[i].stream)
- continue;
-
- if (dc->ctx->dce_version == DCN_VERSION_2_01)
- cstate_en = false;
-
- context->bw_ctx.dml.funcs.rq_dlg_get_dlg_reg(&context->bw_ctx.dml,
- &context->res_ctx.pipe_ctx[i].dlg_regs,
- &context->res_ctx.pipe_ctx[i].ttu_regs,
- pipes,
- pipe_cnt,
- pipe_idx,
- cstate_en,
- context->bw_ctx.bw.dcn.clk.p_state_change_support,
- false, false, true);
-
- context->bw_ctx.dml.funcs.rq_dlg_get_rq_reg(&context->bw_ctx.dml,
- &context->res_ctx.pipe_ctx[i].rq_regs,
- &pipes[pipe_idx].pipe);
- pipe_idx++;
- }
-}
-
-static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *context,
- bool fast_validate)
-{
- bool out = false;
-
- BW_VAL_TRACE_SETUP();
-
- int vlevel = 0;
- int pipe_split_from[MAX_PIPES];
- int pipe_cnt = 0;
- display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
- DC_LOGGER_INIT(dc->ctx->logger);
-
- BW_VAL_TRACE_COUNT();
-
- out = dcn20_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel, fast_validate);
-
- if (pipe_cnt == 0)
- goto validate_out;
-
- if (!out)
- goto validate_fail;
-
- BW_VAL_TRACE_END_VOLTAGE_LEVEL();
-
- if (fast_validate) {
- BW_VAL_TRACE_SKIP(fast);
- goto validate_out;
- }
-
- dcn20_calculate_wm(dc, context, pipes, &pipe_cnt, pipe_split_from, vlevel, fast_validate);
- dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
-
- BW_VAL_TRACE_END_WATERMARKS();
-
- goto validate_out;
-
-validate_fail:
- DC_LOG_WARNING("Mode Validation Warning: %s failed validation.\n",
- dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states]));
-
- BW_VAL_TRACE_SKIP(fail);
- out = false;
-
-validate_out:
- kfree(pipes);
-
- BW_VAL_TRACE_FINISH();
-
- return out;
-}
-
-/*
- * This must be noinline to ensure anything that deals with FP registers
- * is contained within this call; previously our compiling with hard-float
- * would result in fp instructions being emitted outside of the boundaries
- * of the DC_FP_START/END macros, which makes sense as the compiler has no
- * idea about what is wrapped and what is not
- *
- * This is largely just a workaround to avoid breakage introduced with 5.6,
- * ideally all fp-using code should be moved into its own file, only that
- * should be compiled with hard-float, and all code exported from there
- * should be strictly wrapped with DC_FP_START/END
- */
-static noinline bool dcn20_validate_bandwidth_fp(struct dc *dc,
- struct dc_state *context, bool fast_validate)
-{
- bool voltage_supported = false;
- bool full_pstate_supported = false;
- bool dummy_pstate_supported = false;
- double p_state_latency_us;
-
- p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us;
- context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support =
- dc->debug.disable_dram_clock_change_vactive_support;
- context->bw_ctx.dml.soc.allow_dram_clock_one_display_vactive =
- dc->debug.enable_dram_clock_change_one_display_vactive;
-
- /*Unsafe due to current pipe merge and split logic*/
- ASSERT(context != dc->current_state);
-
- if (fast_validate) {
- return dcn20_validate_bandwidth_internal(dc, context, true);
- }
-
- // Best case, we support full UCLK switch latency
- voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
- full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;
-
- if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 ||
- (voltage_supported && full_pstate_supported)) {
- context->bw_ctx.bw.dcn.clk.p_state_change_support = full_pstate_supported;
- goto restore_dml_state;
- }
-
- // Fallback: Try to only support G6 temperature read latency
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us;
-
- voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
- dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;
-
- if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) {
- context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
- goto restore_dml_state;
- }
-
- // ERROR: fallback is supposed to always work.
- ASSERT(false);
-
-restore_dml_state:
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us;
- return voltage_supported;
-}
-
bool dcn20_validate_bandwidth(struct dc *dc, struct dc_state *context,
bool fast_validate)
{
@@ -3467,170 +2293,6 @@ static void dcn20_pp_smu_destroy(struct pp_smu_funcs **pp_smu)
}
}
-void dcn20_cap_soc_clocks(
- struct _vcs_dpi_soc_bounding_box_st *bb,
- struct pp_smu_nv_clock_table max_clocks)
-{
- int i;
-
- // First pass - cap all clocks higher than the reported max
- for (i = 0; i < bb->num_states; i++) {
- if ((bb->clock_limits[i].dcfclk_mhz > (max_clocks.dcfClockInKhz / 1000))
- && max_clocks.dcfClockInKhz != 0)
- bb->clock_limits[i].dcfclk_mhz = (max_clocks.dcfClockInKhz / 1000);
-
- if ((bb->clock_limits[i].dram_speed_mts > (max_clocks.uClockInKhz / 1000) * 16)
- && max_clocks.uClockInKhz != 0)
- bb->clock_limits[i].dram_speed_mts = (max_clocks.uClockInKhz / 1000) * 16;
-
- if ((bb->clock_limits[i].fabricclk_mhz > (max_clocks.fabricClockInKhz / 1000))
- && max_clocks.fabricClockInKhz != 0)
- bb->clock_limits[i].fabricclk_mhz = (max_clocks.fabricClockInKhz / 1000);
-
- if ((bb->clock_limits[i].dispclk_mhz > (max_clocks.displayClockInKhz / 1000))
- && max_clocks.displayClockInKhz != 0)
- bb->clock_limits[i].dispclk_mhz = (max_clocks.displayClockInKhz / 1000);
-
- if ((bb->clock_limits[i].dppclk_mhz > (max_clocks.dppClockInKhz / 1000))
- && max_clocks.dppClockInKhz != 0)
- bb->clock_limits[i].dppclk_mhz = (max_clocks.dppClockInKhz / 1000);
-
- if ((bb->clock_limits[i].phyclk_mhz > (max_clocks.phyClockInKhz / 1000))
- && max_clocks.phyClockInKhz != 0)
- bb->clock_limits[i].phyclk_mhz = (max_clocks.phyClockInKhz / 1000);
-
- if ((bb->clock_limits[i].socclk_mhz > (max_clocks.socClockInKhz / 1000))
- && max_clocks.socClockInKhz != 0)
- bb->clock_limits[i].socclk_mhz = (max_clocks.socClockInKhz / 1000);
-
- if ((bb->clock_limits[i].dscclk_mhz > (max_clocks.dscClockInKhz / 1000))
- && max_clocks.dscClockInKhz != 0)
- bb->clock_limits[i].dscclk_mhz = (max_clocks.dscClockInKhz / 1000);
- }
-
- // Second pass - remove all duplicate clock states
- for (i = bb->num_states - 1; i > 1; i--) {
- bool duplicate = true;
-
- if (bb->clock_limits[i-1].dcfclk_mhz != bb->clock_limits[i].dcfclk_mhz)
- duplicate = false;
- if (bb->clock_limits[i-1].dispclk_mhz != bb->clock_limits[i].dispclk_mhz)
- duplicate = false;
- if (bb->clock_limits[i-1].dppclk_mhz != bb->clock_limits[i].dppclk_mhz)
- duplicate = false;
- if (bb->clock_limits[i-1].dram_speed_mts != bb->clock_limits[i].dram_speed_mts)
- duplicate = false;
- if (bb->clock_limits[i-1].dscclk_mhz != bb->clock_limits[i].dscclk_mhz)
- duplicate = false;
- if (bb->clock_limits[i-1].fabricclk_mhz != bb->clock_limits[i].fabricclk_mhz)
- duplicate = false;
- if (bb->clock_limits[i-1].phyclk_mhz != bb->clock_limits[i].phyclk_mhz)
- duplicate = false;
- if (bb->clock_limits[i-1].socclk_mhz != bb->clock_limits[i].socclk_mhz)
- duplicate = false;
-
- if (duplicate)
- bb->num_states--;
- }
-}
-
-void dcn20_update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb,
- struct pp_smu_nv_clock_table *max_clocks, unsigned int *uclk_states, unsigned int num_states)
-{
- struct _vcs_dpi_voltage_scaling_st calculated_states[DC__VOLTAGE_STATES];
- int i;
- int num_calculated_states = 0;
- int min_dcfclk = 0;
-
- if (num_states == 0)
- return;
-
- memset(calculated_states, 0, sizeof(calculated_states));
-
- if (dc->bb_overrides.min_dcfclk_mhz > 0)
- min_dcfclk = dc->bb_overrides.min_dcfclk_mhz;
- else {
- if (ASICREV_IS_NAVI12_P(dc->ctx->asic_id.hw_internal_rev))
- min_dcfclk = 310;
- else
- // Accounting for SOC/DCF relationship, we can go as high as
- // 506Mhz in Vmin.
- min_dcfclk = 506;
- }
-
- for (i = 0; i < num_states; i++) {
- int min_fclk_required_by_uclk;
- calculated_states[i].state = i;
- calculated_states[i].dram_speed_mts = uclk_states[i] * 16 / 1000;
-
- // FCLK:UCLK ratio is 1.08
- min_fclk_required_by_uclk = div_u64(((unsigned long long)uclk_states[i]) * 1080,
- 1000000);
-
- calculated_states[i].fabricclk_mhz = (min_fclk_required_by_uclk < min_dcfclk) ?
- min_dcfclk : min_fclk_required_by_uclk;
-
- calculated_states[i].socclk_mhz = (calculated_states[i].fabricclk_mhz > max_clocks->socClockInKhz / 1000) ?
- max_clocks->socClockInKhz / 1000 : calculated_states[i].fabricclk_mhz;
-
- calculated_states[i].dcfclk_mhz = (calculated_states[i].fabricclk_mhz > max_clocks->dcfClockInKhz / 1000) ?
- max_clocks->dcfClockInKhz / 1000 : calculated_states[i].fabricclk_mhz;
-
- calculated_states[i].dispclk_mhz = max_clocks->displayClockInKhz / 1000;
- calculated_states[i].dppclk_mhz = max_clocks->displayClockInKhz / 1000;
- calculated_states[i].dscclk_mhz = max_clocks->displayClockInKhz / (1000 * 3);
-
- calculated_states[i].phyclk_mhz = max_clocks->phyClockInKhz / 1000;
-
- num_calculated_states++;
- }
-
- calculated_states[num_calculated_states - 1].socclk_mhz = max_clocks->socClockInKhz / 1000;
- calculated_states[num_calculated_states - 1].fabricclk_mhz = max_clocks->socClockInKhz / 1000;
- calculated_states[num_calculated_states - 1].dcfclk_mhz = max_clocks->dcfClockInKhz / 1000;
-
- memcpy(bb->clock_limits, calculated_states, sizeof(bb->clock_limits));
- bb->num_states = num_calculated_states;
-
- // Duplicate the last state, DML always an extra state identical to max state to work
- memcpy(&bb->clock_limits[num_calculated_states], &bb->clock_limits[num_calculated_states - 1], sizeof(struct _vcs_dpi_voltage_scaling_st));
- bb->clock_limits[num_calculated_states].state = bb->num_states;
-}
-
-void dcn20_patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb)
-{
- if ((int)(bb->sr_exit_time_us * 1000) != dc->bb_overrides.sr_exit_time_ns
- && dc->bb_overrides.sr_exit_time_ns) {
- bb->sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0;
- }
-
- if ((int)(bb->sr_enter_plus_exit_time_us * 1000)
- != dc->bb_overrides.sr_enter_plus_exit_time_ns
- && dc->bb_overrides.sr_enter_plus_exit_time_ns) {
- bb->sr_enter_plus_exit_time_us =
- dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
- }
-
- if ((int)(bb->urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns
- && dc->bb_overrides.urgent_latency_ns) {
- bb->urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0;
- }
-
- if ((int)(bb->dram_clock_change_latency_us * 1000)
- != dc->bb_overrides.dram_clock_change_latency_ns
- && dc->bb_overrides.dram_clock_change_latency_ns) {
- bb->dram_clock_change_latency_us =
- dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
- }
-
- if ((int)(bb->dummy_pstate_latency_us * 1000)
- != dc->bb_overrides.dummy_clock_change_latency_ns
- && dc->bb_overrides.dummy_clock_change_latency_ns) {
- bb->dummy_pstate_latency_us =
- dc->bb_overrides.dummy_clock_change_latency_ns / 1000.0;
- }
-}
-
static struct _vcs_dpi_soc_bounding_box_st *get_asic_rev_soc_bb(
uint32_t hw_internal_rev)
{
@@ -3913,8 +2575,9 @@ static bool dcn20_resource_construct(
ranges.reader_wm_sets[i].wm_inst = i;
ranges.reader_wm_sets[i].min_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MIN;
ranges.reader_wm_sets[i].max_drain_clk_mhz = PP_SMU_WM_SET_RANGE_CLK_UNCONSTRAINED_MAX;
- ranges.reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0;
- ranges.reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16;
+ DC_FP_START();
+ dcn20_fpu_set_wm_ranges(i, &ranges, loaded_bb);
+ DC_FP_END();
ranges.num_reader_wm_sets = i + 1;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h
index 6ec8ff45f0f7..7cbe1e9daa36 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.h
@@ -27,6 +27,7 @@
#define __DC_RESOURCE_DCN20_H__
#include "core_types.h"
+#include "dml/dcn20/dcn20_fpu.h"
#define TO_DCN20_RES_POOL(pool)\
container_of(pool, struct dcn20_resource_pool, base)
@@ -35,6 +36,12 @@ struct dc;
struct resource_pool;
struct _vcs_dpi_display_pipe_params_st;
+extern struct _vcs_dpi_ip_params_st dcn2_0_ip;
+extern struct _vcs_dpi_ip_params_st dcn2_0_nv14_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc;
+extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc;
+extern struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc;
+
struct dcn20_resource_pool {
struct resource_pool base;
};
@@ -49,11 +56,7 @@ unsigned int dcn20_calc_max_scaled_time(
unsigned int time_per_pixel,
enum mmhubbub_wbif_mode mode,
unsigned int urgent_watermark);
-int dcn20_populate_dml_pipes_from_context(
- struct dc *dc,
- struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- bool fast_validate);
+
struct pipe_ctx *dcn20_acquire_idle_pipe_for_layer(
struct dc_state *state,
const struct resource_pool *pool,
@@ -79,7 +82,6 @@ struct dpp *dcn20_dpp_create(
struct input_pixel_processor *dcn20_ipp_create(
struct dc_context *ctx, uint32_t inst);
-
struct output_pixel_processor *dcn20_opp_create(
struct dc_context *ctx, uint32_t inst);
@@ -96,11 +98,6 @@ struct display_stream_compressor *dcn20_dsc_create(
struct dc_context *ctx, uint32_t inst);
void dcn20_dsc_destroy(struct display_stream_compressor **dsc);
-void dcn20_cap_soc_clocks(
- struct _vcs_dpi_soc_bounding_box_st *bb,
- struct pp_smu_nv_clock_table max_clocks);
-void dcn20_update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb,
- struct pp_smu_nv_clock_table *max_clocks, unsigned int *uclk_states, unsigned int num_states);
struct hubp *dcn20_hubp_create(
struct dc_context *ctx,
uint32_t inst);
@@ -158,11 +155,6 @@ bool dcn20_fast_validate_bw(
int *pipe_split_from,
int *vlevel_out,
bool fast_validate);
-void dcn20_calculate_dlg_params(
- struct dc *dc, struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- int pipe_cnt,
- int vlevel);
enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream);
enum dc_status dcn20_add_stream_to_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream);
@@ -170,12 +162,5 @@ enum dc_status dcn20_add_dsc_to_stream_resource(struct dc *dc, struct dc_state *
enum dc_status dcn20_remove_stream_from_ctx(struct dc *dc, struct dc_state *new_ctx, struct dc_stream_state *dc_stream);
enum dc_status dcn20_patch_unknown_plane_state(struct dc_plane_state *plane_state);
-void dcn20_patch_bounding_box(
- struct dc *dc,
- struct _vcs_dpi_soc_bounding_box_st *bb);
-void dcn20_cap_soc_clocks(
- struct _vcs_dpi_soc_bounding_box_st *bb,
- struct pp_smu_nv_clock_table max_clocks);
-
#endif /* __DC_RESOURCE_DCN20_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c
index 8b6505b7dca8..f50ab961bc17 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_dpp.c
@@ -153,6 +153,9 @@ static void dpp201_cnv_setup(
break;
}
+ /* Set default color space based on format if none is given. */
+ color_space = input_color_space ? input_color_space : color_space;
+
if (is_2bit == 1 && alpha_2bit_lut != NULL) {
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT0, alpha_2bit_lut->lut0);
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT1, alpha_2bit_lut->lut1);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c
index fe22530242d2..05b3fba9ccce 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_hwseq.c
@@ -95,8 +95,6 @@ static void gpu_addr_to_uma(struct dce_hwseq *hwseq,
} else if (hwseq->fb_offset.quad_part <= addr->quad_part &&
addr->quad_part <= hwseq->uma_top.quad_part) {
is_in_uma = true;
- } else if (addr->quad_part == 0) {
- is_in_uma = false;
} else {
is_in_uma = false;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c
index f1f89f93603f..1826dd7f3da1 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn201/dcn201_init.c
@@ -27,6 +27,7 @@
#include "dcn10/dcn10_hw_sequencer.h"
#include "dcn20/dcn20_hwseq.h"
#include "dcn201_hwseq.h"
+#include "dcn201_init.h"
static const struct hw_sequencer_funcs dcn201_funcs = {
.program_gamut_remap = dcn10_program_gamut_remap,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile
index bb8c95141082..0dc06e428999 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn21/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/Makefile
@@ -5,31 +5,6 @@
DCN21 = dcn21_init.o dcn21_hubp.o dcn21_hubbub.o dcn21_resource.o \
dcn21_hwseq.o dcn21_link_encoder.o dcn21_dccg.o
-ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mhard-float -msse
-endif
-
-ifdef CONFIG_PPC64
-CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o += -mpreferred-stack-boundary=4
-else
-CFLAGS_$(AMDDALPATH)/dc/dcn21/dcn21_resource.o += -msse2
-endif
-endif
-
AMD_DAL_DCN21 = $(addprefix $(AMDDALPATH)/dc/dcn21/,$(DCN21))
AMD_DISPLAY_FILES += $(AMD_DAL_DCN21)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
index e5cc6bf45743..faab59508d82 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.c
@@ -34,6 +34,7 @@
#include "resource.h"
#include "include/irq_service_interface.h"
#include "dcn20/dcn20_resource.h"
+#include "dcn21/dcn21_resource.h"
#include "dml/dcn20/dcn20_fpu.h"
@@ -89,230 +90,6 @@
#include "dce/dmub_psr.h"
#include "dce/dmub_abm.h"
-#define DC_LOGGER_INIT(logger)
-
-
-struct _vcs_dpi_ip_params_st dcn2_1_ip = {
- .odm_capable = 1,
- .gpuvm_enable = 1,
- .hostvm_enable = 1,
- .gpuvm_max_page_table_levels = 1,
- .hostvm_max_page_table_levels = 4,
- .hostvm_cached_page_table_levels = 2,
- .num_dsc = 3,
- .rob_buffer_size_kbytes = 168,
- .det_buffer_size_kbytes = 164,
- .dpte_buffer_size_in_pte_reqs_luma = 44,
- .dpte_buffer_size_in_pte_reqs_chroma = 42,//todo
- .dpp_output_buffer_pixels = 2560,
- .opp_output_buffer_lines = 1,
- .pixel_chunk_size_kbytes = 8,
- .pte_enable = 1,
- .max_page_table_levels = 4,
- .pte_chunk_size_kbytes = 2,
- .meta_chunk_size_kbytes = 2,
- .min_meta_chunk_size_bytes = 256,
- .writeback_chunk_size_kbytes = 2,
- .line_buffer_size_bits = 789504,
- .is_line_buffer_bpp_fixed = 0,
- .line_buffer_fixed_bpp = 0,
- .dcc_supported = true,
- .max_line_buffer_lines = 12,
- .writeback_luma_buffer_size_kbytes = 12,
- .writeback_chroma_buffer_size_kbytes = 8,
- .writeback_chroma_line_buffer_width_pixels = 4,
- .writeback_max_hscl_ratio = 1,
- .writeback_max_vscl_ratio = 1,
- .writeback_min_hscl_ratio = 1,
- .writeback_min_vscl_ratio = 1,
- .writeback_max_hscl_taps = 12,
- .writeback_max_vscl_taps = 12,
- .writeback_line_buffer_luma_buffer_size = 0,
- .writeback_line_buffer_chroma_buffer_size = 14643,
- .cursor_buffer_size = 8,
- .cursor_chunk_size = 2,
- .max_num_otg = 4,
- .max_num_dpp = 4,
- .max_num_wb = 1,
- .max_dchub_pscl_bw_pix_per_clk = 4,
- .max_pscl_lb_bw_pix_per_clk = 2,
- .max_lb_vscl_bw_pix_per_clk = 4,
- .max_vscl_hscl_bw_pix_per_clk = 4,
- .max_hscl_ratio = 4,
- .max_vscl_ratio = 4,
- .hscl_mults = 4,
- .vscl_mults = 4,
- .max_hscl_taps = 8,
- .max_vscl_taps = 8,
- .dispclk_ramp_margin_percent = 1,
- .underscan_factor = 1.10,
- .min_vblank_lines = 32, //
- .dppclk_delay_subtotal = 77, //
- .dppclk_delay_scl_lb_only = 16,
- .dppclk_delay_scl = 50,
- .dppclk_delay_cnvc_formatter = 8,
- .dppclk_delay_cnvc_cursor = 6,
- .dispclk_delay_subtotal = 87, //
- .dcfclk_cstate_latency = 10, // SRExitTime
- .max_inter_dcn_tile_repeaters = 8,
-
- .xfc_supported = false,
- .xfc_fill_bw_overhead_percent = 10.0,
- .xfc_fill_constant_bytes = 0,
- .ptoi_supported = 0,
- .number_of_cursors = 1,
-};
-
-struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {
- .clock_limits = {
- {
- .state = 0,
- .dcfclk_mhz = 400.0,
- .fabricclk_mhz = 400.0,
- .dispclk_mhz = 600.0,
- .dppclk_mhz = 400.00,
- .phyclk_mhz = 600.0,
- .socclk_mhz = 278.0,
- .dscclk_mhz = 205.67,
- .dram_speed_mts = 1600.0,
- },
- {
- .state = 1,
- .dcfclk_mhz = 464.52,
- .fabricclk_mhz = 800.0,
- .dispclk_mhz = 654.55,
- .dppclk_mhz = 626.09,
- .phyclk_mhz = 600.0,
- .socclk_mhz = 278.0,
- .dscclk_mhz = 205.67,
- .dram_speed_mts = 1600.0,
- },
- {
- .state = 2,
- .dcfclk_mhz = 514.29,
- .fabricclk_mhz = 933.0,
- .dispclk_mhz = 757.89,
- .dppclk_mhz = 685.71,
- .phyclk_mhz = 600.0,
- .socclk_mhz = 278.0,
- .dscclk_mhz = 287.67,
- .dram_speed_mts = 1866.0,
- },
- {
- .state = 3,
- .dcfclk_mhz = 576.00,
- .fabricclk_mhz = 1067.0,
- .dispclk_mhz = 847.06,
- .dppclk_mhz = 757.89,
- .phyclk_mhz = 600.0,
- .socclk_mhz = 715.0,
- .dscclk_mhz = 318.334,
- .dram_speed_mts = 2134.0,
- },
- {
- .state = 4,
- .dcfclk_mhz = 626.09,
- .fabricclk_mhz = 1200.0,
- .dispclk_mhz = 900.00,
- .dppclk_mhz = 847.06,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 953.0,
- .dscclk_mhz = 489.0,
- .dram_speed_mts = 2400.0,
- },
- {
- .state = 5,
- .dcfclk_mhz = 685.71,
- .fabricclk_mhz = 1333.0,
- .dispclk_mhz = 1028.57,
- .dppclk_mhz = 960.00,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 278.0,
- .dscclk_mhz = 287.67,
- .dram_speed_mts = 2666.0,
- },
- {
- .state = 6,
- .dcfclk_mhz = 757.89,
- .fabricclk_mhz = 1467.0,
- .dispclk_mhz = 1107.69,
- .dppclk_mhz = 1028.57,
- .phyclk_mhz = 810.0,
- .socclk_mhz = 715.0,
- .dscclk_mhz = 318.334,
- .dram_speed_mts = 3200.0,
- },
- {
- .state = 7,
- .dcfclk_mhz = 847.06,
- .fabricclk_mhz = 1600.0,
- .dispclk_mhz = 1395.0,
- .dppclk_mhz = 1285.00,
- .phyclk_mhz = 1325.0,
- .socclk_mhz = 953.0,
- .dscclk_mhz = 489.0,
- .dram_speed_mts = 4266.0,
- },
- /*Extra state, no dispclk ramping*/
- {
- .state = 8,
- .dcfclk_mhz = 847.06,
- .fabricclk_mhz = 1600.0,
- .dispclk_mhz = 1395.0,
- .dppclk_mhz = 1285.0,
- .phyclk_mhz = 1325.0,
- .socclk_mhz = 953.0,
- .dscclk_mhz = 489.0,
- .dram_speed_mts = 4266.0,
- },
-
- },
-
- .sr_exit_time_us = 12.5,
- .sr_enter_plus_exit_time_us = 17.0,
- .urgent_latency_us = 4.0,
- .urgent_latency_pixel_data_only_us = 4.0,
- .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
- .urgent_latency_vm_data_only_us = 4.0,
- .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
- .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
- .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 75.0,
- .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
- .max_avg_sdp_bw_use_normal_percent = 60.0,
- .max_avg_dram_bw_use_normal_percent = 100.0,
- .writeback_latency_us = 12.0,
- .max_request_size_bytes = 256,
- .dram_channel_width_bytes = 4,
- .fabric_datapath_to_dcn_data_return_bytes = 32,
- .dcn_downspread_percent = 0.5,
- .downspread_percent = 0.38,
- .dram_page_open_time_ns = 50.0,
- .dram_rw_turnaround_time_ns = 17.5,
- .dram_return_buffer_per_channel_bytes = 8192,
- .round_trip_ping_latency_dcfclk_cycles = 128,
- .urgent_out_of_order_return_per_channel_bytes = 4096,
- .channel_interleave_bytes = 256,
- .num_banks = 8,
- .num_chans = 4,
- .vmm_page_size_bytes = 4096,
- .dram_clock_change_latency_us = 23.84,
- .return_bus_width_bytes = 64,
- .dispclk_dppclk_vco_speed_mhz = 3600,
- .xfc_bus_transport_time_us = 4,
- .xfc_xbuf_latency_tolerance_us = 4,
- .use_urgent_burst_bw = 1,
- .num_states = 8
-};
-
-#ifndef MAX
-#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-#endif
-#ifndef MIN
-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
-#endif
-
/* begin *********************
* macros to expend register list macro defined in HW object header file */
@@ -705,12 +482,6 @@ static const struct dcn10_stream_encoder_mask se_mask = {
static void dcn21_pp_smu_destroy(struct pp_smu_funcs **pp_smu);
-static int dcn21_populate_dml_pipes_from_context(
- struct dc *dc,
- struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- bool fast_validate);
-
static struct input_pixel_processor *dcn21_ipp_create(
struct dc_context *ctx, uint32_t inst)
{
@@ -873,7 +644,7 @@ static const struct dc_debug_options debug_defaults_drv = {
.clock_trace = true,
.disable_pplib_clock_request = true,
.min_disp_clk_khz = 100000,
- .pipe_split_policy = MPC_SPLIT_DYNAMIC,
+ .pipe_split_policy = MPC_SPLIT_AVOID_MULT_DISP,
.force_single_disp_pipe_split = false,
.disable_dcc = DCC_ENABLE,
.vsr_support = true,
@@ -1029,163 +800,13 @@ static void dcn21_resource_destruct(struct dcn21_resource_pool *pool)
dcn21_pp_smu_destroy(&pool->base.pp_smu);
}
-
-static void calculate_wm_set_for_vlevel(
- int vlevel,
- struct wm_range_table_entry *table_entry,
- struct dcn_watermarks *wm_set,
- struct display_mode_lib *dml,
- display_e2e_pipe_params_st *pipes,
- int pipe_cnt)
-{
- double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us;
-
- ASSERT(vlevel < dml->soc.num_states);
- /* only pipe 0 is read for voltage and dcf/soc clocks */
- pipes[0].clks_cfg.voltage = vlevel;
- pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz;
- pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz;
-
- dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us;
- dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us;
- dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us;
-
- wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000;
- wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000;
- wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000;
- wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000;
- wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000;
- wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000;
- wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000;
- wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000;
- dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached;
-
-}
-
-static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb)
-{
- int i;
-
- if (dc->bb_overrides.sr_exit_time_ns) {
- for (i = 0; i < WM_SET_COUNT; i++) {
- dc->clk_mgr->bw_params->wm_table.entries[i].sr_exit_time_us =
- dc->bb_overrides.sr_exit_time_ns / 1000.0;
- }
- }
-
- if (dc->bb_overrides.sr_enter_plus_exit_time_ns) {
- for (i = 0; i < WM_SET_COUNT; i++) {
- dc->clk_mgr->bw_params->wm_table.entries[i].sr_enter_plus_exit_time_us =
- dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
- }
- }
-
- if (dc->bb_overrides.urgent_latency_ns) {
- bb->urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0;
- }
-
- if (dc->bb_overrides.dram_clock_change_latency_ns) {
- for (i = 0; i < WM_SET_COUNT; i++) {
- dc->clk_mgr->bw_params->wm_table.entries[i].pstate_latency_us =
- dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
- }
- }
-}
-
-static void dcn21_calculate_wm(
- struct dc *dc, struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- int *out_pipe_cnt,
- int *pipe_split_from,
- int vlevel_req,
- bool fast_validate)
-{
- int pipe_cnt, i, pipe_idx;
- int vlevel, vlevel_max;
- struct wm_range_table_entry *table_entry;
- struct clk_bw_params *bw_params = dc->clk_mgr->bw_params;
-
- ASSERT(bw_params);
-
- patch_bounding_box(dc, &context->bw_ctx.dml.soc);
-
- for (i = 0, pipe_idx = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
- if (!context->res_ctx.pipe_ctx[i].stream)
- continue;
-
- pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0;
- pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.vba.RequiredDISPCLK[vlevel_req][context->bw_ctx.dml.vba.maxMpcComb];
-
- if (pipe_split_from[i] < 0) {
- pipes[pipe_cnt].clks_cfg.dppclk_mhz =
- context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel_req][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx];
- if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_idx] == pipe_idx)
- pipes[pipe_cnt].pipe.dest.odm_combine =
- context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel_req][pipe_idx];
- else
- pipes[pipe_cnt].pipe.dest.odm_combine = 0;
- pipe_idx++;
- } else {
- pipes[pipe_cnt].clks_cfg.dppclk_mhz =
- context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel_req][context->bw_ctx.dml.vba.maxMpcComb][pipe_split_from[i]];
- if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_split_from[i]] == pipe_split_from[i])
- pipes[pipe_cnt].pipe.dest.odm_combine =
- context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel_req][pipe_split_from[i]];
- else
- pipes[pipe_cnt].pipe.dest.odm_combine = 0;
- }
- pipe_cnt++;
- }
-
- if (pipe_cnt != pipe_idx) {
- if (dc->res_pool->funcs->populate_dml_pipes)
- pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc,
- context, pipes, fast_validate);
- else
- pipe_cnt = dcn21_populate_dml_pipes_from_context(dc,
- context, pipes, fast_validate);
- }
-
- *out_pipe_cnt = pipe_cnt;
-
- vlevel_max = bw_params->clk_table.num_entries - 1;
-
-
- /* WM Set D */
- table_entry = &bw_params->wm_table.entries[WM_D];
- if (table_entry->wm_type == WM_TYPE_RETRAINING)
- vlevel = 0;
- else
- vlevel = vlevel_max;
- calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d,
- &context->bw_ctx.dml, pipes, pipe_cnt);
- /* WM Set C */
- table_entry = &bw_params->wm_table.entries[WM_C];
- vlevel = MIN(MAX(vlevel_req, 3), vlevel_max);
- calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c,
- &context->bw_ctx.dml, pipes, pipe_cnt);
- /* WM Set B */
- table_entry = &bw_params->wm_table.entries[WM_B];
- vlevel = MIN(MAX(vlevel_req, 2), vlevel_max);
- calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b,
- &context->bw_ctx.dml, pipes, pipe_cnt);
-
- /* WM Set A */
- table_entry = &bw_params->wm_table.entries[WM_A];
- vlevel = MIN(vlevel_req, vlevel_max);
- calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a,
- &context->bw_ctx.dml, pipes, pipe_cnt);
-}
-
-
-static bool dcn21_fast_validate_bw(
- struct dc *dc,
- struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- int *pipe_cnt_out,
- int *pipe_split_from,
- int *vlevel_out,
- bool fast_validate)
+bool dcn21_fast_validate_bw(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int *pipe_cnt_out,
+ int *pipe_split_from,
+ int *vlevel_out,
+ bool fast_validate)
{
bool out = false;
int split[MAX_PIPES] = { 0 };
@@ -1197,7 +818,9 @@ static bool dcn21_fast_validate_bw(
dcn20_merge_pipes_for_validate(dc, context);
+ DC_FP_START();
pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc, context, pipes, fast_validate);
+ DC_FP_END();
*pipe_cnt_out = pipe_cnt;
@@ -1287,7 +910,9 @@ static bool dcn21_fast_validate_bw(
hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe);
ASSERT(hsplit_pipe);
if (!hsplit_pipe) {
- context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx] *= 2;
+ DC_FP_START();
+ dcn20_fpu_adjust_dppclk(&context->bw_ctx.dml.vba, vlevel, context->bw_ctx.dml.vba.maxMpcComb, pipe_idx, true);
+ DC_FP_END();
continue;
}
if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) {
@@ -1329,61 +954,6 @@ validate_out:
return out;
}
-static noinline bool dcn21_validate_bandwidth_fp(struct dc *dc,
- struct dc_state *context, bool fast_validate)
-{
- bool out = false;
-
- BW_VAL_TRACE_SETUP();
-
- int vlevel = 0;
- int pipe_split_from[MAX_PIPES];
- int pipe_cnt = 0;
- display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
- DC_LOGGER_INIT(dc->ctx->logger);
-
- BW_VAL_TRACE_COUNT();
-
- /*Unsafe due to current pipe merge and split logic*/
- ASSERT(context != dc->current_state);
-
- out = dcn21_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel, fast_validate);
-
- if (pipe_cnt == 0)
- goto validate_out;
-
- if (!out)
- goto validate_fail;
-
- BW_VAL_TRACE_END_VOLTAGE_LEVEL();
-
- if (fast_validate) {
- BW_VAL_TRACE_SKIP(fast);
- goto validate_out;
- }
-
- dcn21_calculate_wm(dc, context, pipes, &pipe_cnt, pipe_split_from, vlevel, fast_validate);
- dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
-
- BW_VAL_TRACE_END_WATERMARKS();
-
- goto validate_out;
-
-validate_fail:
- DC_LOG_WARNING("Mode Validation Warning: %s failed validation.\n",
- dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states]));
-
- BW_VAL_TRACE_SKIP(fail);
- out = false;
-
-validate_out:
- kfree(pipes);
-
- BW_VAL_TRACE_FINISH();
-
- return out;
-}
-
/*
* Some of the functions further below use the FPU, so we need to wrap this
* with DC_FP_START()/DC_FP_END(). Use the same approach as for
@@ -1427,6 +997,7 @@ static struct clock_source *dcn21_clock_source_create(
return &clk_src->base;
}
+ kfree(clk_src);
BREAK_TO_DEBUGGER();
return NULL;
}
@@ -1558,94 +1129,6 @@ static struct display_stream_compressor *dcn21_dsc_create(struct dc_context *ctx
return &dsc->base;
}
-static struct _vcs_dpi_voltage_scaling_st construct_low_pstate_lvl(struct clk_limit_table *clk_table, unsigned int high_voltage_lvl)
-{
- struct _vcs_dpi_voltage_scaling_st low_pstate_lvl;
- int i;
-
- low_pstate_lvl.state = 1;
- low_pstate_lvl.dcfclk_mhz = clk_table->entries[0].dcfclk_mhz;
- low_pstate_lvl.fabricclk_mhz = clk_table->entries[0].fclk_mhz;
- low_pstate_lvl.socclk_mhz = clk_table->entries[0].socclk_mhz;
- low_pstate_lvl.dram_speed_mts = clk_table->entries[0].memclk_mhz * 2;
-
- low_pstate_lvl.dispclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dispclk_mhz;
- low_pstate_lvl.dppclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dppclk_mhz;
- low_pstate_lvl.dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[high_voltage_lvl].dram_bw_per_chan_gbps;
- low_pstate_lvl.dscclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dscclk_mhz;
- low_pstate_lvl.dtbclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dtbclk_mhz;
- low_pstate_lvl.phyclk_d18_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].phyclk_d18_mhz;
- low_pstate_lvl.phyclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].phyclk_mhz;
-
- for (i = clk_table->num_entries; i > 1; i--)
- clk_table->entries[i] = clk_table->entries[i-1];
- clk_table->entries[1] = clk_table->entries[0];
- clk_table->num_entries++;
-
- return low_pstate_lvl;
-}
-
-static void update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
-{
- struct dcn21_resource_pool *pool = TO_DCN21_RES_POOL(dc->res_pool);
- struct clk_limit_table *clk_table = &bw_params->clk_table;
- struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES];
- unsigned int i, closest_clk_lvl = 0, k = 0;
- int j;
-
- dcn2_1_ip.max_num_otg = pool->base.res_cap->num_timing_generator;
- dcn2_1_ip.max_num_dpp = pool->base.pipe_count;
- dcn2_1_soc.num_chans = bw_params->num_channels;
-
- ASSERT(clk_table->num_entries);
- /* Copy dcn2_1_soc.clock_limits to clock_limits to avoid copying over null states later */
- for (i = 0; i < dcn2_1_soc.num_states + 1; i++) {
- clock_limits[i] = dcn2_1_soc.clock_limits[i];
- }
-
- for (i = 0; i < clk_table->num_entries; i++) {
- /* loop backwards*/
- for (closest_clk_lvl = 0, j = dcn2_1_soc.num_states - 1; j >= 0; j--) {
- if ((unsigned int) dcn2_1_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {
- closest_clk_lvl = j;
- break;
- }
- }
-
- /* clk_table[1] is reserved for min DF PState. skip here to fill in later. */
- if (i == 1)
- k++;
-
- clock_limits[k].state = k;
- clock_limits[k].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz;
- clock_limits[k].fabricclk_mhz = clk_table->entries[i].fclk_mhz;
- clock_limits[k].socclk_mhz = clk_table->entries[i].socclk_mhz;
- clock_limits[k].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2;
-
- clock_limits[k].dispclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz;
- clock_limits[k].dppclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz;
- clock_limits[k].dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps;
- clock_limits[k].dscclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz;
- clock_limits[k].dtbclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz;
- clock_limits[k].phyclk_d18_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz;
- clock_limits[k].phyclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz;
-
- k++;
- }
- for (i = 0; i < clk_table->num_entries + 1; i++)
- dcn2_1_soc.clock_limits[i] = clock_limits[i];
- if (clk_table->num_entries) {
- dcn2_1_soc.num_states = clk_table->num_entries + 1;
- /* fill in min DF PState */
- dcn2_1_soc.clock_limits[1] = construct_low_pstate_lvl(clk_table, closest_clk_lvl);
- /* duplicate last level */
- dcn2_1_soc.clock_limits[dcn2_1_soc.num_states] = dcn2_1_soc.clock_limits[dcn2_1_soc.num_states - 1];
- dcn2_1_soc.clock_limits[dcn2_1_soc.num_states].state = dcn2_1_soc.num_states;
- }
-
- dml_init_instance(&dc->dml, &dcn2_1_soc, &dcn2_1_ip, DML_PROJECT_DCN21);
-}
-
static struct pp_smu_funcs *dcn21_pp_smu_create(struct dc_context *ctx)
{
struct pp_smu_funcs *pp_smu = kzalloc(sizeof(*pp_smu), GFP_KERNEL);
@@ -1896,24 +1379,6 @@ static uint32_t read_pipe_fuses(struct dc_context *ctx)
return value;
}
-static int dcn21_populate_dml_pipes_from_context(
- struct dc *dc,
- struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- bool fast_validate)
-{
- uint32_t pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
- int i;
-
- for (i = 0; i < pipe_cnt; i++) {
-
- pipes[i].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active;
- pipes[i].pipe.src.gpuvm = 1;
- }
-
- return pipe_cnt;
-}
-
static enum dc_status dcn21_patch_unknown_plane_state(struct dc_plane_state *plane_state)
{
enum dc_status result = DC_OK;
@@ -1941,7 +1406,7 @@ static const struct resource_funcs dcn21_res_pool_funcs = {
.patch_unknown_plane_state = dcn21_patch_unknown_plane_state,
.set_mcif_arb_params = dcn20_set_mcif_arb_params,
.find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
- .update_bw_bounding_box = update_bw_bounding_box
+ .update_bw_bounding_box = dcn21_update_bw_bounding_box,
};
static bool dcn21_resource_construct(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h
index a27355171bca..f7ecc002c2f7 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn21/dcn21_resource.h
@@ -35,11 +35,22 @@ struct dc;
struct resource_pool;
struct _vcs_dpi_display_pipe_params_st;
+extern struct _vcs_dpi_ip_params_st dcn2_1_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc;
+
struct dcn21_resource_pool {
struct resource_pool base;
};
struct resource_pool *dcn21_create_resource_pool(
const struct dc_init_data *init_data,
struct dc *dc);
+bool dcn21_fast_validate_bw(
+ struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int *pipe_cnt_out,
+ int *pipe_split_from,
+ int *vlevel_out,
+ bool fast_validate);
#endif /* _DCN21_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h
index e2c264ecb20f..42140e73c3b2 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dio_stream_encoder.h
@@ -95,6 +95,8 @@
SRI(DP_VID_STREAM_CNTL, DP, id), \
SRI(DP_VID_TIMING, DP, id), \
SRI(DP_SEC_AUD_N, DP, id), \
+ SRI(DP_SEC_AUD_N_READBACK, DP, id), \
+ SRI(DP_SEC_AUD_M_READBACK, DP, id), \
SRI(DP_SEC_TIMESTAMP, DP, id), \
SRI(DP_DSC_CNTL, DP, id), \
SRI(DP_DSC_BYTES_PER_PIXEL, DP, id), \
@@ -157,6 +159,8 @@
SE_SF(DIG0_HDMI_ACR_48_0, HDMI_ACR_CTS_48, mask_sh),\
SE_SF(DIG0_HDMI_ACR_48_1, HDMI_ACR_N_48, mask_sh),\
SE_SF(DP0_DP_SEC_AUD_N, DP_SEC_AUD_N, mask_sh),\
+ SE_SF(DP0_DP_SEC_AUD_N_READBACK, DP_SEC_AUD_N_READBACK, mask_sh),\
+ SE_SF(DP0_DP_SEC_AUD_M_READBACK, DP_SEC_AUD_M_READBACK, mask_sh),\
SE_SF(DP0_DP_SEC_TIMESTAMP, DP_SEC_TIMESTAMP_MODE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ASP_ENABLE, mask_sh),\
SE_SF(DP0_DP_SEC_CNTL, DP_SEC_ATP_ENABLE, mask_sh),\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c
index ab3918c0a15b..0dcc07531643 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp.c
@@ -294,6 +294,9 @@ static void dpp3_cnv_setup (
break;
}
+ /* Set default color space based on format if none is given. */
+ color_space = input_color_space ? input_color_space : color_space;
+
if (is_2bit == 1 && alpha_2bit_lut != NULL) {
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT0, alpha_2bit_lut->lut0);
REG_UPDATE(ALPHA_2BIT_LUT, ALPHA_2BIT_LUT1, alpha_2bit_lut->lut1);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c
index 387eec616162..87dbeca18984 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_dpp_cm.c
@@ -408,6 +408,6 @@ void dpp3_cm_set_gamut_remap(
gamut_mode = 1;
//follow dcn2 approach for now - using only coefficient set A
- program_gamut_remap(dpp, arr_reg_val, GAMUT_REMAP_COEFF);
+ program_gamut_remap(dpp, arr_reg_val, gamut_mode);
}
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c
index f4414de96acc..152c9c5733f1 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c
@@ -448,6 +448,7 @@ static const struct hubbub_funcs hubbub30_funcs = {
.program_watermarks = hubbub3_program_watermarks,
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
+ .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
.force_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes,
.force_pstate_change_control = hubbub3_force_pstate_change_control,
.init_watermarks = hubbub3_init_watermarks,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
index 1db1ca19411d..782b8db451b4 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hwseq.c
@@ -535,8 +535,12 @@ void dcn30_init_hw(struct dc *dc)
/* Check for enabled DIG to identify enabled display */
if (link->link_enc->funcs->is_dig_enabled &&
- link->link_enc->funcs->is_dig_enabled(link->link_enc))
+ link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
link->link_status.link_active = true;
+ if (link->link_enc->funcs->fec_is_active &&
+ link->link_enc->funcs->fec_is_active(link->link_enc))
+ link->fec_state = dc_link_fec_enabled;
+ }
}
/* Power gate DSCs */
@@ -545,8 +549,10 @@ void dcn30_init_hw(struct dc *dc)
hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
/* we want to turn off all dp displays before doing detection */
- if (dc->config.power_down_display_on_boot)
- dc_link_blank_all_dp_displays(dc);
+ dc_link_blank_all_dp_displays(dc);
+
+ if (hws->funcs.enable_power_gating_plane)
+ hws->funcs.enable_power_gating_plane(dc->hwseq, true);
/* If taking control over from VBIOS, we may want to optimize our first
* mode set, so we need to skip powering down pipes until we know which
@@ -554,7 +560,7 @@ void dcn30_init_hw(struct dc *dc)
* Otherwise, if taking control is not possible, we need to power
* everything down.
*/
- if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) {
+ if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
hws->funcs.init_pipes(dc, dc->current_state);
if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
@@ -566,7 +572,7 @@ void dcn30_init_hw(struct dc *dc)
* To avoid this, power down hardware on boot
* if DIG is turned on and seamless boot not enabled
*/
- if (dc->config.power_down_display_on_boot) {
+ if (!dc->config.seamless_boot_edp_requested) {
struct dc_link *edp_links[MAX_NUM_EDP];
struct dc_link *edp_link = NULL;
@@ -625,8 +631,6 @@ void dcn30_init_hw(struct dc *dc)
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
}
- if (hws->funcs.enable_power_gating_plane)
- hws->funcs.enable_power_gating_plane(dc->hwseq, true);
if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h
index b7dc78624963..34b9cedbd012 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_mpc.h
@@ -99,11 +99,6 @@
SRII(MPCC_OGAM_CONTROL, MPCC_OGAM, inst),\
SRII(MPCC_OGAM_LUT_CONTROL, MPCC_OGAM, inst)
-/*
- SRII(MPCC_OGAM_LUT_RAM_CONTROL, MPCC_OGAM, inst),\
- SRII(MPCC_OGAM_MODE, MPCC_OGAM, inst)
-*/
-
#define MPC_OUT_MUX_REG_LIST_DCN3_0(inst) \
MPC_OUT_MUX_COMMON_REG_LIST_DCN1_0(inst),\
SRII(CSC_MODE, MPC_OUT, inst),\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
index f5e8916601d3..b604fb26f288 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
@@ -28,6 +28,8 @@
#include "dc.h"
#include "dcn_calc_math.h"
+#include "dml/dcn30/dcn30_fpu.h"
+
#define REG(reg)\
optc1->tg_regs->reg
@@ -184,6 +186,14 @@ void optc3_set_dsc_config(struct timing_generator *optc,
}
+void optc3_set_vrr_m_const(struct timing_generator *optc,
+ double vtotal_avg)
+{
+ DC_FP_START();
+ optc3_fpu_set_vrr_m_const(optc, vtotal_avg);
+ DC_FP_END();
+}
+
void optc3_set_odm_bypass(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing)
{
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h
index 736e63bc80c2..97f11ef6e9f0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.h
@@ -344,5 +344,5 @@ void optc3_set_timing_db_mode(struct timing_generator *optc, bool enable);
void optc3_set_odm_bypass(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing);
void optc3_tg_init(struct timing_generator *optc);
-
+void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max);
#endif /* __DC_OPTC_DCN30_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
index 8ca26383b568..1c1a67c4cec1 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.c
@@ -72,8 +72,8 @@
#include "nbio/nbio_7_4_offset.h"
-#include "dcn/dpcs_3_0_0_offset.h"
-#include "dcn/dpcs_3_0_0_sh_mask.h"
+#include "dpcs/dpcs_3_0_0_offset.h"
+#include "dpcs/dpcs_3_0_0_sh_mask.h"
#include "mmhub/mmhub_2_0_0_offset.h"
#include "mmhub/mmhub_2_0_0_sh_mask.h"
@@ -84,6 +84,7 @@
#include "dce/dce_aux.h"
#include "dce/dce_i2c.h"
+#include "dml/dcn30/dcn30_fpu.h"
#include "dml/dcn30/display_mode_vba_30.h"
#include "vm_helper.h"
#include "dcn20/dcn20_vmid.h"
@@ -91,137 +92,6 @@
#define DC_LOGGER_INIT(logger)
-struct _vcs_dpi_ip_params_st dcn3_0_ip = {
- .use_min_dcfclk = 0,
- .clamp_min_dcfclk = 0,
- .odm_capable = 1,
- .gpuvm_enable = 0,
- .hostvm_enable = 0,
- .gpuvm_max_page_table_levels = 4,
- .hostvm_max_page_table_levels = 4,
- .hostvm_cached_page_table_levels = 0,
- .pte_group_size_bytes = 2048,
- .num_dsc = 6,
- .rob_buffer_size_kbytes = 184,
- .det_buffer_size_kbytes = 184,
- .dpte_buffer_size_in_pte_reqs_luma = 84,
- .pde_proc_buffer_size_64k_reqs = 48,
- .dpp_output_buffer_pixels = 2560,
- .opp_output_buffer_lines = 1,
- .pixel_chunk_size_kbytes = 8,
- .pte_enable = 1,
- .max_page_table_levels = 2,
- .pte_chunk_size_kbytes = 2, // ?
- .meta_chunk_size_kbytes = 2,
- .writeback_chunk_size_kbytes = 8,
- .line_buffer_size_bits = 789504,
- .is_line_buffer_bpp_fixed = 0, // ?
- .line_buffer_fixed_bpp = 0, // ?
- .dcc_supported = true,
- .writeback_interface_buffer_size_kbytes = 90,
- .writeback_line_buffer_buffer_size = 0,
- .max_line_buffer_lines = 12,
- .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640
- .writeback_chroma_buffer_size_kbytes = 8,
- .writeback_chroma_line_buffer_width_pixels = 4,
- .writeback_max_hscl_ratio = 1,
- .writeback_max_vscl_ratio = 1,
- .writeback_min_hscl_ratio = 1,
- .writeback_min_vscl_ratio = 1,
- .writeback_max_hscl_taps = 1,
- .writeback_max_vscl_taps = 1,
- .writeback_line_buffer_luma_buffer_size = 0,
- .writeback_line_buffer_chroma_buffer_size = 14643,
- .cursor_buffer_size = 8,
- .cursor_chunk_size = 2,
- .max_num_otg = 6,
- .max_num_dpp = 6,
- .max_num_wb = 1,
- .max_dchub_pscl_bw_pix_per_clk = 4,
- .max_pscl_lb_bw_pix_per_clk = 2,
- .max_lb_vscl_bw_pix_per_clk = 4,
- .max_vscl_hscl_bw_pix_per_clk = 4,
- .max_hscl_ratio = 6,
- .max_vscl_ratio = 6,
- .hscl_mults = 4,
- .vscl_mults = 4,
- .max_hscl_taps = 8,
- .max_vscl_taps = 8,
- .dispclk_ramp_margin_percent = 1,
- .underscan_factor = 1.11,
- .min_vblank_lines = 32,
- .dppclk_delay_subtotal = 46,
- .dynamic_metadata_vm_enabled = true,
- .dppclk_delay_scl_lb_only = 16,
- .dppclk_delay_scl = 50,
- .dppclk_delay_cnvc_formatter = 27,
- .dppclk_delay_cnvc_cursor = 6,
- .dispclk_delay_subtotal = 119,
- .dcfclk_cstate_latency = 5.2, // SRExitTime
- .max_inter_dcn_tile_repeaters = 8,
- .odm_combine_4to1_supported = true,
-
- .xfc_supported = false,
- .xfc_fill_bw_overhead_percent = 10.0,
- .xfc_fill_constant_bytes = 0,
- .gfx7_compat_tiling_supported = 0,
- .number_of_cursors = 1,
-};
-
-struct _vcs_dpi_soc_bounding_box_st dcn3_0_soc = {
- .clock_limits = {
- {
- .state = 0,
- .dispclk_mhz = 562.0,
- .dppclk_mhz = 300.0,
- .phyclk_mhz = 300.0,
- .phyclk_d18_mhz = 667.0,
- .dscclk_mhz = 405.6,
- },
- },
- .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */
- .num_states = 1,
- .sr_exit_time_us = 15.5,
- .sr_enter_plus_exit_time_us = 20,
- .urgent_latency_us = 4.0,
- .urgent_latency_pixel_data_only_us = 4.0,
- .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
- .urgent_latency_vm_data_only_us = 4.0,
- .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
- .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
- .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
- .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
- .max_avg_sdp_bw_use_normal_percent = 60.0,
- .max_avg_dram_bw_use_normal_percent = 40.0,
- .writeback_latency_us = 12.0,
- .max_request_size_bytes = 256,
- .fabric_datapath_to_dcn_data_return_bytes = 64,
- .dcn_downspread_percent = 0.5,
- .downspread_percent = 0.38,
- .dram_page_open_time_ns = 50.0,
- .dram_rw_turnaround_time_ns = 17.5,
- .dram_return_buffer_per_channel_bytes = 8192,
- .round_trip_ping_latency_dcfclk_cycles = 191,
- .urgent_out_of_order_return_per_channel_bytes = 4096,
- .channel_interleave_bytes = 256,
- .num_banks = 8,
- .gpuvm_min_page_size_bytes = 4096,
- .hostvm_min_page_size_bytes = 4096,
- .dram_clock_change_latency_us = 404,
- .dummy_pstate_latency_us = 5,
- .writeback_dram_clock_change_latency_us = 23.0,
- .return_bus_width_bytes = 64,
- .dispclk_dppclk_vco_speed_mhz = 3650,
- .xfc_bus_transport_time_us = 20, // ?
- .xfc_xbuf_latency_tolerance_us = 4, // ?
- .use_urgent_burst_bw = 1, // ?
- .do_urgent_latency_adjustment = true,
- .urgent_latency_adjustment_fabric_clock_component_us = 1.0,
- .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
-};
-
enum dcn30_clk_src_array_id {
DCN30_CLK_SRC_PLL0,
DCN30_CLK_SRC_PLL1,
@@ -1462,7 +1332,9 @@ int dcn30_populate_dml_pipes_from_context(
int i, pipe_cnt;
struct resource_context *res_ctx = &context->res_ctx;
+ DC_FP_START();
dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ DC_FP_END();
for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
if (!res_ctx->pipe_ctx[i].stream)
@@ -1478,90 +1350,9 @@ int dcn30_populate_dml_pipes_from_context(
void dcn30_populate_dml_writeback_from_context(
struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes)
{
- int pipe_cnt, i, j;
- double max_calc_writeback_dispclk;
- double writeback_dispclk;
- struct writeback_st dout_wb;
-
- for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
- struct dc_stream_state *stream = res_ctx->pipe_ctx[i].stream;
-
- if (!stream)
- continue;
- max_calc_writeback_dispclk = 0;
-
- /* Set writeback information */
- pipes[pipe_cnt].dout.wb_enable = 0;
- pipes[pipe_cnt].dout.num_active_wb = 0;
- for (j = 0; j < stream->num_wb_info; j++) {
- struct dc_writeback_info *wb_info = &stream->writeback_info[j];
-
- if (wb_info->wb_enabled && wb_info->writeback_source_plane &&
- (wb_info->writeback_source_plane == res_ctx->pipe_ctx[i].plane_state)) {
- pipes[pipe_cnt].dout.wb_enable = 1;
- pipes[pipe_cnt].dout.num_active_wb++;
- dout_wb.wb_src_height = wb_info->dwb_params.cnv_params.crop_en ?
- wb_info->dwb_params.cnv_params.crop_height :
- wb_info->dwb_params.cnv_params.src_height;
- dout_wb.wb_src_width = wb_info->dwb_params.cnv_params.crop_en ?
- wb_info->dwb_params.cnv_params.crop_width :
- wb_info->dwb_params.cnv_params.src_width;
- dout_wb.wb_dst_width = wb_info->dwb_params.dest_width;
- dout_wb.wb_dst_height = wb_info->dwb_params.dest_height;
-
- /* For IP that doesn't support WB scaling, set h/v taps to 1 to avoid DML validation failure */
- if (dc->dml.ip.writeback_max_hscl_taps > 1) {
- dout_wb.wb_htaps_luma = wb_info->dwb_params.scaler_taps.h_taps;
- dout_wb.wb_vtaps_luma = wb_info->dwb_params.scaler_taps.v_taps;
- } else {
- dout_wb.wb_htaps_luma = 1;
- dout_wb.wb_vtaps_luma = 1;
- }
- dout_wb.wb_htaps_chroma = 0;
- dout_wb.wb_vtaps_chroma = 0;
- dout_wb.wb_hratio = wb_info->dwb_params.cnv_params.crop_en ?
- (double)wb_info->dwb_params.cnv_params.crop_width /
- (double)wb_info->dwb_params.dest_width :
- (double)wb_info->dwb_params.cnv_params.src_width /
- (double)wb_info->dwb_params.dest_width;
- dout_wb.wb_vratio = wb_info->dwb_params.cnv_params.crop_en ?
- (double)wb_info->dwb_params.cnv_params.crop_height /
- (double)wb_info->dwb_params.dest_height :
- (double)wb_info->dwb_params.cnv_params.src_height /
- (double)wb_info->dwb_params.dest_height;
- if (wb_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_ARGB ||
- wb_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_RGBA)
- dout_wb.wb_pixel_format = dm_444_64;
- else
- dout_wb.wb_pixel_format = dm_444_32;
-
- /* Workaround for cases where multiple writebacks are connected to same plane
- * In which case, need to compute worst case and set the associated writeback parameters
- * This workaround is necessary due to DML computation assuming only 1 set of writeback
- * parameters per pipe
- */
- writeback_dispclk = dml30_CalculateWriteBackDISPCLK(
- dout_wb.wb_pixel_format,
- pipes[pipe_cnt].pipe.dest.pixel_rate_mhz,
- dout_wb.wb_hratio,
- dout_wb.wb_vratio,
- dout_wb.wb_htaps_luma,
- dout_wb.wb_vtaps_luma,
- dout_wb.wb_src_width,
- dout_wb.wb_dst_width,
- pipes[pipe_cnt].pipe.dest.htotal,
- dc->current_state->bw_ctx.dml.ip.writeback_line_buffer_buffer_size);
-
- if (writeback_dispclk > max_calc_writeback_dispclk) {
- max_calc_writeback_dispclk = writeback_dispclk;
- pipes[pipe_cnt].dout.wb = dout_wb;
- }
- }
- }
-
- pipe_cnt++;
- }
-
+ DC_FP_START();
+ dcn30_fpu_populate_dml_writeback_from_context(dc, res_ctx, pipes);
+ DC_FP_END();
}
unsigned int dcn30_calc_max_scaled_time(
@@ -1596,7 +1387,7 @@ void dcn30_set_mcif_arb_params(
enum mmhubbub_wbif_mode wbif_mode;
struct display_mode_lib *dml = &context->bw_ctx.dml;
struct mcif_arb_params *wb_arb_params;
- int i, j, k, dwb_pipe;
+ int i, j, dwb_pipe;
/* Writeback MCIF_WB arbitration parameters */
dwb_pipe = 0;
@@ -1620,17 +1411,15 @@ void dcn30_set_mcif_arb_params(
else
wbif_mode = PACKED_444;
- for (k = 0; k < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); k++) {
- wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(dml, pipes, pipe_cnt) * 1000;
- wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(dml, pipes, pipe_cnt) * 1000;
- }
+ DC_FP_START();
+ dcn30_fpu_set_mcif_arb_params(wb_arb_params, dml, pipes, pipe_cnt, j);
+ DC_FP_END();
wb_arb_params->time_per_pixel = (1000000 << 6) / context->res_ctx.pipe_ctx[i].stream->phy_pix_clk; /* time_per_pixel should be in u6.6 format */
wb_arb_params->slice_lines = 32;
wb_arb_params->arbitration_slice = 2; /* irrelevant since there is no YUV output */
wb_arb_params->max_scaled_time = dcn30_calc_max_scaled_time(wb_arb_params->time_per_pixel,
wbif_mode,
wb_arb_params->cli_watermark[0]); /* assume 4 watermark sets have the same value */
- wb_arb_params->dram_speed_change_duration = dml->vba.WritebackAllowDRAMClockChangeEndPosition[j] * pipes[0].clks_cfg.refclk_mhz; /* num_clock_cycles = us * MHz */
dwb_pipe++;
@@ -1731,7 +1520,10 @@ static bool init_soc_bounding_box(struct dc *dc,
loaded_ip->max_num_otg = pool->base.res_cap->num_timing_generator;
loaded_ip->max_num_dpp = pool->base.pipe_count;
loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk;
+
+ DC_FP_START();
dcn20_patch_bounding_box(dc, loaded_bb);
+ DC_FP_END();
if (dc->ctx->dc_bios->funcs->get_soc_bb_info) {
struct bp_soc_bb_info bb_info = {0};
@@ -2106,176 +1898,11 @@ validate_out:
return out;
}
-/*
- * This must be noinline to ensure anything that deals with FP registers
- * is contained within this call; previously our compiling with hard-float
- * would result in fp instructions being emitted outside of the boundaries
- * of the DC_FP_START/END macros, which makes sense as the compiler has no
- * idea about what is wrapped and what is not
- *
- * This is largely just a workaround to avoid breakage introduced with 5.6,
- * ideally all fp-using code should be moved into its own file, only that
- * should be compiled with hard-float, and all code exported from there
- * should be strictly wrapped with DC_FP_START/END
- */
-static noinline void dcn30_calculate_wm_and_dlg_fp(
- struct dc *dc, struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- int pipe_cnt,
- int vlevel)
-{
- int maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb;
- int i, pipe_idx;
- double dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][maxMpcComb];
- bool pstate_en = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] != dm_dram_clock_change_unsupported;
-
- if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk)
- dcfclk = context->bw_ctx.dml.soc.min_dcfclk;
-
- pipes[0].clks_cfg.voltage = vlevel;
- pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
- pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
-
- /* Set B:
- * DCFCLK: 1GHz or min required above 1GHz
- * FCLK/UCLK: Max
- */
- if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid) {
- if (vlevel == 0) {
- pipes[0].clks_cfg.voltage = 1;
- pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dcfclk_mhz;
- }
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us;
- context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us;
- context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us;
- }
- context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
- pipes[0].clks_cfg.voltage = vlevel;
- pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
-
- /* Set D:
- * DCFCLK: Min Required
- * FCLK(proportional to UCLK): 1GHz or Max
- * MALL stutter, sr_enter_exit = 4, sr_exit = 2us
- */
- /*
- if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].valid) {
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us;
- context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us;
- context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us;
- }
- context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- */
-
- /* Set C:
- * DCFCLK: Min Required
- * FCLK(proportional to UCLK): 1GHz or Max
- * pstate latency overridden to 5us
- */
- if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) {
- unsigned int min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed;
- unsigned int min_dram_speed_mts_margin = 160;
-
- if (context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] == dm_dram_clock_change_unsupported)
- min_dram_speed_mts = dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz * 16;
-
- /* find largest table entry that is lower than dram speed, but lower than DPM0 still uses DPM0 */
- for (i = 3; i > 0; i--)
- if (min_dram_speed_mts + min_dram_speed_mts_margin > dc->clk_mgr->bw_params->dummy_pstate_table[i].dram_speed_mts)
- break;
-
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->dummy_pstate_table[i].dummy_pstate_latency_us;
- context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us;
- context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us;
- }
-
- context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
- if (!pstate_en) {
- /* The only difference between A and C is p-state latency, if p-state is not supported we want to
- * calculate DLG based on dummy p-state latency, and max out the set A p-state watermark
- */
- context->bw_ctx.bw.dcn.watermarks.a = context->bw_ctx.bw.dcn.watermarks.c;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 0;
- } else {
- /* Set A:
- * DCFCLK: Min Required
- * FCLK(proportional to UCLK): 1GHz or Max
- *
- * Set A calculated last so that following calculations are based on Set A
- */
- dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
- context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- }
-
- context->perf_params.stutter_period_us = context->bw_ctx.dml.vba.StutterPeriod;
-
- /* Make set D = set A until set D is enabled */
- context->bw_ctx.bw.dcn.watermarks.d = context->bw_ctx.bw.dcn.watermarks.a;
-
- for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
- if (!context->res_ctx.pipe_ctx[i].stream)
- continue;
-
- pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
- pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
-
- if (dc->config.forced_clocks) {
- pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
- pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
- }
- if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000)
- pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
- if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
- pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
-
- pipe_idx++;
- }
-
- dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
-
- if (!pstate_en)
- /* Restore full p-state latency */
- context->bw_ctx.dml.soc.dram_clock_change_latency_us =
- dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
-}
-
void dcn30_update_soc_for_wm_a(struct dc *dc, struct dc_state *context)
{
- if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].valid) {
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
- context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us;
- context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us;
- }
+ DC_FP_START();
+ dcn30_fpu_update_soc_for_wm_a(dc, context);
+ DC_FP_END();
}
void dcn30_calculate_wm_and_dlg(
@@ -2285,7 +1912,7 @@ void dcn30_calculate_wm_and_dlg(
int vlevel)
{
DC_FP_START();
- dcn30_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel);
+ dcn30_fpu_calculate_wm_and_dlg(dc, context, pipes, pipe_cnt, vlevel);
DC_FP_END();
}
@@ -2344,40 +1971,6 @@ validate_out:
return out;
}
-/*
- * This must be noinline to ensure anything that deals with FP registers
- * is contained within this call; previously our compiling with hard-float
- * would result in fp instructions being emitted outside of the boundaries
- * of the DC_FP_START/END macros, which makes sense as the compiler has no
- * idea about what is wrapped and what is not
- *
- * This is largely just a workaround to avoid breakage introduced with 5.6,
- * ideally all fp-using code should be moved into its own file, only that
- * should be compiled with hard-float, and all code exported from there
- * should be strictly wrapped with DC_FP_START/END
- */
-static noinline void dcn30_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
- unsigned int *optimal_dcfclk,
- unsigned int *optimal_fclk)
-{
- double bw_from_dram, bw_from_dram1, bw_from_dram2;
-
- bw_from_dram1 = uclk_mts * dcn3_0_soc.num_chans *
- dcn3_0_soc.dram_channel_width_bytes * (dcn3_0_soc.max_avg_dram_bw_use_normal_percent / 100);
- bw_from_dram2 = uclk_mts * dcn3_0_soc.num_chans *
- dcn3_0_soc.dram_channel_width_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100);
-
- bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
-
- if (optimal_fclk)
- *optimal_fclk = bw_from_dram /
- (dcn3_0_soc.fabric_datapath_to_dcn_data_return_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100));
-
- if (optimal_dcfclk)
- *optimal_dcfclk = bw_from_dram /
- (dcn3_0_soc.return_bus_width_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100));
-}
-
void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
{
unsigned int i, j;
@@ -2392,47 +1985,43 @@ void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params
unsigned int num_dcfclk_sta_targets = 4;
unsigned int num_uclk_states;
+ struct dc_bounding_box_max_clk dcn30_bb_max_clk;
+
+ memset(&dcn30_bb_max_clk, 0, sizeof(dcn30_bb_max_clk));
+
if (dc->ctx->dc_bios->vram_info.num_chans)
dcn3_0_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
- if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
- dcn3_0_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
-
- dcn3_0_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
- dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+ DC_FP_START();
+ dcn30_fpu_update_dram_channel_width_bytes(dc);
+ DC_FP_END();
if (bw_params->clk_table.entries[0].memclk_mhz) {
- int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
- if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
- max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
- if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
- max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
- if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
- max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
- if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
- max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
+ if (bw_params->clk_table.entries[i].dcfclk_mhz > dcn30_bb_max_clk.max_dcfclk_mhz)
+ dcn30_bb_max_clk.max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
+ if (bw_params->clk_table.entries[i].dispclk_mhz > dcn30_bb_max_clk.max_dispclk_mhz)
+ dcn30_bb_max_clk.max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
+ if (bw_params->clk_table.entries[i].dppclk_mhz > dcn30_bb_max_clk.max_dppclk_mhz)
+ dcn30_bb_max_clk.max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
+ if (bw_params->clk_table.entries[i].phyclk_mhz > dcn30_bb_max_clk.max_phyclk_mhz)
+ dcn30_bb_max_clk.max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
}
- if (!max_dcfclk_mhz)
- max_dcfclk_mhz = dcn3_0_soc.clock_limits[0].dcfclk_mhz;
- if (!max_dispclk_mhz)
- max_dispclk_mhz = dcn3_0_soc.clock_limits[0].dispclk_mhz;
- if (!max_dppclk_mhz)
- max_dppclk_mhz = dcn3_0_soc.clock_limits[0].dppclk_mhz;
- if (!max_phyclk_mhz)
- max_phyclk_mhz = dcn3_0_soc.clock_limits[0].phyclk_mhz;
+ DC_FP_START();
+ dcn30_fpu_update_max_clk(&dcn30_bb_max_clk);
+ DC_FP_END();
- if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+ if (dcn30_bb_max_clk.max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
// If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array
- dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
+ dcfclk_sta_targets[num_dcfclk_sta_targets] = dcn30_bb_max_clk.max_dcfclk_mhz;
num_dcfclk_sta_targets++;
- } else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+ } else if (dcn30_bb_max_clk.max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
// If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates
for (i = 0; i < num_dcfclk_sta_targets; i++) {
- if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
- dcfclk_sta_targets[i] = max_dcfclk_mhz;
+ if (dcfclk_sta_targets[i] > dcn30_bb_max_clk.max_dcfclk_mhz) {
+ dcfclk_sta_targets[i] = dcn30_bb_max_clk.max_dcfclk_mhz;
break;
}
}
@@ -2445,7 +2034,7 @@ void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params
// Calculate optimal dcfclk for each uclk
for (i = 0; i < num_uclk_states; i++) {
DC_FP_START();
- dcn30_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
+ dcn30_fpu_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
&optimal_dcfclk_for_uclk[i], NULL);
DC_FP_END();
if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz) {
@@ -2472,7 +2061,7 @@ void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params
dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
} else {
- if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+ if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= dcn30_bb_max_clk.max_dcfclk_mhz) {
dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
} else {
@@ -2487,33 +2076,15 @@ void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params
}
while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
- optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+ optimal_dcfclk_for_uclk[j] <= dcn30_bb_max_clk.max_dcfclk_mhz) {
dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
}
dcn3_0_soc.num_states = num_states;
- for (i = 0; i < dcn3_0_soc.num_states; i++) {
- dcn3_0_soc.clock_limits[i].state = i;
- dcn3_0_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
- dcn3_0_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
- dcn3_0_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
-
- /* Fill all states with max values of all other clocks */
- dcn3_0_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
- dcn3_0_soc.clock_limits[i].dppclk_mhz = max_dppclk_mhz;
- dcn3_0_soc.clock_limits[i].phyclk_mhz = max_phyclk_mhz;
- dcn3_0_soc.clock_limits[i].dtbclk_mhz = dcn3_0_soc.clock_limits[0].dtbclk_mhz;
- /* These clocks cannot come from bw_params, always fill from dcn3_0_soc[1] */
- /* FCLK, PHYCLK_D18, SOCCLK, DSCCLK */
- dcn3_0_soc.clock_limits[i].phyclk_d18_mhz = dcn3_0_soc.clock_limits[0].phyclk_d18_mhz;
- dcn3_0_soc.clock_limits[i].socclk_mhz = dcn3_0_soc.clock_limits[0].socclk_mhz;
- dcn3_0_soc.clock_limits[i].dscclk_mhz = dcn3_0_soc.clock_limits[0].dscclk_mhz;
- }
- /* re-init DML with updated bb */
- dml_init_instance(&dc->dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30);
- if (dc->current_state)
- dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30);
+ DC_FP_START();
+ dcn30_fpu_update_bw_bounding_box(dc, bw_params, &dcn30_bb_max_clk, dcfclk_mhz, dram_speed_mts);
+ DC_FP_END();
}
}
@@ -2595,9 +2166,9 @@ static bool dcn30_resource_construct(
dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576;
dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
- dc->caps.max_slave_planes = 1;
- dc->caps.max_slave_yuv_planes = 1;
- dc->caps.max_slave_rgb_planes = 1;
+ dc->caps.max_slave_planes = 2;
+ dc->caps.max_slave_yuv_planes = 2;
+ dc->caps.max_slave_rgb_planes = 2;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
dc->caps.extended_aux_timeout_support = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
index b92e4cc0232f..3330a1026fa5 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn30/dcn30_resource.h
@@ -35,6 +35,9 @@ struct dc;
struct resource_pool;
struct _vcs_dpi_display_pipe_params_st;
+extern struct _vcs_dpi_ip_params_st dcn3_0_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn3_0_soc;
+
struct dcn30_resource_pool {
struct resource_pool base;
};
@@ -96,4 +99,6 @@ enum dc_status dcn30_add_stream_to_ctx(
void dcn30_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+void dcn30_setup_mclk_switch_using_fw_based_vblank_stretch(struct dc *dc, struct dc_state *context);
+
#endif /* _DCN30_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c
index 1e3bd2e9cdcc..a046664e2031 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c
@@ -60,6 +60,7 @@ static const struct hubbub_funcs hubbub301_funcs = {
.program_watermarks = hubbub3_program_watermarks,
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
+ .verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
.force_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes,
.force_pstate_change_control = hubbub3_force_pstate_change_control,
.hubbub_read_state = hubbub2_read_state,
diff --git a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
index 5d9637b07429..a5df74110284 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn301/dcn301_resource.c
@@ -73,14 +73,16 @@
#include "nbio/nbio_7_2_0_offset.h"
-#include "dcn/dpcs_3_0_0_offset.h"
-#include "dcn/dpcs_3_0_0_sh_mask.h"
+#include "dpcs/dpcs_3_0_0_offset.h"
+#include "dpcs/dpcs_3_0_0_sh_mask.h"
#include "reg_helper.h"
#include "dce/dmub_abm.h"
#include "dce/dce_aux.h"
#include "dce/dce_i2c.h"
+#include "dml/dcn30/dcn30_fpu.h"
+
#include "dml/dcn30/display_mode_vba_30.h"
#include "dml/dcn301/dcn301_fpu.h"
#include "vm_helper.h"
diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/Makefile b/drivers/gpu/drm/amd/display/dc/dcn302/Makefile
index 101620a8867a..f9561d7f97a1 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn302/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn302/Makefile
@@ -1,11 +1,6 @@
#
# (c) Copyright 2020 Advanced Micro Devices, Inc. All the rights reserved
#
-# All rights reserved. This notice is intended as a precaution against
-# inadvertent publication and does not imply publication or any waiver
-# of confidentiality. The year included in the foregoing notice is the
-# year of creation of the work.
-#
# Authors: AMD
#
# Makefile for dcn302.
@@ -20,13 +15,6 @@ ifdef CONFIG_PPC64
CFLAGS_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o := -mhard-float -maltivec
endif
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-CFLAGS_$(AMDDALPATH)/dc/dcn302/dcn302_resource.o += -mhard-float
-endif
-
ifdef CONFIG_X86
ifdef IS_OLD_GCC
# Stack alignment mismatch, proceed with caution.
diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
index 2e9cbfa7663b..f537888f4fa6 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.c
@@ -43,6 +43,8 @@
#include "dcn20/dcn20_dsc.h"
#include "dcn20/dcn20_resource.h"
+#include "dml/dcn30/dcn30_fpu.h"
+
#include "dcn10/dcn10_resource.h"
#include "dce/dce_abm.h"
@@ -61,150 +63,18 @@
#include "resource.h"
#include "vm_helper.h"
+#include "dml/dcn302/dcn302_fpu.h"
+
#include "dimgrey_cavefish_ip_offset.h"
#include "dcn/dcn_3_0_2_offset.h"
#include "dcn/dcn_3_0_2_sh_mask.h"
-#include "dcn/dpcs_3_0_0_offset.h"
-#include "dcn/dpcs_3_0_0_sh_mask.h"
+#include "dpcs/dpcs_3_0_0_offset.h"
+#include "dpcs/dpcs_3_0_0_sh_mask.h"
#include "nbio/nbio_7_4_offset.h"
#include "amdgpu_socbb.h"
#define DC_LOGGER_INIT(logger)
-struct _vcs_dpi_ip_params_st dcn3_02_ip = {
- .use_min_dcfclk = 0,
- .clamp_min_dcfclk = 0,
- .odm_capable = 1,
- .gpuvm_enable = 1,
- .hostvm_enable = 0,
- .gpuvm_max_page_table_levels = 4,
- .hostvm_max_page_table_levels = 4,
- .hostvm_cached_page_table_levels = 0,
- .pte_group_size_bytes = 2048,
- .num_dsc = 5,
- .rob_buffer_size_kbytes = 184,
- .det_buffer_size_kbytes = 184,
- .dpte_buffer_size_in_pte_reqs_luma = 64,
- .dpte_buffer_size_in_pte_reqs_chroma = 34,
- .pde_proc_buffer_size_64k_reqs = 48,
- .dpp_output_buffer_pixels = 2560,
- .opp_output_buffer_lines = 1,
- .pixel_chunk_size_kbytes = 8,
- .pte_enable = 1,
- .max_page_table_levels = 2,
- .pte_chunk_size_kbytes = 2, // ?
- .meta_chunk_size_kbytes = 2,
- .writeback_chunk_size_kbytes = 8,
- .line_buffer_size_bits = 789504,
- .is_line_buffer_bpp_fixed = 0, // ?
- .line_buffer_fixed_bpp = 0, // ?
- .dcc_supported = true,
- .writeback_interface_buffer_size_kbytes = 90,
- .writeback_line_buffer_buffer_size = 0,
- .max_line_buffer_lines = 12,
- .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640
- .writeback_chroma_buffer_size_kbytes = 8,
- .writeback_chroma_line_buffer_width_pixels = 4,
- .writeback_max_hscl_ratio = 1,
- .writeback_max_vscl_ratio = 1,
- .writeback_min_hscl_ratio = 1,
- .writeback_min_vscl_ratio = 1,
- .writeback_max_hscl_taps = 1,
- .writeback_max_vscl_taps = 1,
- .writeback_line_buffer_luma_buffer_size = 0,
- .writeback_line_buffer_chroma_buffer_size = 14643,
- .cursor_buffer_size = 8,
- .cursor_chunk_size = 2,
- .max_num_otg = 5,
- .max_num_dpp = 5,
- .max_num_wb = 1,
- .max_dchub_pscl_bw_pix_per_clk = 4,
- .max_pscl_lb_bw_pix_per_clk = 2,
- .max_lb_vscl_bw_pix_per_clk = 4,
- .max_vscl_hscl_bw_pix_per_clk = 4,
- .max_hscl_ratio = 6,
- .max_vscl_ratio = 6,
- .hscl_mults = 4,
- .vscl_mults = 4,
- .max_hscl_taps = 8,
- .max_vscl_taps = 8,
- .dispclk_ramp_margin_percent = 1,
- .underscan_factor = 1.11,
- .min_vblank_lines = 32,
- .dppclk_delay_subtotal = 46,
- .dynamic_metadata_vm_enabled = true,
- .dppclk_delay_scl_lb_only = 16,
- .dppclk_delay_scl = 50,
- .dppclk_delay_cnvc_formatter = 27,
- .dppclk_delay_cnvc_cursor = 6,
- .dispclk_delay_subtotal = 119,
- .dcfclk_cstate_latency = 5.2, // SRExitTime
- .max_inter_dcn_tile_repeaters = 8,
- .max_num_hdmi_frl_outputs = 1,
- .odm_combine_4to1_supported = true,
-
- .xfc_supported = false,
- .xfc_fill_bw_overhead_percent = 10.0,
- .xfc_fill_constant_bytes = 0,
- .gfx7_compat_tiling_supported = 0,
- .number_of_cursors = 1,
-};
-
-struct _vcs_dpi_soc_bounding_box_st dcn3_02_soc = {
- .clock_limits = {
- {
- .state = 0,
- .dispclk_mhz = 562.0,
- .dppclk_mhz = 300.0,
- .phyclk_mhz = 300.0,
- .phyclk_d18_mhz = 667.0,
- .dscclk_mhz = 405.6,
- },
- },
-
- .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */
- .num_states = 1,
- .sr_exit_time_us = 26.5,
- .sr_enter_plus_exit_time_us = 31,
- .urgent_latency_us = 4.0,
- .urgent_latency_pixel_data_only_us = 4.0,
- .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
- .urgent_latency_vm_data_only_us = 4.0,
- .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
- .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
- .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
- .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
- .max_avg_sdp_bw_use_normal_percent = 60.0,
- .max_avg_dram_bw_use_normal_percent = 40.0,
- .writeback_latency_us = 12.0,
- .max_request_size_bytes = 256,
- .fabric_datapath_to_dcn_data_return_bytes = 64,
- .dcn_downspread_percent = 0.5,
- .downspread_percent = 0.38,
- .dram_page_open_time_ns = 50.0,
- .dram_rw_turnaround_time_ns = 17.5,
- .dram_return_buffer_per_channel_bytes = 8192,
- .round_trip_ping_latency_dcfclk_cycles = 156,
- .urgent_out_of_order_return_per_channel_bytes = 4096,
- .channel_interleave_bytes = 256,
- .num_banks = 8,
- .gpuvm_min_page_size_bytes = 4096,
- .hostvm_min_page_size_bytes = 4096,
- .dram_clock_change_latency_us = 404,
- .dummy_pstate_latency_us = 5,
- .writeback_dram_clock_change_latency_us = 23.0,
- .return_bus_width_bytes = 64,
- .dispclk_dppclk_vco_speed_mhz = 3650,
- .xfc_bus_transport_time_us = 20, // ?
- .xfc_xbuf_latency_tolerance_us = 4, // ?
- .use_urgent_burst_bw = 1, // ?
- .do_urgent_latency_adjustment = true,
- .urgent_latency_adjustment_fabric_clock_component_us = 1.0,
- .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
-};
-
static const struct dc_debug_options debug_defaults_drv = {
.disable_dmcu = true,
.force_abm_enable = false,
@@ -1105,24 +975,19 @@ static bool init_soc_bounding_box(struct dc *dc, struct resource_pool *pool)
loaded_ip->max_num_otg = pool->pipe_count;
loaded_ip->max_num_dpp = pool->pipe_count;
loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk;
+ DC_FP_START();
dcn20_patch_bounding_box(dc, loaded_bb);
+ DC_FP_END();
if (dc->ctx->dc_bios->funcs->get_soc_bb_info) {
struct bp_soc_bb_info bb_info = { 0 };
if (dc->ctx->dc_bios->funcs->get_soc_bb_info(
dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) {
- if (bb_info.dram_clock_change_latency_100ns > 0)
- dcn3_02_soc.dram_clock_change_latency_us =
- bb_info.dram_clock_change_latency_100ns * 10;
-
- if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
- dcn3_02_soc.sr_enter_plus_exit_time_us =
- bb_info.dram_sr_enter_exit_latency_100ns * 10;
- if (bb_info.dram_sr_exit_latency_100ns > 0)
- dcn3_02_soc.sr_exit_time_us =
- bb_info.dram_sr_exit_latency_100ns * 10;
+ DC_FP_START();
+ dcn302_fpu_init_soc_bounding_box(bb_info);
+ DC_FP_END();
}
}
@@ -1257,170 +1122,11 @@ static void dcn302_destroy_resource_pool(struct resource_pool **pool)
*pool = NULL;
}
-static void dcn302_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
- unsigned int *optimal_dcfclk,
- unsigned int *optimal_fclk)
-{
- double bw_from_dram, bw_from_dram1, bw_from_dram2;
-
- bw_from_dram1 = uclk_mts * dcn3_02_soc.num_chans *
- dcn3_02_soc.dram_channel_width_bytes * (dcn3_02_soc.max_avg_dram_bw_use_normal_percent / 100);
- bw_from_dram2 = uclk_mts * dcn3_02_soc.num_chans *
- dcn3_02_soc.dram_channel_width_bytes * (dcn3_02_soc.max_avg_sdp_bw_use_normal_percent / 100);
-
- bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
-
- if (optimal_fclk)
- *optimal_fclk = bw_from_dram /
- (dcn3_02_soc.fabric_datapath_to_dcn_data_return_bytes * (dcn3_02_soc.max_avg_sdp_bw_use_normal_percent / 100));
-
- if (optimal_dcfclk)
- *optimal_dcfclk = bw_from_dram /
- (dcn3_02_soc.return_bus_width_bytes * (dcn3_02_soc.max_avg_sdp_bw_use_normal_percent / 100));
-}
-
void dcn302_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
{
- unsigned int i, j;
- unsigned int num_states = 0;
-
- unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0};
- unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0};
- unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0};
- unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0};
-
- unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {694, 875, 1000, 1200};
- unsigned int num_dcfclk_sta_targets = 4;
- unsigned int num_uclk_states;
-
-
- if (dc->ctx->dc_bios->vram_info.num_chans)
- dcn3_02_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
-
- if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
- dcn3_02_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
-
- dcn3_02_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
- dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
-
- if (bw_params->clk_table.entries[0].memclk_mhz) {
- int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
-
- for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
- if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
- max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
- if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
- max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
- if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
- max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
- if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
- max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
- }
- if (!max_dcfclk_mhz)
- max_dcfclk_mhz = dcn3_02_soc.clock_limits[0].dcfclk_mhz;
- if (!max_dispclk_mhz)
- max_dispclk_mhz = dcn3_02_soc.clock_limits[0].dispclk_mhz;
- if (!max_dppclk_mhz)
- max_dppclk_mhz = dcn3_02_soc.clock_limits[0].dppclk_mhz;
- if (!max_phyclk_mhz)
- max_phyclk_mhz = dcn3_02_soc.clock_limits[0].phyclk_mhz;
-
- if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
- /* If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array */
- dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
- num_dcfclk_sta_targets++;
- } else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
- /* If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates */
- for (i = 0; i < num_dcfclk_sta_targets; i++) {
- if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
- dcfclk_sta_targets[i] = max_dcfclk_mhz;
- break;
- }
- }
- /* Update size of array since we "removed" duplicates */
- num_dcfclk_sta_targets = i + 1;
- }
-
- num_uclk_states = bw_params->clk_table.num_entries;
-
- /* Calculate optimal dcfclk for each uclk */
- for (i = 0; i < num_uclk_states; i++) {
- dcn302_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
- &optimal_dcfclk_for_uclk[i], NULL);
- if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz) {
- optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz;
- }
- }
-
- /* Calculate optimal uclk for each dcfclk sta target */
- for (i = 0; i < num_dcfclk_sta_targets; i++) {
- for (j = 0; j < num_uclk_states; j++) {
- if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) {
- optimal_uclk_for_dcfclk_sta_targets[i] =
- bw_params->clk_table.entries[j].memclk_mhz * 16;
- break;
- }
- }
- }
-
- i = 0;
- j = 0;
- /* create the final dcfclk and uclk table */
- while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) {
- if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) {
- dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
- dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
- } else {
- if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
- dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
- dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
- } else {
- j = num_uclk_states;
- }
- }
- }
-
- while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) {
- dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
- dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
- }
-
- while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
- optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
- dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
- dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
- }
-
- dcn3_02_soc.num_states = num_states;
- for (i = 0; i < dcn3_02_soc.num_states; i++) {
- dcn3_02_soc.clock_limits[i].state = i;
- dcn3_02_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
- dcn3_02_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
- dcn3_02_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
-
- /* Fill all states with max values of all other clocks */
- dcn3_02_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
- dcn3_02_soc.clock_limits[i].dppclk_mhz = max_dppclk_mhz;
- dcn3_02_soc.clock_limits[i].phyclk_mhz = max_phyclk_mhz;
- /* Populate from bw_params for DTBCLK, SOCCLK */
- if (!bw_params->clk_table.entries[i].dtbclk_mhz && i > 0)
- dcn3_02_soc.clock_limits[i].dtbclk_mhz = dcn3_02_soc.clock_limits[i-1].dtbclk_mhz;
- else
- dcn3_02_soc.clock_limits[i].dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
- if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
- dcn3_02_soc.clock_limits[i].socclk_mhz = dcn3_02_soc.clock_limits[i-1].socclk_mhz;
- else
- dcn3_02_soc.clock_limits[i].socclk_mhz = bw_params->clk_table.entries[i].socclk_mhz;
- /* These clocks cannot come from bw_params, always fill from dcn3_02_soc[1] */
- /* FCLK, PHYCLK_D18, DSCCLK */
- dcn3_02_soc.clock_limits[i].phyclk_d18_mhz = dcn3_02_soc.clock_limits[0].phyclk_d18_mhz;
- dcn3_02_soc.clock_limits[i].dscclk_mhz = dcn3_02_soc.clock_limits[0].dscclk_mhz;
- }
- /* re-init DML with updated bb */
- dml_init_instance(&dc->dml, &dcn3_02_soc, &dcn3_02_ip, DML_PROJECT_DCN30);
- if (dc->current_state)
- dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_02_soc, &dcn3_02_ip, DML_PROJECT_DCN30);
- }
+ DC_FP_START();
+ dcn302_fpu_update_bw_bounding_box(dc, bw_params);
+ DC_FP_END();
}
static struct resource_funcs dcn302_res_pool_funcs = {
@@ -1515,9 +1221,9 @@ static bool dcn302_resource_construct(
/* total size = mall per channel * num channels * 1024 * 1024 */
dc->caps.mall_size_total = dc->caps.mall_size_per_mem_channel * dc->ctx->dc_bios->vram_info.num_chans * 1048576;
dc->caps.cursor_cache_size = dc->caps.max_cursor_size * dc->caps.max_cursor_size * 8;
- dc->caps.max_slave_planes = 1;
- dc->caps.max_slave_yuv_planes = 1;
- dc->caps.max_slave_rgb_planes = 1;
+ dc->caps.max_slave_planes = 2;
+ dc->caps.max_slave_yuv_planes = 2;
+ dc->caps.max_slave_rgb_planes = 2;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
dc->caps.extended_aux_timeout_support = true;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h
index 42d2c73e30bc..9f24e73b92b3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn302/dcn302_resource.h
@@ -28,6 +28,9 @@
#include "core_types.h"
+extern struct _vcs_dpi_ip_params_st dcn3_02_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn3_02_soc;
+
struct resource_pool *dcn302_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc);
void dcn302_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/Makefile b/drivers/gpu/drm/amd/display/dc/dcn303/Makefile
index 6f7a1f2b49f0..8702e0b7fda3 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn303/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn303/Makefile
@@ -8,32 +8,6 @@
DCN3_03 = dcn303_init.o dcn303_hwseq.o dcn303_resource.o
-ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn303/dcn303_resource.o := -msse
-endif
-
-ifdef CONFIG_PPC64
-CFLAGS_$(AMDDALPATH)/dc/dcn303/dcn303_resource.o := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-CFLAGS_$(AMDDALPATH)/dc/dcn303/dcn303_resource.o += -mhard-float
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-CFLAGS_$(AMDDALPATH)/dc/dcn303/dcn303_resource.o += -mpreferred-stack-boundary=4
-else
-CFLAGS_$(AMDDALPATH)/dc/dcn303/dcn303_resource.o += -msse2
-endif
-endif
-
AMD_DAL_DCN3_03 = $(addprefix $(AMDDALPATH)/dc/dcn303/,$(DCN3_03))
AMD_DISPLAY_FILES += $(AMD_DAL_DCN3_03)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
index 2de687f64cf6..76f863eb86ef 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.c
@@ -25,6 +25,8 @@
#include "dcn20/dcn20_dsc.h"
#include "dcn20/dcn20_resource.h"
+#include "dml/dcn30/dcn30_fpu.h"
+
#include "dcn10/dcn10_resource.h"
#include "dc_link_ddc.h"
@@ -48,144 +50,14 @@
#include "sienna_cichlid_ip_offset.h"
#include "dcn/dcn_3_0_3_offset.h"
#include "dcn/dcn_3_0_3_sh_mask.h"
-#include "dcn/dpcs_3_0_3_offset.h"
-#include "dcn/dpcs_3_0_3_sh_mask.h"
+#include "dpcs/dpcs_3_0_3_offset.h"
+#include "dpcs/dpcs_3_0_3_sh_mask.h"
#include "nbio/nbio_2_3_offset.h"
-#define DC_LOGGER_INIT(logger)
+#include "dml/dcn303/dcn303_fpu.h"
-struct _vcs_dpi_ip_params_st dcn3_03_ip = {
- .use_min_dcfclk = 0,
- .clamp_min_dcfclk = 0,
- .odm_capable = 1,
- .gpuvm_enable = 1,
- .hostvm_enable = 0,
- .gpuvm_max_page_table_levels = 4,
- .hostvm_max_page_table_levels = 4,
- .hostvm_cached_page_table_levels = 0,
- .pte_group_size_bytes = 2048,
- .num_dsc = 2,
- .rob_buffer_size_kbytes = 184,
- .det_buffer_size_kbytes = 184,
- .dpte_buffer_size_in_pte_reqs_luma = 64,
- .dpte_buffer_size_in_pte_reqs_chroma = 34,
- .pde_proc_buffer_size_64k_reqs = 48,
- .dpp_output_buffer_pixels = 2560,
- .opp_output_buffer_lines = 1,
- .pixel_chunk_size_kbytes = 8,
- .pte_enable = 1,
- .max_page_table_levels = 2,
- .pte_chunk_size_kbytes = 2, // ?
- .meta_chunk_size_kbytes = 2,
- .writeback_chunk_size_kbytes = 8,
- .line_buffer_size_bits = 789504,
- .is_line_buffer_bpp_fixed = 0, // ?
- .line_buffer_fixed_bpp = 0, // ?
- .dcc_supported = true,
- .writeback_interface_buffer_size_kbytes = 90,
- .writeback_line_buffer_buffer_size = 0,
- .max_line_buffer_lines = 12,
- .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640
- .writeback_chroma_buffer_size_kbytes = 8,
- .writeback_chroma_line_buffer_width_pixels = 4,
- .writeback_max_hscl_ratio = 1,
- .writeback_max_vscl_ratio = 1,
- .writeback_min_hscl_ratio = 1,
- .writeback_min_vscl_ratio = 1,
- .writeback_max_hscl_taps = 1,
- .writeback_max_vscl_taps = 1,
- .writeback_line_buffer_luma_buffer_size = 0,
- .writeback_line_buffer_chroma_buffer_size = 14643,
- .cursor_buffer_size = 8,
- .cursor_chunk_size = 2,
- .max_num_otg = 2,
- .max_num_dpp = 2,
- .max_num_wb = 1,
- .max_dchub_pscl_bw_pix_per_clk = 4,
- .max_pscl_lb_bw_pix_per_clk = 2,
- .max_lb_vscl_bw_pix_per_clk = 4,
- .max_vscl_hscl_bw_pix_per_clk = 4,
- .max_hscl_ratio = 6,
- .max_vscl_ratio = 6,
- .hscl_mults = 4,
- .vscl_mults = 4,
- .max_hscl_taps = 8,
- .max_vscl_taps = 8,
- .dispclk_ramp_margin_percent = 1,
- .underscan_factor = 1.11,
- .min_vblank_lines = 32,
- .dppclk_delay_subtotal = 46,
- .dynamic_metadata_vm_enabled = true,
- .dppclk_delay_scl_lb_only = 16,
- .dppclk_delay_scl = 50,
- .dppclk_delay_cnvc_formatter = 27,
- .dppclk_delay_cnvc_cursor = 6,
- .dispclk_delay_subtotal = 119,
- .dcfclk_cstate_latency = 5.2, // SRExitTime
- .max_inter_dcn_tile_repeaters = 8,
- .max_num_hdmi_frl_outputs = 1,
- .odm_combine_4to1_supported = false,
- .xfc_supported = false,
- .xfc_fill_bw_overhead_percent = 10.0,
- .xfc_fill_constant_bytes = 0,
- .gfx7_compat_tiling_supported = 0,
- .number_of_cursors = 1,
-};
-
-struct _vcs_dpi_soc_bounding_box_st dcn3_03_soc = {
- .clock_limits = {
- {
- .state = 0,
- .dispclk_mhz = 1217.0,
- .dppclk_mhz = 1217.0,
- .phyclk_mhz = 810.0,
- .phyclk_d18_mhz = 667.0,
- .dscclk_mhz = 405.6,
- },
- },
+#define DC_LOGGER_INIT(logger)
- .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */
- .num_states = 1,
- .sr_exit_time_us = 35.5,
- .sr_enter_plus_exit_time_us = 40,
- .urgent_latency_us = 4.0,
- .urgent_latency_pixel_data_only_us = 4.0,
- .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
- .urgent_latency_vm_data_only_us = 4.0,
- .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
- .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
- .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
- .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
- .max_avg_sdp_bw_use_normal_percent = 60.0,
- .max_avg_dram_bw_use_normal_percent = 40.0,
- .writeback_latency_us = 12.0,
- .max_request_size_bytes = 256,
- .fabric_datapath_to_dcn_data_return_bytes = 64,
- .dcn_downspread_percent = 0.5,
- .downspread_percent = 0.38,
- .dram_page_open_time_ns = 50.0,
- .dram_rw_turnaround_time_ns = 17.5,
- .dram_return_buffer_per_channel_bytes = 8192,
- .round_trip_ping_latency_dcfclk_cycles = 156,
- .urgent_out_of_order_return_per_channel_bytes = 4096,
- .channel_interleave_bytes = 256,
- .num_banks = 8,
- .gpuvm_min_page_size_bytes = 4096,
- .hostvm_min_page_size_bytes = 4096,
- .dram_clock_change_latency_us = 404,
- .dummy_pstate_latency_us = 5,
- .writeback_dram_clock_change_latency_us = 23.0,
- .return_bus_width_bytes = 64,
- .dispclk_dppclk_vco_speed_mhz = 3650,
- .xfc_bus_transport_time_us = 20, // ?
- .xfc_xbuf_latency_tolerance_us = 4, // ?
- .use_urgent_burst_bw = 1, // ?
- .do_urgent_latency_adjustment = true,
- .urgent_latency_adjustment_fabric_clock_component_us = 1.0,
- .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
-};
static const struct dc_debug_options debug_defaults_drv = {
.disable_dmcu = true,
@@ -1031,24 +903,18 @@ static bool init_soc_bounding_box(struct dc *dc, struct resource_pool *pool)
loaded_ip->max_num_otg = pool->pipe_count;
loaded_ip->max_num_dpp = pool->pipe_count;
loaded_ip->clamp_min_dcfclk = dc->config.clamp_min_dcfclk;
+ DC_FP_START();
dcn20_patch_bounding_box(dc, loaded_bb);
+ DC_FP_END();
if (dc->ctx->dc_bios->funcs->get_soc_bb_info) {
struct bp_soc_bb_info bb_info = { 0 };
if (dc->ctx->dc_bios->funcs->get_soc_bb_info(
dc->ctx->dc_bios, &bb_info) == BP_RESULT_OK) {
- if (bb_info.dram_clock_change_latency_100ns > 0)
- dcn3_03_soc.dram_clock_change_latency_us =
- bb_info.dram_clock_change_latency_100ns * 10;
-
- if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
- dcn3_03_soc.sr_enter_plus_exit_time_us =
- bb_info.dram_sr_enter_exit_latency_100ns * 10;
-
- if (bb_info.dram_sr_exit_latency_100ns > 0)
- dcn3_03_soc.sr_exit_time_us =
- bb_info.dram_sr_exit_latency_100ns * 10;
+ DC_FP_START();
+ dcn303_fpu_init_soc_bounding_box(bb_info);
+ DC_FP_END();
}
}
@@ -1186,183 +1052,12 @@ static void dcn303_destroy_resource_pool(struct resource_pool **pool)
*pool = NULL;
}
-static void dcn303_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
- unsigned int *optimal_dcfclk,
- unsigned int *optimal_fclk)
-{
- double bw_from_dram, bw_from_dram1, bw_from_dram2;
-
- bw_from_dram1 = uclk_mts * dcn3_03_soc.num_chans *
- dcn3_03_soc.dram_channel_width_bytes * (dcn3_03_soc.max_avg_dram_bw_use_normal_percent / 100);
- bw_from_dram2 = uclk_mts * dcn3_03_soc.num_chans *
- dcn3_03_soc.dram_channel_width_bytes * (dcn3_03_soc.max_avg_sdp_bw_use_normal_percent / 100);
-
- bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
-
- if (optimal_fclk)
- *optimal_fclk = bw_from_dram /
- (dcn3_03_soc.fabric_datapath_to_dcn_data_return_bytes *
- (dcn3_03_soc.max_avg_sdp_bw_use_normal_percent / 100));
-
- if (optimal_dcfclk)
- *optimal_dcfclk = bw_from_dram /
- (dcn3_03_soc.return_bus_width_bytes * (dcn3_03_soc.max_avg_sdp_bw_use_normal_percent / 100));
-}
void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
{
- unsigned int i, j;
- unsigned int num_states = 0;
-
- unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0};
- unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0};
- unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0};
- unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0};
-
- unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {694, 875, 1000, 1200};
- unsigned int num_dcfclk_sta_targets = 4;
- unsigned int num_uclk_states;
-
-
- if (dc->ctx->dc_bios->vram_info.num_chans)
- dcn3_03_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
-
- if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
- dcn3_03_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
-
- dcn3_03_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
- dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
-
- if (bw_params->clk_table.entries[0].memclk_mhz) {
- int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
-
- for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
- if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
- max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
- if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
- max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
- if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
- max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
- if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
- max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
- }
- if (!max_dcfclk_mhz)
- max_dcfclk_mhz = dcn3_03_soc.clock_limits[0].dcfclk_mhz;
- if (!max_dispclk_mhz)
- max_dispclk_mhz = dcn3_03_soc.clock_limits[0].dispclk_mhz;
- if (!max_dppclk_mhz)
- max_dppclk_mhz = dcn3_03_soc.clock_limits[0].dppclk_mhz;
- if (!max_phyclk_mhz)
- max_phyclk_mhz = dcn3_03_soc.clock_limits[0].phyclk_mhz;
-
- if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
- dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
- num_dcfclk_sta_targets++;
- } else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
- for (i = 0; i < num_dcfclk_sta_targets; i++) {
- if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
- dcfclk_sta_targets[i] = max_dcfclk_mhz;
- break;
- }
- }
- /* Update size of array since we "removed" duplicates */
- num_dcfclk_sta_targets = i + 1;
- }
-
- num_uclk_states = bw_params->clk_table.num_entries;
-
- /* Calculate optimal dcfclk for each uclk */
- for (i = 0; i < num_uclk_states; i++) {
- dcn303_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
- &optimal_dcfclk_for_uclk[i], NULL);
- if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz)
- optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz;
- }
-
- /* Calculate optimal uclk for each dcfclk sta target */
- for (i = 0; i < num_dcfclk_sta_targets; i++) {
- for (j = 0; j < num_uclk_states; j++) {
- if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) {
- optimal_uclk_for_dcfclk_sta_targets[i] =
- bw_params->clk_table.entries[j].memclk_mhz * 16;
- break;
- }
- }
- }
-
- i = 0;
- j = 0;
- /* create the final dcfclk and uclk table */
- while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) {
- if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) {
- dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
- dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
- } else {
- if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
- dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
- dram_speed_mts[num_states++] =
- bw_params->clk_table.entries[j++].memclk_mhz * 16;
- } else {
- j = num_uclk_states;
- }
- }
- }
-
- while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) {
- dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
- dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
- }
-
- while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
- optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
- dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
- dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
- }
-
- dcn3_03_soc.num_states = num_states;
- for (i = 0; i < dcn3_03_soc.num_states; i++) {
- dcn3_03_soc.clock_limits[i].state = i;
- dcn3_03_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
- dcn3_03_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
- dcn3_03_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
-
- /* Fill all states with max values of all other clocks */
- dcn3_03_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
- dcn3_03_soc.clock_limits[i].dppclk_mhz = max_dppclk_mhz;
- dcn3_03_soc.clock_limits[i].phyclk_mhz = max_phyclk_mhz;
- /* Populate from bw_params for DTBCLK, SOCCLK */
- if (!bw_params->clk_table.entries[i].dtbclk_mhz && i > 0)
- dcn3_03_soc.clock_limits[i].dtbclk_mhz = dcn3_03_soc.clock_limits[i-1].dtbclk_mhz;
- else
- dcn3_03_soc.clock_limits[i].dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
- if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
- dcn3_03_soc.clock_limits[i].socclk_mhz = dcn3_03_soc.clock_limits[i-1].socclk_mhz;
- else
- dcn3_03_soc.clock_limits[i].socclk_mhz = bw_params->clk_table.entries[i].socclk_mhz;
- /* These clocks cannot come from bw_params, always fill from dcn3_03_soc[1] */
- /* FCLK, PHYCLK_D18, DSCCLK */
- dcn3_03_soc.clock_limits[i].phyclk_d18_mhz = dcn3_03_soc.clock_limits[0].phyclk_d18_mhz;
- dcn3_03_soc.clock_limits[i].dscclk_mhz = dcn3_03_soc.clock_limits[0].dscclk_mhz;
- }
-
- // WA: patch strobe modes to compensate for DCN303 BW issue
- if (dcn3_03_soc.num_chans <= 4) {
- for (i = 0; i < dcn3_03_soc.num_states; i++) {
- if (dcn3_03_soc.clock_limits[i].dram_speed_mts > 1700)
- break;
-
- if (dcn3_03_soc.clock_limits[i].dram_speed_mts >= 1500) {
- dcn3_03_soc.clock_limits[i].dcfclk_mhz = 100;
- dcn3_03_soc.clock_limits[i].fabricclk_mhz = 100;
- }
- }
- }
-
- /* re-init DML with updated bb */
- dml_init_instance(&dc->dml, &dcn3_03_soc, &dcn3_03_ip, DML_PROJECT_DCN30);
- if (dc->current_state)
- dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_03_soc, &dcn3_03_ip, DML_PROJECT_DCN30);
- }
+ DC_FP_START();
+ dcn303_fpu_update_bw_bounding_box(dc, bw_params);
+ DC_FP_END();
}
static struct resource_funcs dcn303_res_pool_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h
index 5b590c169763..9c7d79540900 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn303/dcn303_resource.h
@@ -10,6 +10,9 @@
#include "core_types.h"
+extern struct _vcs_dpi_ip_params_st dcn3_03_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn3_03_soc;
+
struct resource_pool *dcn303_create_resource_pool(const struct dc_init_data *init_data, struct dc *dc);
void dcn303_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
index d20e3b8ccc30..ec041e3cda30 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/Makefile
@@ -15,32 +15,6 @@ DCN31 = dcn31_resource.o dcn31_hubbub.o dcn31_hwseq.o dcn31_init.o dcn31_hubp.o
dcn31_apg.o dcn31_hpo_dp_stream_encoder.o dcn31_hpo_dp_link_encoder.o \
dcn31_afmt.o dcn31_vpg.o
-ifdef CONFIG_X86
-CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o := -msse
-endif
-
-ifdef CONFIG_PPC64
-CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o := -mhard-float -maltivec
-endif
-
-ifdef CONFIG_CC_IS_GCC
-ifeq ($(call cc-ifversion, -lt, 0701, y), y)
-IS_OLD_GCC = 1
-endif
-CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -mhard-float
-endif
-
-ifdef CONFIG_X86
-ifdef IS_OLD_GCC
-# Stack alignment mismatch, proceed with caution.
-# GCC < 7.1 cannot compile code using `double` and -mpreferred-stack-boundary=3
-# (8B stack alignment).
-CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -mpreferred-stack-boundary=4
-else
-CFLAGS_$(AMDDALPATH)/dc/dcn31/dcn31_resource.o += -msse2
-endif
-endif
-
AMD_DAL_DCN31 = $(addprefix $(AMDDALPATH)/dc/dcn31/,$(DCN31))
AMD_DISPLAY_FILES += $(AMD_DAL_DCN31)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
index ea4f8e06b07c..bbc58d167c63 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
@@ -121,7 +121,8 @@ static void dccg31_enable_dpstreamclk(struct dccg *dccg, int otg_inst)
return;
}
if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ DPSTREAMCLK_GATE_DISABLE, 1,
DPSTREAMCLK_ROOT_GATE_DISABLE, 1);
}
@@ -130,8 +131,9 @@ static void dccg31_disable_dpstreamclk(struct dccg *dccg, int otg_inst)
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpstream)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
- DPSTREAMCLK_ROOT_GATE_DISABLE, 0);
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ DPSTREAMCLK_ROOT_GATE_DISABLE, 0,
+ DPSTREAMCLK_GATE_DISABLE, 0);
switch (otg_inst) {
case 0:
@@ -180,7 +182,8 @@ void dccg31_enable_symclk32_se(
switch (hpo_se_inst) {
case 0:
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_SE0_GATE_DISABLE, 1,
SYMCLK32_ROOT_SE0_GATE_DISABLE, 1);
REG_UPDATE_2(SYMCLK32_SE_CNTL,
SYMCLK32_SE0_SRC_SEL, phyd32clk,
@@ -188,7 +191,8 @@ void dccg31_enable_symclk32_se(
break;
case 1:
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_SE1_GATE_DISABLE, 1,
SYMCLK32_ROOT_SE1_GATE_DISABLE, 1);
REG_UPDATE_2(SYMCLK32_SE_CNTL,
SYMCLK32_SE1_SRC_SEL, phyd32clk,
@@ -196,7 +200,8 @@ void dccg31_enable_symclk32_se(
break;
case 2:
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_SE2_GATE_DISABLE, 1,
SYMCLK32_ROOT_SE2_GATE_DISABLE, 1);
REG_UPDATE_2(SYMCLK32_SE_CNTL,
SYMCLK32_SE2_SRC_SEL, phyd32clk,
@@ -204,7 +209,8 @@ void dccg31_enable_symclk32_se(
break;
case 3:
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_SE3_GATE_DISABLE, 1,
SYMCLK32_ROOT_SE3_GATE_DISABLE, 1);
REG_UPDATE_2(SYMCLK32_SE_CNTL,
SYMCLK32_SE3_SRC_SEL, phyd32clk,
@@ -229,7 +235,8 @@ void dccg31_disable_symclk32_se(
SYMCLK32_SE0_SRC_SEL, 0,
SYMCLK32_SE0_EN, 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_SE0_GATE_DISABLE, 0,
SYMCLK32_ROOT_SE0_GATE_DISABLE, 0);
break;
case 1:
@@ -237,7 +244,8 @@ void dccg31_disable_symclk32_se(
SYMCLK32_SE1_SRC_SEL, 0,
SYMCLK32_SE1_EN, 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_SE1_GATE_DISABLE, 0,
SYMCLK32_ROOT_SE1_GATE_DISABLE, 0);
break;
case 2:
@@ -245,7 +253,8 @@ void dccg31_disable_symclk32_se(
SYMCLK32_SE2_SRC_SEL, 0,
SYMCLK32_SE2_EN, 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_SE2_GATE_DISABLE, 0,
SYMCLK32_ROOT_SE2_GATE_DISABLE, 0);
break;
case 3:
@@ -253,7 +262,8 @@ void dccg31_disable_symclk32_se(
SYMCLK32_SE3_SRC_SEL, 0,
SYMCLK32_SE3_EN, 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_se)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_SE3_GATE_DISABLE, 0,
SYMCLK32_ROOT_SE3_GATE_DISABLE, 0);
break;
default:
@@ -275,7 +285,8 @@ void dccg31_enable_symclk32_le(
switch (hpo_le_inst) {
case 0:
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_LE0_GATE_DISABLE, 1,
SYMCLK32_ROOT_LE0_GATE_DISABLE, 1);
REG_UPDATE_2(SYMCLK32_LE_CNTL,
SYMCLK32_LE0_SRC_SEL, phyd32clk,
@@ -283,7 +294,8 @@ void dccg31_enable_symclk32_le(
break;
case 1:
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_LE1_GATE_DISABLE, 1,
SYMCLK32_ROOT_LE1_GATE_DISABLE, 1);
REG_UPDATE_2(SYMCLK32_LE_CNTL,
SYMCLK32_LE1_SRC_SEL, phyd32clk,
@@ -308,7 +320,8 @@ void dccg31_disable_symclk32_le(
SYMCLK32_LE0_SRC_SEL, 0,
SYMCLK32_LE0_EN, 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_LE0_GATE_DISABLE, 0,
SYMCLK32_ROOT_LE0_GATE_DISABLE, 0);
break;
case 1:
@@ -316,7 +329,8 @@ void dccg31_disable_symclk32_le(
SYMCLK32_LE1_SRC_SEL, 0,
SYMCLK32_LE1_EN, 0);
if (dccg->ctx->dc->debug.root_clock_optimization.bits.symclk32_le)
- REG_UPDATE(DCCG_GATE_DISABLE_CNTL3,
+ REG_UPDATE_2(DCCG_GATE_DISABLE_CNTL3,
+ SYMCLK32_LE1_GATE_DISABLE, 0,
SYMCLK32_ROOT_LE1_GATE_DISABLE, 0);
break;
default:
@@ -406,54 +420,89 @@ void dccg31_set_physymclk(
/* Force PHYSYMCLK on and Select phyd32clk as the source of clock which is output to PHY through DCIO */
switch (phy_inst) {
case 0:
- if (force_enable)
+ if (force_enable) {
REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
PHYASYMCLK_FORCE_EN, 1,
PHYASYMCLK_FORCE_SRC_SEL, clk_src);
- else
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYASYMCLK_GATE_DISABLE, 1);
+ } else {
REG_UPDATE_2(PHYASYMCLK_CLOCK_CNTL,
PHYASYMCLK_FORCE_EN, 0,
PHYASYMCLK_FORCE_SRC_SEL, 0);
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYASYMCLK_GATE_DISABLE, 0);
+ }
break;
case 1:
- if (force_enable)
+ if (force_enable) {
REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
PHYBSYMCLK_FORCE_EN, 1,
PHYBSYMCLK_FORCE_SRC_SEL, clk_src);
- else
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYBSYMCLK_GATE_DISABLE, 1);
+ } else {
REG_UPDATE_2(PHYBSYMCLK_CLOCK_CNTL,
PHYBSYMCLK_FORCE_EN, 0,
PHYBSYMCLK_FORCE_SRC_SEL, 0);
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYBSYMCLK_GATE_DISABLE, 0);
+ }
break;
case 2:
- if (force_enable)
+ if (force_enable) {
REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
PHYCSYMCLK_FORCE_EN, 1,
PHYCSYMCLK_FORCE_SRC_SEL, clk_src);
- else
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYCSYMCLK_GATE_DISABLE, 1);
+ } else {
REG_UPDATE_2(PHYCSYMCLK_CLOCK_CNTL,
PHYCSYMCLK_FORCE_EN, 0,
PHYCSYMCLK_FORCE_SRC_SEL, 0);
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYCSYMCLK_GATE_DISABLE, 0);
+ }
break;
case 3:
- if (force_enable)
+ if (force_enable) {
REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
PHYDSYMCLK_FORCE_EN, 1,
PHYDSYMCLK_FORCE_SRC_SEL, clk_src);
- else
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYDSYMCLK_GATE_DISABLE, 1);
+ } else {
REG_UPDATE_2(PHYDSYMCLK_CLOCK_CNTL,
PHYDSYMCLK_FORCE_EN, 0,
PHYDSYMCLK_FORCE_SRC_SEL, 0);
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYDSYMCLK_GATE_DISABLE, 0);
+ }
break;
case 4:
- if (force_enable)
+ if (force_enable) {
REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
PHYESYMCLK_FORCE_EN, 1,
PHYESYMCLK_FORCE_SRC_SEL, clk_src);
- else
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYESYMCLK_GATE_DISABLE, 1);
+ } else {
REG_UPDATE_2(PHYESYMCLK_CLOCK_CNTL,
PHYESYMCLK_FORCE_EN, 0,
PHYESYMCLK_FORCE_SRC_SEL, 0);
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk)
+ REG_UPDATE(DCCG_GATE_DISABLE_CNTL2,
+ PHYESYMCLK_GATE_DISABLE, 0);
+ }
break;
default:
BREAK_TO_DEBUGGER();
@@ -464,12 +513,10 @@ void dccg31_set_physymclk(
/* Controls the generation of pixel valid for OTG in (OTG -> HPO case) */
static void dccg31_set_dtbclk_dto(
struct dccg *dccg,
- int dtbclk_inst,
- int req_dtbclk_khz,
- int num_odm_segments,
- const struct dc_crtc_timing *timing)
+ struct dtbclk_dto_params *params)
{
struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+ int req_dtbclk_khz = params->pixclk_khz;
uint32_t dtbdto_div;
/* Mode DTBDTO Rate DTBCLK_DTO<x>_DIV Register
@@ -480,57 +527,53 @@ static void dccg31_set_dtbclk_dto(
* DSC native 4:2:2 pixel rate/2 4
* Other modes pixel rate 8
*/
- if (num_odm_segments == 4) {
+ if (params->num_odm_segments == 4) {
dtbdto_div = 2;
- req_dtbclk_khz = req_dtbclk_khz / 4;
- } else if ((num_odm_segments == 2) ||
- (timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ||
- (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
- && !timing->dsc_cfg.ycbcr422_simple)) {
+ req_dtbclk_khz = params->pixclk_khz / 4;
+ } else if ((params->num_odm_segments == 2) ||
+ (params->timing->pixel_encoding == PIXEL_ENCODING_YCBCR420) ||
+ (params->timing->flags.DSC && params->timing->pixel_encoding == PIXEL_ENCODING_YCBCR422
+ && !params->timing->dsc_cfg.ycbcr422_simple)) {
dtbdto_div = 4;
- req_dtbclk_khz = req_dtbclk_khz / 2;
+ req_dtbclk_khz = params->pixclk_khz / 2;
} else
dtbdto_div = 8;
- if (dccg->ref_dtbclk_khz && req_dtbclk_khz) {
+ if (params->ref_dtbclk_khz && req_dtbclk_khz) {
uint32_t modulo, phase;
// phase / modulo = dtbclk / dtbclk ref
- modulo = dccg->ref_dtbclk_khz * 1000;
- phase = div_u64((((unsigned long long)modulo * req_dtbclk_khz) + dccg->ref_dtbclk_khz - 1),
- dccg->ref_dtbclk_khz);
+ modulo = params->ref_dtbclk_khz * 1000;
+ phase = div_u64((((unsigned long long)modulo * req_dtbclk_khz) + params->ref_dtbclk_khz - 1),
+ params->ref_dtbclk_khz);
- REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
- DTBCLK_DTO_DIV[dtbclk_inst], dtbdto_div);
+ REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],
+ DTBCLK_DTO_DIV[params->otg_inst], dtbdto_div);
- REG_WRITE(DTBCLK_DTO_MODULO[dtbclk_inst], modulo);
- REG_WRITE(DTBCLK_DTO_PHASE[dtbclk_inst], phase);
+ REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], modulo);
+ REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], phase);
- REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
- DTBCLK_DTO_ENABLE[dtbclk_inst], 1);
+ REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],
+ DTBCLK_DTO_ENABLE[params->otg_inst], 1);
- REG_WAIT(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
- DTBCLKDTO_ENABLE_STATUS[dtbclk_inst], 1,
+ REG_WAIT(OTG_PIXEL_RATE_CNTL[params->otg_inst],
+ DTBCLKDTO_ENABLE_STATUS[params->otg_inst], 1,
1, 100);
/* The recommended programming sequence to enable DTBCLK DTO to generate
* valid pixel HPO DPSTREAM ENCODER, specifies that DTO source select should
* be set only after DTO is enabled
*/
- REG_UPDATE(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
- PIPE_DTO_SRC_SEL[dtbclk_inst], 1);
-
- dccg->dtbclk_khz[dtbclk_inst] = req_dtbclk_khz;
+ REG_UPDATE(OTG_PIXEL_RATE_CNTL[params->otg_inst],
+ PIPE_DTO_SRC_SEL[params->otg_inst], 1);
} else {
- REG_UPDATE_3(OTG_PIXEL_RATE_CNTL[dtbclk_inst],
- DTBCLK_DTO_ENABLE[dtbclk_inst], 0,
- PIPE_DTO_SRC_SEL[dtbclk_inst], 0,
- DTBCLK_DTO_DIV[dtbclk_inst], dtbdto_div);
+ REG_UPDATE_3(OTG_PIXEL_RATE_CNTL[params->otg_inst],
+ DTBCLK_DTO_ENABLE[params->otg_inst], 0,
+ PIPE_DTO_SRC_SEL[params->otg_inst], 0,
+ DTBCLK_DTO_DIV[params->otg_inst], dtbdto_div);
- REG_WRITE(DTBCLK_DTO_MODULO[dtbclk_inst], 0);
- REG_WRITE(DTBCLK_DTO_PHASE[dtbclk_inst], 0);
-
- dccg->dtbclk_khz[dtbclk_inst] = 0;
+ REG_WRITE(DTBCLK_DTO_MODULO[params->otg_inst], 0);
+ REG_WRITE(DTBCLK_DTO_PHASE[params->otg_inst], 0);
}
}
@@ -557,16 +600,12 @@ void dccg31_set_audio_dtbclk_dto(
REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
DCCG_AUDIO_DTO_SEL, 4); // 04 - DCCG_AUDIO_DTO_SEL_AUDIO_DTO_DTBCLK
-
- dccg->audio_dtbclk_khz = req_audio_dtbclk_khz;
} else {
REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_PHASE, 0);
REG_WRITE(DCCG_AUDIO_DTBCLK_DTO_MODULO, 0);
REG_UPDATE(DCCG_AUDIO_DTO_SOURCE,
DCCG_AUDIO_DTO_SEL, 3); // 03 - DCCG_AUDIO_DTO_SEL_NO_AUDIO_DTO
-
- dccg->audio_dtbclk_khz = 0;
}
}
@@ -615,6 +654,13 @@ void dccg31_init(struct dccg *dccg)
dccg31_disable_dpstreamclk(dccg, 3);
}
+ if (dccg->ctx->dc->debug.root_clock_optimization.bits.physymclk) {
+ dccg31_set_physymclk(dccg, 0, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
+ dccg31_set_physymclk(dccg, 1, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
+ dccg31_set_physymclk(dccg, 2, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
+ dccg31_set_physymclk(dccg, 3, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
+ dccg31_set_physymclk(dccg, 4, PHYSYMCLK_FORCE_SRC_SYMCLK, false);
+ }
}
static const struct dccg_funcs dccg31_funcs = {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
index a013a32bbaf7..269cabbea72a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.h
@@ -66,6 +66,7 @@
SR(DSCCLK1_DTO_PARAM),\
SR(DSCCLK2_DTO_PARAM),\
SR(DSCCLK_DTO_CTRL),\
+ SR(DCCG_GATE_DISABLE_CNTL2),\
SR(DCCG_GATE_DISABLE_CNTL3),\
SR(HDMISTREAMCLK0_DTO_PARAM)
@@ -135,6 +136,11 @@
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK0_DTO_ENABLE, mask_sh),\
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK1_DTO_ENABLE, mask_sh),\
DCCG_SF(DSCCLK_DTO_CTRL, DSCCLK2_DTO_ENABLE, mask_sh),\
+ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYASYMCLK_GATE_DISABLE, mask_sh),\
+ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYBSYMCLK_GATE_DISABLE, mask_sh),\
+ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYCSYMCLK_GATE_DISABLE, mask_sh),\
+ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYDSYMCLK_GATE_DISABLE, mask_sh),\
+ DCCG_SF(DCCG_GATE_DISABLE_CNTL2, PHYESYMCLK_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, DPSTREAMCLK_ROOT_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, DPSTREAMCLK_GATE_DISABLE, mask_sh),\
DCCG_SF(DCCG_GATE_DISABLE_CNTL3, SYMCLK32_ROOT_SE0_GATE_DISABLE, mask_sh),\
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
index 8b9b1a5309ba..8b12b4111c88 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dio_link_encoder.c
@@ -230,9 +230,7 @@ static void enc31_hw_init(struct link_encoder *enc)
AUX_RX_PHASE_DETECT_LEN, [21,20] = 0x3 default is 3
AUX_RX_DETECTION_THRESHOLD [30:28] = 1
*/
- AUX_REG_WRITE(AUX_DPHY_RX_CONTROL0, 0x103d1110);
-
- AUX_REG_WRITE(AUX_DPHY_TX_CONTROL, 0x21c7a);
+ // dmub will read AUX_DPHY_RX_CONTROL0/AUX_DPHY_TX_CONTROL from vbios table in dp_aux_init
//AUX_DPHY_TX_REF_CONTROL'AUX_TX_REF_DIV HW default is 0x32;
// Set AUX_TX_REF_DIV Divider to generate 2 MHz reference from refclk
@@ -240,18 +238,9 @@ static void enc31_hw_init(struct link_encoder *enc)
// 100MHz -> 0x32
// 48MHz -> 0x18
-#ifdef CLEANUP_FIXME
- /*from display_init*/
- REG_WRITE(RDPCSTX_DEBUG_CONFIG, 0);
-#endif
-
// Set TMDS_CTL0 to 1. This is a legacy setting.
REG_UPDATE(TMDS_CTL_BITS, TMDS_CTL0, 1);
- /*HW default is 5*/
- REG_UPDATE(RDPCSTX_CNTL,
- RDPCS_TX_FIFO_RD_START_DELAY, 4);
-
dcn10_aux_initialize(enc10);
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
index 5065904c7833..23621ff08c90 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.c
@@ -710,6 +710,16 @@ static void dcn31_hpo_dp_stream_enc_read_state(
}
}
+static void dcn31_set_hblank_min_symbol_width(
+ struct hpo_dp_stream_encoder *enc,
+ uint16_t width)
+{
+ struct dcn31_hpo_dp_stream_encoder *enc3 = DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(enc);
+
+ REG_SET(DP_SYM32_ENC_HBLANK_CONTROL, 0,
+ HBLANK_MINIMUM_SYMBOL_WIDTH, width);
+}
+
static const struct hpo_dp_stream_encoder_funcs dcn30_str_enc_funcs = {
.enable_stream = dcn31_hpo_dp_stream_enc_enable_stream,
.dp_unblank = dcn31_hpo_dp_stream_enc_dp_unblank,
@@ -725,6 +735,7 @@ static const struct hpo_dp_stream_encoder_funcs dcn30_str_enc_funcs = {
.dp_audio_enable = dcn31_hpo_dp_stream_enc_audio_enable,
.dp_audio_disable = dcn31_hpo_dp_stream_enc_audio_disable,
.read_state = dcn31_hpo_dp_stream_enc_read_state,
+ .set_hblank_min_symbol_width = dcn31_set_hblank_min_symbol_width,
};
void dcn31_hpo_dp_stream_encoder_construct(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h
index 70b94fc25304..7c77c71591a0 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hpo_dp_stream_encoder.h
@@ -80,7 +80,8 @@
SRI(DP_SYM32_ENC_SDP_GSP_CONTROL11, DP_SYM32_ENC, id),\
SRI(DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL, DP_SYM32_ENC, id),\
SRI(DP_SYM32_ENC_SDP_AUDIO_CONTROL0, DP_SYM32_ENC, id),\
- SRI(DP_SYM32_ENC_VID_CRC_CONTROL, DP_SYM32_ENC, id)
+ SRI(DP_SYM32_ENC_VID_CRC_CONTROL, DP_SYM32_ENC, id), \
+ SRI(DP_SYM32_ENC_HBLANK_CONTROL, DP_SYM32_ENC, id)
#define DCN3_1_HPO_DP_STREAM_ENC_REGS \
uint32_t DP_STREAM_MAPPER_CONTROL0;\
@@ -116,7 +117,8 @@
uint32_t DP_SYM32_ENC_SDP_GSP_CONTROL11;\
uint32_t DP_SYM32_ENC_SDP_METADATA_PACKET_CONTROL;\
uint32_t DP_SYM32_ENC_SDP_AUDIO_CONTROL0;\
- uint32_t DP_SYM32_ENC_VID_CRC_CONTROL
+ uint32_t DP_SYM32_ENC_VID_CRC_CONTROL;\
+ uint32_t DP_SYM32_ENC_HBLANK_CONTROL
#define DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(mask_sh)\
@@ -202,7 +204,8 @@
type GSP_SOF_REFERENCE;\
type METADATA_PACKET_ENABLE;\
type CRC_ENABLE;\
- type CRC_CONT_MODE_ENABLE
+ type CRC_CONT_MODE_ENABLE;\
+ type HBLANK_MINIMUM_SYMBOL_WIDTH
struct dcn31_hpo_dp_stream_encoder_registers {
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
index 5e3bcaf12cac..51c5f3685470 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
@@ -949,6 +949,65 @@ static void hubbub31_get_dchub_ref_freq(struct hubbub *hubbub,
}
}
+static bool hubbub31_verify_allow_pstate_change_high(struct hubbub *hubbub)
+{
+ struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);
+
+ /*
+ * Pstate latency is ~20us so if we wait over 40us and pstate allow
+ * still not asserted, we are probably stuck and going to hang
+ */
+ const unsigned int pstate_wait_timeout_us = 100;
+ const unsigned int pstate_wait_expected_timeout_us = 40;
+
+ static unsigned int max_sampled_pstate_wait_us; /* data collection */
+ static bool forced_pstate_allow; /* help with revert wa */
+
+ unsigned int debug_data = 0;
+ unsigned int i;
+
+ if (forced_pstate_allow) {
+ /* we hacked to force pstate allow to prevent hang last time
+ * we verify_allow_pstate_change_high. so disable force
+ * here so we can check status
+ */
+ REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
+ DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0,
+ DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0);
+ forced_pstate_allow = false;
+ }
+
+ REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub2->debug_test_index_pstate);
+
+ for (i = 0; i < pstate_wait_timeout_us; i++) {
+ debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);
+
+ /* Debug bit is specific to ASIC. */
+ if (debug_data & (1 << 26)) {
+ if (i > pstate_wait_expected_timeout_us)
+ DC_LOG_WARNING("pstate took longer than expected ~%dus\n", i);
+ return true;
+ }
+ if (max_sampled_pstate_wait_us < i)
+ max_sampled_pstate_wait_us = i;
+
+ udelay(1);
+ }
+
+ /* force pstate allow to prevent system hang
+ * and break to debugger to investigate
+ */
+ REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
+ DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1,
+ DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1);
+ forced_pstate_allow = true;
+
+ DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n",
+ debug_data);
+
+ return false;
+}
+
static const struct hubbub_funcs hubbub31_funcs = {
.update_dchub = hubbub2_update_dchub,
.init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx,
@@ -961,6 +1020,7 @@ static const struct hubbub_funcs hubbub31_funcs = {
.program_watermarks = hubbub31_program_watermarks,
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
+ .verify_allow_pstate_change_high = hubbub31_verify_allow_pstate_change_high,
.program_det_size = dcn31_program_det_size,
.program_compbuf_size = dcn31_program_compbuf_size,
.init_crb = dcn31_init_crb,
@@ -982,5 +1042,7 @@ void hubbub31_construct(struct dcn20_hubbub *hubbub31,
hubbub31->detile_buf_size = det_size_kb * 1024;
hubbub31->pixel_chunk_size = pixel_chunk_size_kb * 1024;
hubbub31->crb_size_segs = config_return_buffer_size_kb / DCN31_CRB_SEGMENT_SIZE_KB;
+
+ hubbub31->debug_test_index_pstate = 0x6;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c
index 53b792b997b7..197a5cae068b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubp.c
@@ -54,6 +54,14 @@ void hubp31_soft_reset(struct hubp *hubp, bool reset)
REG_UPDATE(DCHUBP_CNTL, HUBP_SOFT_RESET, reset);
}
+static void hubp31_program_extended_blank(struct hubp *hubp,
+ unsigned int min_dst_y_next_start_optimized)
+{
+ struct dcn20_hubp *hubp2 = TO_DCN20_HUBP(hubp);
+
+ REG_SET(BLANK_OFFSET_1, 0, MIN_DST_Y_NEXT_START, min_dst_y_next_start_optimized);
+}
+
static struct hubp_funcs dcn31_hubp_funcs = {
.hubp_enable_tripleBuffer = hubp2_enable_triplebuffer,
.hubp_is_triplebuffer_enabled = hubp2_is_triplebuffer_enabled,
@@ -80,6 +88,7 @@ static struct hubp_funcs dcn31_hubp_funcs = {
.set_unbounded_requesting = hubp31_set_unbounded_requesting,
.hubp_soft_reset = hubp31_soft_reset,
.hubp_in_blank = hubp1_in_blank,
+ .program_extended_blank = hubp31_program_extended_blank,
};
bool hubp31_construct(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
index 4206ce5bf9a9..531dd2c65007 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
@@ -188,17 +188,23 @@ void dcn31_init_hw(struct dc *dc)
/* Check for enabled DIG to identify enabled display */
if (link->link_enc->funcs->is_dig_enabled &&
- link->link_enc->funcs->is_dig_enabled(link->link_enc))
+ link->link_enc->funcs->is_dig_enabled(link->link_enc)) {
link->link_status.link_active = true;
+ if (link->link_enc->funcs->fec_is_active &&
+ link->link_enc->funcs->fec_is_active(link->link_enc))
+ link->fec_state = dc_link_fec_enabled;
+ }
}
/* Enables outbox notifications for usb4 dpia */
if (dc->res_pool->usb4_dpia_count)
- dmub_enable_outbox_notification(dc);
+ dmub_enable_outbox_notification(dc->ctx->dmub_srv);
/* we want to turn off all dp displays before doing detection */
- if (dc->config.power_down_display_on_boot)
- dc_link_blank_all_dp_displays(dc);
+ dc_link_blank_all_dp_displays(dc);
+
+ if (hws->funcs.enable_power_gating_plane)
+ hws->funcs.enable_power_gating_plane(dc->hwseq, true);
/* If taking control over from VBIOS, we may want to optimize our first
* mode set, so we need to skip powering down pipes until we know which
@@ -206,7 +212,7 @@ void dcn31_init_hw(struct dc *dc)
* Otherwise, if taking control is not possible, we need to power
* everything down.
*/
- if (dcb->funcs->is_accelerated_mode(dcb) || dc->config.power_down_display_on_boot) {
+ if (dcb->funcs->is_accelerated_mode(dcb) || !dc->config.seamless_boot_edp_requested) {
hws->funcs.init_pipes(dc, dc->current_state);
if (dc->res_pool->hubbub->funcs->allow_self_refresh_control)
dc->res_pool->hubbub->funcs->allow_self_refresh_control(dc->res_pool->hubbub,
@@ -249,8 +255,6 @@ void dcn31_init_hw(struct dc *dc)
REG_UPDATE(DCFCLK_CNTL, DCFCLK_GATE_DIS, 0);
}
- if (hws->funcs.enable_power_gating_plane)
- hws->funcs.enable_power_gating_plane(dc->hwseq, true);
if (!dcb->funcs->is_accelerated_mode(dcb) && dc->res_pool->hubbub->funcs->init_watermarks)
dc->res_pool->hubbub->funcs->init_watermarks(dc->res_pool->hubbub);
@@ -339,22 +343,32 @@ void dcn31_enable_power_gating_plane(
bool enable)
{
bool force_on = true; /* disable power gating */
+ uint32_t org_ip_request_cntl = 0;
- if (enable)
+ if (enable && !hws->ctx->dc->debug.disable_hubp_power_gate)
force_on = false;
+ REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
+ if (org_ip_request_cntl == 0)
+ REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
/* DCHUBP0/1/2/3/4/5 */
REG_UPDATE(DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
REG_UPDATE(DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
-
/* DPP0/1/2/3/4/5 */
REG_UPDATE(DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
REG_UPDATE(DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+ force_on = true; /* disable power gating */
+ if (enable && !hws->ctx->dc->debug.disable_dsc_power_gate)
+ force_on = false;
+
/* DCS0/1/2/3/4/5 */
REG_UPDATE(DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
REG_UPDATE(DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
REG_UPDATE(DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, force_on);
+
+ if (org_ip_request_cntl == 0)
+ REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
}
void dcn31_update_info_frame(struct pipe_ctx *pipe_ctx)
@@ -420,12 +434,15 @@ void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool p
{
uint32_t power_gate = power_on ? 0 : 1;
uint32_t pwr_status = power_on ? 0 : 2;
-
+ uint32_t org_ip_request_cntl;
if (hws->ctx->dc->debug.disable_hubp_power_gate)
return;
if (REG(DOMAIN0_PG_CONFIG) == 0)
return;
+ REG_GET(DC_IP_REQUEST_CNTL, IP_REQUEST_EN, &org_ip_request_cntl);
+ if (org_ip_request_cntl == 0)
+ REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 1);
switch (hubp_inst) {
case 0:
@@ -448,6 +465,8 @@ void dcn31_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool p
BREAK_TO_DEBUGGER();
break;
}
+ if (org_ip_request_cntl == 0)
+ REG_SET(DC_IP_REQUEST_CNTL, 0, IP_REQUEST_EN, 0);
}
int dcn31_init_sys_ctx(struct dce_hwseq *hws, struct dc *dc, struct dc_phy_addr_space_config *pa_config)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
index d7559e5a99ce..e708f07fe75a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_init.c
@@ -153,9 +153,4 @@ void dcn31_hw_sequencer_construct(struct dc *dc)
dc->hwss.init_hw = dcn20_fpga_init_hw;
dc->hwseq->funcs.init_pipes = NULL;
}
- if (dc->debug.disable_z10) {
- /*hw not support z10 or sw disable it*/
- dc->hwss.z10_restore = NULL;
- dc->hwss.z10_save_init = NULL;
- }
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
index e8562fa11366..c51f7dca94f8 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
@@ -91,8 +91,7 @@ static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, i
optc1->opp_count = opp_cnt;
}
-/**
- * Enable CRTC
+/*
* Enable CRTC - call ASIC Control Object to enable Timing generator.
*/
static bool optc31_enable_crtc(struct timing_generator *optc)
@@ -124,7 +123,6 @@ static bool optc31_enable_crtc(struct timing_generator *optc)
static bool optc31_disable_crtc(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
-
/* disable otg request until end of the first line
* in the vertical blank region
*/
@@ -138,6 +136,7 @@ static bool optc31_disable_crtc(struct timing_generator *optc)
REG_WAIT(OTG_CLOCK_CONTROL,
OTG_BUSY, 0,
1, 100000);
+ optc1_clear_optc_underflow(optc);
return true;
}
@@ -158,10 +157,13 @@ static bool optc31_immediate_disable_crtc(struct timing_generator *optc)
OTG_BUSY, 0,
1, 100000);
+ /* clear the false state */
+ optc1_clear_optc_underflow(optc);
+
return true;
}
-static void optc31_set_drr(
+void optc31_set_drr(
struct timing_generator *optc,
const struct drr_params *params)
{
@@ -211,6 +213,26 @@ static void optc31_set_drr(
}
}
+void optc3_init_odm(struct timing_generator *optc)
+{
+ struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+ REG_SET_5(OPTC_DATA_SOURCE_SELECT, 0,
+ OPTC_NUM_OF_INPUT_SEGMENT, 0,
+ OPTC_SEG0_SRC_SEL, optc->inst,
+ OPTC_SEG1_SRC_SEL, 0xf,
+ OPTC_SEG2_SRC_SEL, 0xf,
+ OPTC_SEG3_SRC_SEL, 0xf
+ );
+
+ REG_SET(OTG_H_TIMING_CNTL, 0,
+ OTG_H_TIMING_DIV_MODE, 0);
+
+ REG_SET(OPTC_MEMORY_CONFIG, 0,
+ OPTC_MEM_SEL, 0);
+ optc1->opp_count = 1;
+}
+
static struct timing_generator_funcs dcn31_tg_funcs = {
.validate_timing = optc1_validate_timing,
.program_timing = optc1_program_timing,
@@ -270,6 +292,7 @@ static struct timing_generator_funcs dcn31_tg_funcs = {
.program_manual_trigger = optc2_program_manual_trigger,
.setup_manual_trigger = optc2_setup_manual_trigger,
.get_hw_timing = optc1_get_hw_timing,
+ .init_odm = optc3_init_odm,
};
void dcn31_timing_generator_init(struct optc *optc1)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
index d8ef2f0d0c95..9e881f2ce74b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.h
@@ -256,4 +256,8 @@
void dcn31_timing_generator_init(struct optc *optc1);
+void optc31_set_drr(struct timing_generator *optc, const struct drr_params *params);
+
+void optc3_init_odm(struct timing_generator *optc);
+
#endif /* __DC_OPTC_DCN31_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c
index 83ece02380a8..11ea9d13e312 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_panel_cntl.c
@@ -83,7 +83,8 @@ static uint32_t dcn31_panel_cntl_hw_init(struct panel_cntl *panel_cntl)
cmd.panel_cntl.data.bl_pwm_period_cntl = panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL;
cmd.panel_cntl.data.bl_pwm_ref_div1 =
panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV;
-
+ cmd.panel_cntl.data.bl_pwm_ref_div2 =
+ panel_cntl->stored_backlight_registers.PANEL_PWRSEQ_REF_DIV2;
if (!dc_dmub_srv_cmd_with_reply_data(dc_dmub_srv, &cmd))
return 0;
@@ -92,6 +93,8 @@ static uint32_t dcn31_panel_cntl_hw_init(struct panel_cntl *panel_cntl)
panel_cntl->stored_backlight_registers.BL_PWM_PERIOD_CNTL = cmd.panel_cntl.data.bl_pwm_period_cntl;
panel_cntl->stored_backlight_registers.LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV =
cmd.panel_cntl.data.bl_pwm_ref_div1;
+ panel_cntl->stored_backlight_registers.PANEL_PWRSEQ_REF_DIV2 =
+ cmd.panel_cntl.data.bl_pwm_ref_div2;
return cmd.panel_cntl.data.current_backlight;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
index 8d64187478e4..3d9f07d4770b 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
@@ -36,6 +36,8 @@
#include "dcn20/dcn20_resource.h"
#include "dcn30/dcn30_resource.h"
+#include "dml/dcn30/dcn30_fpu.h"
+
#include "dcn10/dcn10_ipp.h"
#include "dcn30/dcn30_hubbub.h"
#include "dcn31/dcn31_hubbub.h"
@@ -65,6 +67,7 @@
#include "virtual/virtual_stream_encoder.h"
#include "dce110/dce110_resource.h"
#include "dml/display_mode_vba.h"
+#include "dml/dcn31/dcn31_fpu.h"
#include "dcn31/dcn31_dccg.h"
#include "dcn10/dcn10_resource.h"
#include "dcn31_panel_cntl.h"
@@ -102,152 +105,6 @@
#define DC_LOGGER_INIT(logger)
-#define DCN3_1_DEFAULT_DET_SIZE 384
-
-struct _vcs_dpi_ip_params_st dcn3_1_ip = {
- .gpuvm_enable = 1,
- .gpuvm_max_page_table_levels = 1,
- .hostvm_enable = 1,
- .hostvm_max_page_table_levels = 2,
- .rob_buffer_size_kbytes = 64,
- .det_buffer_size_kbytes = DCN3_1_DEFAULT_DET_SIZE,
- .config_return_buffer_size_in_kbytes = 1792,
- .compressed_buffer_segment_size_in_kbytes = 64,
- .meta_fifo_size_in_kentries = 32,
- .zero_size_buffer_entries = 512,
- .compbuf_reserved_space_64b = 256,
- .compbuf_reserved_space_zs = 64,
- .dpp_output_buffer_pixels = 2560,
- .opp_output_buffer_lines = 1,
- .pixel_chunk_size_kbytes = 8,
- .meta_chunk_size_kbytes = 2,
- .min_meta_chunk_size_bytes = 256,
- .writeback_chunk_size_kbytes = 8,
- .ptoi_supported = false,
- .num_dsc = 3,
- .maximum_dsc_bits_per_component = 10,
- .dsc422_native_support = false,
- .is_line_buffer_bpp_fixed = true,
- .line_buffer_fixed_bpp = 48,
- .line_buffer_size_bits = 789504,
- .max_line_buffer_lines = 12,
- .writeback_interface_buffer_size_kbytes = 90,
- .max_num_dpp = 4,
- .max_num_otg = 4,
- .max_num_hdmi_frl_outputs = 1,
- .max_num_wb = 1,
- .max_dchub_pscl_bw_pix_per_clk = 4,
- .max_pscl_lb_bw_pix_per_clk = 2,
- .max_lb_vscl_bw_pix_per_clk = 4,
- .max_vscl_hscl_bw_pix_per_clk = 4,
- .max_hscl_ratio = 6,
- .max_vscl_ratio = 6,
- .max_hscl_taps = 8,
- .max_vscl_taps = 8,
- .dpte_buffer_size_in_pte_reqs_luma = 64,
- .dpte_buffer_size_in_pte_reqs_chroma = 34,
- .dispclk_ramp_margin_percent = 1,
- .max_inter_dcn_tile_repeaters = 8,
- .cursor_buffer_size = 16,
- .cursor_chunk_size = 2,
- .writeback_line_buffer_buffer_size = 0,
- .writeback_min_hscl_ratio = 1,
- .writeback_min_vscl_ratio = 1,
- .writeback_max_hscl_ratio = 1,
- .writeback_max_vscl_ratio = 1,
- .writeback_max_hscl_taps = 1,
- .writeback_max_vscl_taps = 1,
- .dppclk_delay_subtotal = 46,
- .dppclk_delay_scl = 50,
- .dppclk_delay_scl_lb_only = 16,
- .dppclk_delay_cnvc_formatter = 27,
- .dppclk_delay_cnvc_cursor = 6,
- .dispclk_delay_subtotal = 119,
- .dynamic_metadata_vm_enabled = false,
- .odm_combine_4to1_supported = false,
- .dcc_supported = true,
-};
-
-struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc = {
- /*TODO: correct dispclk/dppclk voltage level determination*/
- .clock_limits = {
- {
- .state = 0,
- .dispclk_mhz = 1200.0,
- .dppclk_mhz = 1200.0,
- .phyclk_mhz = 600.0,
- .phyclk_d18_mhz = 667.0,
- .dscclk_mhz = 186.0,
- .dtbclk_mhz = 625.0,
- },
- {
- .state = 1,
- .dispclk_mhz = 1200.0,
- .dppclk_mhz = 1200.0,
- .phyclk_mhz = 810.0,
- .phyclk_d18_mhz = 667.0,
- .dscclk_mhz = 209.0,
- .dtbclk_mhz = 625.0,
- },
- {
- .state = 2,
- .dispclk_mhz = 1200.0,
- .dppclk_mhz = 1200.0,
- .phyclk_mhz = 810.0,
- .phyclk_d18_mhz = 667.0,
- .dscclk_mhz = 209.0,
- .dtbclk_mhz = 625.0,
- },
- {
- .state = 3,
- .dispclk_mhz = 1200.0,
- .dppclk_mhz = 1200.0,
- .phyclk_mhz = 810.0,
- .phyclk_d18_mhz = 667.0,
- .dscclk_mhz = 371.0,
- .dtbclk_mhz = 625.0,
- },
- {
- .state = 4,
- .dispclk_mhz = 1200.0,
- .dppclk_mhz = 1200.0,
- .phyclk_mhz = 810.0,
- .phyclk_d18_mhz = 667.0,
- .dscclk_mhz = 417.0,
- .dtbclk_mhz = 625.0,
- },
- },
- .num_states = 5,
- .sr_exit_time_us = 9.0,
- .sr_enter_plus_exit_time_us = 11.0,
- .sr_exit_z8_time_us = 442.0,
- .sr_enter_plus_exit_z8_time_us = 560.0,
- .writeback_latency_us = 12.0,
- .dram_channel_width_bytes = 4,
- .round_trip_ping_latency_dcfclk_cycles = 106,
- .urgent_latency_pixel_data_only_us = 4.0,
- .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
- .urgent_latency_vm_data_only_us = 4.0,
- .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
- .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
- .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
- .pct_ideal_sdp_bw_after_urgent = 80.0,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 65.0,
- .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
- .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0,
- .max_avg_sdp_bw_use_normal_percent = 60.0,
- .max_avg_dram_bw_use_normal_percent = 60.0,
- .fabric_datapath_to_dcn_data_return_bytes = 32,
- .return_bus_width_bytes = 64,
- .downspread_percent = 0.38,
- .dcn_downspread_percent = 0.5,
- .gpuvm_min_page_size_bytes = 4096,
- .hostvm_min_page_size_bytes = 4096,
- .do_urgent_latency_adjustment = false,
- .urgent_latency_adjustment_fabric_clock_component_us = 0,
- .urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
-};
-
enum dcn31_clk_src_array_id {
DCN31_CLK_SRC_PLL0,
DCN31_CLK_SRC_PLL1,
@@ -1011,7 +868,7 @@ static const struct dc_debug_options debug_defaults_drv = {
.max_downscale_src_width = 4096,/*upto true 4K*/
.disable_pplib_wm_range = false,
.scl_reset_length10 = true,
- .sanity_checks = false,
+ .sanity_checks = true,
.underflow_assert_delay_us = 0xFFFFFFFF,
.dwb_fi_phase = -1, // -1 = disable,
.dmub_command_table = true,
@@ -1030,9 +887,12 @@ static const struct dc_debug_options debug_defaults_drv = {
.afmt = true,
}
},
+ .disable_z10 = true,
.optimize_edp_link_rate = true,
.enable_sw_cntl_psr = true,
.apply_vendor_specific_lttpr_wa = true,
+ .enable_z9_disable_interface = true, /* Allow support for the PMFW interface for disable Z9*/
+ .dml_hostvm_override = DML_HOSTVM_OVERRIDE_FALSE,
};
static const struct dc_debug_options debug_defaults_diags = {
@@ -1390,12 +1250,6 @@ static struct stream_encoder *dcn31_stream_encoder_create(
return NULL;
}
- if (ctx->asic_id.chip_family == FAMILY_YELLOW_CARP &&
- ctx->asic_id.hw_internal_rev == YELLOW_CARP_B0) {
- if ((eng_id == ENGINE_ID_DIGC) || (eng_id == ENGINE_ID_DIGD))
- eng_id = eng_id + 3; // For B0 only. C->F, D->G.
- }
-
dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios,
eng_id, vpg, afmt,
&stream_enc_regs[eng_id],
@@ -1776,7 +1630,7 @@ static bool is_dual_plane(enum surface_pixel_format format)
return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA;
}
-static int dcn31_populate_dml_pipes_from_context(
+int dcn31_populate_dml_pipes_from_context(
struct dc *dc, struct dc_state *context,
display_e2e_pipe_params_st *pipes,
bool fast_validate)
@@ -1786,7 +1640,9 @@ static int dcn31_populate_dml_pipes_from_context(
struct pipe_ctx *pipe;
bool upscaled = false;
+ DC_FP_START();
dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ DC_FP_END();
for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
struct dc_crtc_timing *timing;
@@ -1807,7 +1663,6 @@ static int dcn31_populate_dml_pipes_from_context(
* intermittently experienced depending on peak b/w requirements.
*/
pipes[pipe_cnt].pipe.src.immediate_flip = true;
-
pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
pipes[pipe_cnt].pipe.src.gpuvm = true;
pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
@@ -1816,6 +1671,13 @@ static int dcn31_populate_dml_pipes_from_context(
pipes[pipe_cnt].pipe.src.dcc_rate = 3;
pipes[pipe_cnt].dout.dsc_input_bpc = 0;
+ if (dc->debug.dml_hostvm_override == DML_HOSTVM_NO_OVERRIDE)
+ pipes[pipe_cnt].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active;
+ else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_FALSE)
+ pipes[pipe_cnt].pipe.src.hostvm = false;
+ else if (dc->debug.dml_hostvm_override == DML_HOSTVM_OVERRIDE_TRUE)
+ pipes[pipe_cnt].pipe.src.hostvm = true;
+
if (pipes[pipe_cnt].dout.dsc_enable) {
switch (timing->display_color_depth) {
case COLOR_DEPTH_888:
@@ -1841,7 +1703,8 @@ static int dcn31_populate_dml_pipes_from_context(
if (is_dual_plane(pipe->plane_state->format)
&& pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) {
dc->config.enable_4to1MPC = true;
- } else if (!is_dual_plane(pipe->plane_state->format)) {
+ } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) {
+ /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */
context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192;
pipes[0].pipe.src.unbounded_req_mode = true;
}
@@ -1864,149 +1727,35 @@ void dcn31_update_soc_for_wm_a(struct dc *dc, struct dc_state *context)
}
}
-static void dcn31_calculate_wm_and_dlg_fp(
+void dcn31_calculate_wm_and_dlg(
struct dc *dc, struct dc_state *context,
display_e2e_pipe_params_st *pipes,
int pipe_cnt,
int vlevel)
{
- int i, pipe_idx;
- double dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
-
- if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk)
- dcfclk = context->bw_ctx.dml.soc.min_dcfclk;
-
- /* We don't recalculate clocks for 0 pipe configs, which can block
- * S0i3 as high clocks will block low power states
- * Override any clocks that can block S0i3 to min here
- */
- if (pipe_cnt == 0) {
- context->bw_ctx.bw.dcn.clk.dcfclk_khz = dcfclk; // always should be vlevel 0
- return;
- }
-
- pipes[0].clks_cfg.voltage = vlevel;
- pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
- pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
-
-#if 0 // TODO
- /* Set B:
- * TODO
- */
- if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid) {
- if (vlevel == 0) {
- pipes[0].clks_cfg.voltage = 1;
- pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dcfclk_mhz;
- }
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us;
- context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us;
- context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us;
- }
- context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
- pipes[0].clks_cfg.voltage = vlevel;
- pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
-
- /* Set C:
- * TODO
- */
- if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) {
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.pstate_latency_us;
- context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us;
- context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us;
- }
- context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.c.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-
- /* Set D:
- * TODO
- */
- if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].valid) {
- context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us;
- context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us;
- context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us;
- }
- context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.d.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
-#endif
-
- /* Set A:
- * All clocks min required
- *
- * Set A calculated last so that following calculations are based on Set A
- */
- dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
- context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- context->bw_ctx.bw.dcn.watermarks.a.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
- /* TODO: remove: */
- context->bw_ctx.bw.dcn.watermarks.b = context->bw_ctx.bw.dcn.watermarks.a;
- context->bw_ctx.bw.dcn.watermarks.c = context->bw_ctx.bw.dcn.watermarks.a;
- context->bw_ctx.bw.dcn.watermarks.d = context->bw_ctx.bw.dcn.watermarks.a;
- /* end remove*/
-
- for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
- if (!context->res_ctx.pipe_ctx[i].stream)
- continue;
-
- pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
- pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
-
- if (dc->config.forced_clocks || dc->debug.max_disp_clk) {
- pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
- pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
- }
- if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000)
- pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
- if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
- pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
-
- pipe_idx++;
- }
+ DC_FP_START();
+ dcn31_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel);
+ DC_FP_END();
+}
- dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
+void
+dcn31_populate_dml_writeback_from_context(struct dc *dc,
+ struct resource_context *res_ctx,
+ display_e2e_pipe_params_st *pipes)
+{
+ DC_FP_START();
+ dcn30_populate_dml_writeback_from_context(dc, res_ctx, pipes);
+ DC_FP_END();
}
-void dcn31_calculate_wm_and_dlg(
- struct dc *dc, struct dc_state *context,
- display_e2e_pipe_params_st *pipes,
- int pipe_cnt,
- int vlevel)
+void
+dcn31_set_mcif_arb_params(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt)
{
DC_FP_START();
- dcn31_calculate_wm_and_dlg_fp(dc, context, pipes, pipe_cnt, vlevel);
+ dcn30_set_mcif_arb_params(dc, context, pipes, pipe_cnt);
DC_FP_END();
}
@@ -2025,7 +1774,9 @@ bool dcn31_validate_bandwidth(struct dc *dc,
BW_VAL_TRACE_COUNT();
+ DC_FP_START();
out = dcn30_internal_validate_bw(dc, context, pipes, &pipe_cnt, &vlevel, fast_validate);
+ DC_FP_END();
// Disable fast_validate to set min dcfclk in alculate_wm_and_dlg
if (pipe_cnt == 0)
@@ -2066,77 +1817,6 @@ static struct dc_cap_funcs cap_funcs = {
.get_dcc_compression_cap = dcn20_get_dcc_compression_cap
};
-static void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
-{
- struct clk_limit_table *clk_table = &bw_params->clk_table;
- struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES];
- unsigned int i, closest_clk_lvl;
- int j;
-
- // Default clock levels are used for diags, which may lead to overclocking.
- if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
- int max_dispclk_mhz = 0, max_dppclk_mhz = 0;
-
- dcn3_1_ip.max_num_otg = dc->res_pool->res_cap->num_timing_generator;
- dcn3_1_ip.max_num_dpp = dc->res_pool->pipe_count;
- dcn3_1_soc.num_chans = bw_params->num_channels;
-
- ASSERT(clk_table->num_entries);
-
- /* Prepass to find max clocks independent of voltage level. */
- for (i = 0; i < clk_table->num_entries; ++i) {
- if (clk_table->entries[i].dispclk_mhz > max_dispclk_mhz)
- max_dispclk_mhz = clk_table->entries[i].dispclk_mhz;
- if (clk_table->entries[i].dppclk_mhz > max_dppclk_mhz)
- max_dppclk_mhz = clk_table->entries[i].dppclk_mhz;
- }
-
- for (i = 0; i < clk_table->num_entries; i++) {
- /* loop backwards*/
- for (closest_clk_lvl = 0, j = dcn3_1_soc.num_states - 1; j >= 0; j--) {
- if ((unsigned int) dcn3_1_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {
- closest_clk_lvl = j;
- break;
- }
- }
-
- clock_limits[i].state = i;
-
- /* Clocks dependent on voltage level. */
- clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz;
- clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz;
- clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz;
- clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2 * clk_table->entries[i].wck_ratio;
-
- /* Clocks independent of voltage level. */
- clock_limits[i].dispclk_mhz = max_dispclk_mhz ? max_dispclk_mhz :
- dcn3_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz;
-
- clock_limits[i].dppclk_mhz = max_dppclk_mhz ? max_dppclk_mhz :
- dcn3_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz;
-
- clock_limits[i].dram_bw_per_chan_gbps = dcn3_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps;
- clock_limits[i].dscclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz;
- clock_limits[i].dtbclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz;
- clock_limits[i].phyclk_d18_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz;
- clock_limits[i].phyclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz;
- }
- for (i = 0; i < clk_table->num_entries; i++)
- dcn3_1_soc.clock_limits[i] = clock_limits[i];
- if (clk_table->num_entries) {
- dcn3_1_soc.num_states = clk_table->num_entries;
- }
- }
-
- dcn3_1_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
- dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
-
- if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
- dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31);
- else
- dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31_FPGA);
-}
-
static struct resource_funcs dcn31_res_pool_funcs = {
.destroy = dcn31_destroy_resource_pool,
.link_enc_create = dcn31_link_encoder_create,
@@ -2152,8 +1832,8 @@ static struct resource_funcs dcn31_res_pool_funcs = {
.add_stream_to_ctx = dcn30_add_stream_to_ctx,
.add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
.remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
- .populate_dml_writeback_from_context = dcn30_populate_dml_writeback_from_context,
- .set_mcif_arb_params = dcn30_set_mcif_arb_params,
+ .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context,
+ .set_mcif_arb_params = dcn31_set_mcif_arb_params,
.find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
.acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut,
.release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
@@ -2174,7 +1854,7 @@ static struct clock_source *dcn30_clock_source_create(
if (!clk_src)
return NULL;
- if (dcn3_clk_src_construct(clk_src, ctx, bios, id,
+ if (dcn31_clk_src_construct(clk_src, ctx, bios, id,
regs, &cs_shift, &cs_mask)) {
clk_src->base.dp_clk_src = dp_clk_src;
return &clk_src->base;
@@ -2214,9 +1894,9 @@ static bool dcn31_resource_construct(
dc->caps.min_horizontal_blanking_period = 80;
dc->caps.dmdata_alloc_size = 2048;
- dc->caps.max_slave_planes = 1;
- dc->caps.max_slave_yuv_planes = 1;
- dc->caps.max_slave_rgb_planes = 1;
+ dc->caps.max_slave_planes = 2;
+ dc->caps.max_slave_yuv_planes = 2;
+ dc->caps.max_slave_rgb_planes = 2;
dc->caps.post_blend_color_processing = true;
dc->caps.force_dp_tps4_for_cp2520 = true;
dc->caps.dp_hpo = true;
@@ -2225,6 +1905,7 @@ static bool dcn31_resource_construct(
dc->caps.extended_aux_timeout_support = true;
dc->caps.dmcub_support = true;
dc->caps.is_apu = true;
+ dc->caps.zstate_support = true;
/* Color pipeline capabilities */
dc->caps.color.dpp.dcn_arch = 1;
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h
index a513363b3326..393458015d6a 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.h
@@ -31,6 +31,9 @@
#define TO_DCN31_RES_POOL(pool)\
container_of(pool, struct dcn31_resource_pool, base)
+extern struct _vcs_dpi_ip_params_st dcn3_1_ip;
+extern struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc;
+
struct dcn31_resource_pool {
struct resource_pool base;
};
@@ -43,6 +46,19 @@ void dcn31_calculate_wm_and_dlg(
display_e2e_pipe_params_st *pipes,
int pipe_cnt,
int vlevel);
+int dcn31_populate_dml_pipes_from_context(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate);
+void
+dcn31_populate_dml_writeback_from_context(struct dc *dc,
+ struct resource_context *res_ctx,
+ display_e2e_pipe_params_st *pipes);
+void
+dcn31_set_mcif_arb_params(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt);
void dcn31_update_soc_for_wm_a(struct dc *dc, struct dc_state *context);
struct resource_pool *dcn31_create_resource_pool(
diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/Makefile b/drivers/gpu/drm/amd/display/dc/dcn315/Makefile
new file mode 100644
index 000000000000..59381d24800b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn315/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright © 2021 Advanced Micro Devices, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Authors: AMD
+#
+# Makefile for dcn315.
+
+DCN315 = dcn315_resource.o
+
+AMD_DAL_DCN315 = $(addprefix $(AMDDALPATH)/dc/dcn315/,$(DCN315))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_DCN315)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
new file mode 100644
index 000000000000..2b42af030b33
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.c
@@ -0,0 +1,2053 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#include "dm_services.h"
+#include "dc.h"
+
+#include "dcn31/dcn31_init.h"
+
+#include "resource.h"
+#include "include/irq_service_interface.h"
+#include "dcn315_resource.h"
+
+#include "dcn20/dcn20_resource.h"
+#include "dcn30/dcn30_resource.h"
+#include "dcn31/dcn31_resource.h"
+
+#include "dcn10/dcn10_ipp.h"
+#include "dcn30/dcn30_hubbub.h"
+#include "dcn31/dcn31_hubbub.h"
+#include "dcn30/dcn30_mpc.h"
+#include "dcn31/dcn31_hubp.h"
+#include "irq/dcn315/irq_service_dcn315.h"
+#include "dcn30/dcn30_dpp.h"
+#include "dcn31/dcn31_optc.h"
+#include "dcn20/dcn20_hwseq.h"
+#include "dcn30/dcn30_hwseq.h"
+#include "dce110/dce110_hw_sequencer.h"
+#include "dcn30/dcn30_opp.h"
+#include "dcn20/dcn20_dsc.h"
+#include "dcn30/dcn30_vpg.h"
+#include "dcn30/dcn30_afmt.h"
+#include "dcn30/dcn30_dio_stream_encoder.h"
+#include "dcn31/dcn31_hpo_dp_stream_encoder.h"
+#include "dcn31/dcn31_hpo_dp_link_encoder.h"
+#include "dcn31/dcn31_apg.h"
+#include "dcn31/dcn31_dio_link_encoder.h"
+#include "dcn31/dcn31_vpg.h"
+#include "dcn31/dcn31_afmt.h"
+#include "dce/dce_clock_source.h"
+#include "dce/dce_audio.h"
+#include "dce/dce_hwseq.h"
+#include "clk_mgr.h"
+#include "virtual/virtual_stream_encoder.h"
+#include "dce110/dce110_resource.h"
+#include "dml/display_mode_vba.h"
+#include "dml/dcn31/dcn31_fpu.h"
+#include "dcn31/dcn31_dccg.h"
+#include "dcn10/dcn10_resource.h"
+#include "dcn31/dcn31_panel_cntl.h"
+
+#include "dcn30/dcn30_dwb.h"
+#include "dcn30/dcn30_mmhubbub.h"
+
+#include "dcn/dcn_3_1_5_offset.h"
+#include "dcn/dcn_3_1_5_sh_mask.h"
+#include "dpcs/dpcs_4_2_2_offset.h"
+#include "dpcs/dpcs_4_2_2_sh_mask.h"
+
+#define NBIO_BASE__INST0_SEG0 0x00000000
+#define NBIO_BASE__INST0_SEG1 0x00000014
+#define NBIO_BASE__INST0_SEG2 0x00000D20
+#define NBIO_BASE__INST0_SEG3 0x00010400
+#define NBIO_BASE__INST0_SEG4 0x0241B000
+#define NBIO_BASE__INST0_SEG5 0x04040000
+
+#define DPCS_BASE__INST0_SEG0 0x00000012
+#define DPCS_BASE__INST0_SEG1 0x000000C0
+#define DPCS_BASE__INST0_SEG2 0x000034C0
+#define DPCS_BASE__INST0_SEG3 0x00009000
+#define DPCS_BASE__INST0_SEG4 0x02403C00
+#define DPCS_BASE__INST0_SEG5 0
+
+#define DCN_BASE__INST0_SEG0 0x00000012
+#define DCN_BASE__INST0_SEG1 0x000000C0
+#define DCN_BASE__INST0_SEG2 0x000034C0
+#define DCN_BASE__INST0_SEG3 0x00009000
+#define DCN_BASE__INST0_SEG4 0x02403C00
+#define DCN_BASE__INST0_SEG5 0
+
+#define regBIF_BX_PF2_RSMU_INDEX 0x0000
+#define regBIF_BX_PF2_RSMU_INDEX_BASE_IDX 1
+#define regBIF_BX_PF2_RSMU_DATA 0x0001
+#define regBIF_BX_PF2_RSMU_DATA_BASE_IDX 1
+#define regBIF_BX2_BIOS_SCRATCH_6 0x003e
+#define regBIF_BX2_BIOS_SCRATCH_6_BASE_IDX 1
+#define BIF_BX2_BIOS_SCRATCH_6__BIOS_SCRATCH_6__SHIFT 0x0
+#define BIF_BX2_BIOS_SCRATCH_6__BIOS_SCRATCH_6_MASK 0xFFFFFFFFL
+#define regBIF_BX2_BIOS_SCRATCH_2 0x003a
+#define regBIF_BX2_BIOS_SCRATCH_2_BASE_IDX 1
+#define BIF_BX2_BIOS_SCRATCH_2__BIOS_SCRATCH_2__SHIFT 0x0
+#define BIF_BX2_BIOS_SCRATCH_2__BIOS_SCRATCH_2_MASK 0xFFFFFFFFL
+#define regBIF_BX2_BIOS_SCRATCH_3 0x003b
+#define regBIF_BX2_BIOS_SCRATCH_3_BASE_IDX 1
+#define BIF_BX2_BIOS_SCRATCH_3__BIOS_SCRATCH_3__SHIFT 0x0
+#define BIF_BX2_BIOS_SCRATCH_3__BIOS_SCRATCH_3_MASK 0xFFFFFFFFL
+
+#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6
+#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2
+#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10
+#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L
+
+#include "reg_helper.h"
+#include "dce/dmub_abm.h"
+#include "dce/dmub_psr.h"
+#include "dce/dce_aux.h"
+#include "dce/dce_i2c.h"
+
+#include "dml/dcn30/display_mode_vba_30.h"
+#include "vm_helper.h"
+#include "dcn20/dcn20_vmid.h"
+
+#include "link_enc_cfg.h"
+
+#define DCN3_15_MAX_DET_SIZE 384
+#define DCN3_15_CRB_SEGMENT_SIZE_KB 64
+
+enum dcn31_clk_src_array_id {
+ DCN31_CLK_SRC_PLL0,
+ DCN31_CLK_SRC_PLL1,
+ DCN31_CLK_SRC_PLL2,
+ DCN31_CLK_SRC_PLL3,
+ DCN31_CLK_SRC_PLL4,
+ DCN30_CLK_SRC_TOTAL
+};
+
+/* begin *********************
+ * macros to expend register list macro defined in HW object header file
+ */
+
+/* DCN */
+/* TODO awful hack. fixup dcn20_dwb.h */
+#undef BASE_INNER
+#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
+
+#define BASE(seg) BASE_INNER(seg)
+
+#define SR(reg_name)\
+ .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \
+ reg ## reg_name
+
+#define SRI(reg_name, block, id)\
+ .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRI2(reg_name, block, id)\
+ .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \
+ reg ## reg_name
+
+#define SRIR(var_name, reg_name, block, id)\
+ .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRII(reg_name, block, id)\
+ .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRII_MPC_RMU(reg_name, block, id)\
+ .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRII_DWB(reg_name, temp_name, block, id)\
+ .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## temp_name
+
+#define DCCG_SRII(reg_name, block, id)\
+ .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define VUPDATE_SRII(reg_name, block, id)\
+ .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \
+ reg ## reg_name ## _ ## block ## id
+
+/* NBIO */
+#define NBIO_BASE_INNER(seg) \
+ NBIO_BASE__INST0_SEG ## seg
+
+#define NBIO_BASE(seg) \
+ NBIO_BASE_INNER(seg)
+
+#define NBIO_SR(reg_name)\
+ .reg_name = NBIO_BASE(regBIF_BX2_ ## reg_name ## _BASE_IDX) + \
+ regBIF_BX2_ ## reg_name
+
+static const struct bios_registers bios_regs = {
+ NBIO_SR(BIOS_SCRATCH_3),
+ NBIO_SR(BIOS_SCRATCH_6)
+};
+
+#define clk_src_regs(index, pllid)\
+[index] = {\
+ CS_COMMON_REG_LIST_DCN3_0(index, pllid),\
+}
+
+static const struct dce110_clk_src_regs clk_src_regs[] = {
+ clk_src_regs(0, A),
+ clk_src_regs(1, B),
+ clk_src_regs(2, C),
+ clk_src_regs(3, D),
+ clk_src_regs(4, E)
+};
+
+static const struct dce110_clk_src_shift cs_shift = {
+ CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT)
+};
+
+static const struct dce110_clk_src_mask cs_mask = {
+ CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK)
+};
+
+#define abm_regs(id)\
+[id] = {\
+ ABM_DCN302_REG_LIST(id)\
+}
+
+static const struct dce_abm_registers abm_regs[] = {
+ abm_regs(0),
+ abm_regs(1),
+ abm_regs(2),
+ abm_regs(3),
+};
+
+static const struct dce_abm_shift abm_shift = {
+ ABM_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dce_abm_mask abm_mask = {
+ ABM_MASK_SH_LIST_DCN30(_MASK)
+};
+
+#define audio_regs(id)\
+[id] = {\
+ AUD_COMMON_REG_LIST(id)\
+}
+
+static const struct dce_audio_registers audio_regs[] = {
+ audio_regs(0),
+ audio_regs(1),
+ audio_regs(2),
+ audio_regs(3),
+ audio_regs(4),
+ audio_regs(5),
+ audio_regs(6)
+};
+
+#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\
+ SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\
+ SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\
+ AUD_COMMON_MASK_SH_LIST_BASE(mask_sh)
+
+static const struct dce_audio_shift audio_shift = {
+ DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_audio_mask audio_mask = {
+ DCE120_AUD_COMMON_MASK_SH_LIST(_MASK)
+};
+
+#define vpg_regs(id)\
+[id] = {\
+ VPG_DCN31_REG_LIST(id)\
+}
+
+static const struct dcn31_vpg_registers vpg_regs[] = {
+ vpg_regs(0),
+ vpg_regs(1),
+ vpg_regs(2),
+ vpg_regs(3),
+ vpg_regs(4),
+ vpg_regs(5),
+ vpg_regs(6),
+ vpg_regs(7),
+ vpg_regs(8),
+ vpg_regs(9),
+};
+
+static const struct dcn31_vpg_shift vpg_shift = {
+ DCN31_VPG_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_vpg_mask vpg_mask = {
+ DCN31_VPG_MASK_SH_LIST(_MASK)
+};
+
+#define afmt_regs(id)\
+[id] = {\
+ AFMT_DCN31_REG_LIST(id)\
+}
+
+static const struct dcn31_afmt_registers afmt_regs[] = {
+ afmt_regs(0),
+ afmt_regs(1),
+ afmt_regs(2),
+ afmt_regs(3),
+ afmt_regs(4),
+ afmt_regs(5)
+};
+
+static const struct dcn31_afmt_shift afmt_shift = {
+ DCN31_AFMT_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_afmt_mask afmt_mask = {
+ DCN31_AFMT_MASK_SH_LIST(_MASK)
+};
+
+#define apg_regs(id)\
+[id] = {\
+ APG_DCN31_REG_LIST(id)\
+}
+
+static const struct dcn31_apg_registers apg_regs[] = {
+ apg_regs(0),
+ apg_regs(1),
+ apg_regs(2),
+ apg_regs(3)
+};
+
+static const struct dcn31_apg_shift apg_shift = {
+ DCN31_APG_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_apg_mask apg_mask = {
+ DCN31_APG_MASK_SH_LIST(_MASK)
+};
+
+#define stream_enc_regs(id)\
+[id] = {\
+ SE_DCN3_REG_LIST(id)\
+}
+
+static const struct dcn10_stream_enc_registers stream_enc_regs[] = {
+ stream_enc_regs(0),
+ stream_enc_regs(1),
+ stream_enc_regs(2),
+ stream_enc_regs(3),
+ stream_enc_regs(4)
+};
+
+static const struct dcn10_stream_encoder_shift se_shift = {
+ SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dcn10_stream_encoder_mask se_mask = {
+ SE_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+
+#define aux_regs(id)\
+[id] = {\
+ DCN2_AUX_REG_LIST(id)\
+}
+
+static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = {
+ aux_regs(0),
+ aux_regs(1),
+ aux_regs(2),
+ aux_regs(3),
+ aux_regs(4)
+};
+
+#define hpd_regs(id)\
+[id] = {\
+ HPD_REG_LIST(id)\
+}
+
+static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = {
+ hpd_regs(0),
+ hpd_regs(1),
+ hpd_regs(2),
+ hpd_regs(3),
+ hpd_regs(4)
+};
+
+#define link_regs(id, phyid)\
+[id] = {\
+ LE_DCN31_REG_LIST(id), \
+ UNIPHY_DCN2_REG_LIST(phyid), \
+ DPCS_DCN31_REG_LIST(id), \
+}
+
+static const struct dce110_aux_registers_shift aux_shift = {
+ DCN_AUX_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce110_aux_registers_mask aux_mask = {
+ DCN_AUX_MASK_SH_LIST(_MASK)
+};
+
+static const struct dcn10_link_enc_registers link_enc_regs[] = {
+ link_regs(0, A),
+ link_regs(1, B),
+ link_regs(2, C),
+ link_regs(3, D),
+ link_regs(4, E)
+};
+
+static const struct dcn10_link_enc_shift le_shift = {
+ LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \
+ DPCS_DCN31_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn10_link_enc_mask le_mask = {
+ LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \
+ DPCS_DCN31_MASK_SH_LIST(_MASK)
+};
+
+#define hpo_dp_stream_encoder_reg_list(id)\
+[id] = {\
+ DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\
+}
+
+static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = {
+ hpo_dp_stream_encoder_reg_list(0),
+ hpo_dp_stream_encoder_reg_list(1),
+ hpo_dp_stream_encoder_reg_list(2),
+ hpo_dp_stream_encoder_reg_list(3),
+};
+
+static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = {
+ DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = {
+ DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK)
+};
+
+
+#define hpo_dp_link_encoder_reg_list(id)\
+[id] = {\
+ DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\
+ DCN3_1_RDPCSTX_REG_LIST(0),\
+ DCN3_1_RDPCSTX_REG_LIST(1),\
+ DCN3_1_RDPCSTX_REG_LIST(2),\
+ DCN3_1_RDPCSTX_REG_LIST(3),\
+ DCN3_1_RDPCSTX_REG_LIST(4)\
+}
+
+static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = {
+ hpo_dp_link_encoder_reg_list(0),
+ hpo_dp_link_encoder_reg_list(1),
+};
+
+static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = {
+ DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = {
+ DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK)
+};
+
+#define dpp_regs(id)\
+[id] = {\
+ DPP_REG_LIST_DCN30(id),\
+}
+
+static const struct dcn3_dpp_registers dpp_regs[] = {
+ dpp_regs(0),
+ dpp_regs(1),
+ dpp_regs(2),
+ dpp_regs(3)
+};
+
+static const struct dcn3_dpp_shift tf_shift = {
+ DPP_REG_LIST_SH_MASK_DCN30(__SHIFT)
+};
+
+static const struct dcn3_dpp_mask tf_mask = {
+ DPP_REG_LIST_SH_MASK_DCN30(_MASK)
+};
+
+#define opp_regs(id)\
+[id] = {\
+ OPP_REG_LIST_DCN30(id),\
+}
+
+static const struct dcn20_opp_registers opp_regs[] = {
+ opp_regs(0),
+ opp_regs(1),
+ opp_regs(2),
+ opp_regs(3)
+};
+
+static const struct dcn20_opp_shift opp_shift = {
+ OPP_MASK_SH_LIST_DCN20(__SHIFT)
+};
+
+static const struct dcn20_opp_mask opp_mask = {
+ OPP_MASK_SH_LIST_DCN20(_MASK)
+};
+
+#define aux_engine_regs(id)\
+[id] = {\
+ AUX_COMMON_REG_LIST0(id), \
+ .AUXN_IMPCAL = 0, \
+ .AUXP_IMPCAL = 0, \
+ .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \
+}
+
+static const struct dce110_aux_registers aux_engine_regs[] = {
+ aux_engine_regs(0),
+ aux_engine_regs(1),
+ aux_engine_regs(2),
+ aux_engine_regs(3),
+ aux_engine_regs(4)
+};
+
+#define dwbc_regs_dcn3(id)\
+[id] = {\
+ DWBC_COMMON_REG_LIST_DCN30(id),\
+}
+
+static const struct dcn30_dwbc_registers dwbc30_regs[] = {
+ dwbc_regs_dcn3(0),
+};
+
+static const struct dcn30_dwbc_shift dwbc30_shift = {
+ DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dcn30_dwbc_mask dwbc30_mask = {
+ DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+#define mcif_wb_regs_dcn3(id)\
+[id] = {\
+ MCIF_WB_COMMON_REG_LIST_DCN30(id),\
+}
+
+static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = {
+ mcif_wb_regs_dcn3(0)
+};
+
+static const struct dcn30_mmhubbub_shift mcif_wb30_shift = {
+ MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dcn30_mmhubbub_mask mcif_wb30_mask = {
+ MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+#define dsc_regsDCN20(id)\
+[id] = {\
+ DSC_REG_LIST_DCN20(id)\
+}
+
+static const struct dcn20_dsc_registers dsc_regs[] = {
+ dsc_regsDCN20(0),
+ dsc_regsDCN20(1),
+ dsc_regsDCN20(2)
+};
+
+static const struct dcn20_dsc_shift dsc_shift = {
+ DSC_REG_LIST_SH_MASK_DCN20(__SHIFT)
+};
+
+static const struct dcn20_dsc_mask dsc_mask = {
+ DSC_REG_LIST_SH_MASK_DCN20(_MASK)
+};
+
+static const struct dcn30_mpc_registers mpc_regs = {
+ MPC_REG_LIST_DCN3_0(0),
+ MPC_REG_LIST_DCN3_0(1),
+ MPC_REG_LIST_DCN3_0(2),
+ MPC_REG_LIST_DCN3_0(3),
+ MPC_OUT_MUX_REG_LIST_DCN3_0(0),
+ MPC_OUT_MUX_REG_LIST_DCN3_0(1),
+ MPC_OUT_MUX_REG_LIST_DCN3_0(2),
+ MPC_OUT_MUX_REG_LIST_DCN3_0(3),
+ MPC_DWB_MUX_REG_LIST_DCN3_0(0),
+};
+
+static const struct dcn30_mpc_shift mpc_shift = {
+ MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dcn30_mpc_mask mpc_mask = {
+ MPC_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+#define optc_regs(id)\
+[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)}
+
+static const struct dcn_optc_registers optc_regs[] = {
+ optc_regs(0),
+ optc_regs(1),
+ optc_regs(2),
+ optc_regs(3)
+};
+
+static const struct dcn_optc_shift optc_shift = {
+ OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT)
+};
+
+static const struct dcn_optc_mask optc_mask = {
+ OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK)
+};
+
+#define hubp_regs(id)\
+[id] = {\
+ HUBP_REG_LIST_DCN30(id)\
+}
+
+static const struct dcn_hubp2_registers hubp_regs[] = {
+ hubp_regs(0),
+ hubp_regs(1),
+ hubp_regs(2),
+ hubp_regs(3)
+};
+
+
+static const struct dcn_hubp2_shift hubp_shift = {
+ HUBP_MASK_SH_LIST_DCN31(__SHIFT)
+};
+
+static const struct dcn_hubp2_mask hubp_mask = {
+ HUBP_MASK_SH_LIST_DCN31(_MASK)
+};
+static const struct dcn_hubbub_registers hubbub_reg = {
+ HUBBUB_REG_LIST_DCN31(0)
+};
+
+static const struct dcn_hubbub_shift hubbub_shift = {
+ HUBBUB_MASK_SH_LIST_DCN31(__SHIFT)
+};
+
+static const struct dcn_hubbub_mask hubbub_mask = {
+ HUBBUB_MASK_SH_LIST_DCN31(_MASK)
+};
+
+static const struct dccg_registers dccg_regs = {
+ DCCG_REG_LIST_DCN31()
+};
+
+static const struct dccg_shift dccg_shift = {
+ DCCG_MASK_SH_LIST_DCN31(__SHIFT)
+};
+
+static const struct dccg_mask dccg_mask = {
+ DCCG_MASK_SH_LIST_DCN31(_MASK)
+};
+
+
+#define SRII2(reg_name_pre, reg_name_post, id)\
+ .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \
+ ## id ## _ ## reg_name_post ## _BASE_IDX) + \
+ reg ## reg_name_pre ## id ## _ ## reg_name_post
+
+
+#define HWSEQ_DCN31_REG_LIST()\
+ SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \
+ SR(DCHUBBUB_ARB_HOSTVM_CNTL), \
+ SR(DIO_MEM_PWR_CTRL), \
+ SR(ODM_MEM_PWR_CTRL3), \
+ SR(DMU_MEM_PWR_CNTL), \
+ SR(MMHUBBUB_MEM_PWR_CNTL), \
+ SR(DCCG_GATE_DISABLE_CNTL), \
+ SR(DCCG_GATE_DISABLE_CNTL2), \
+ SR(DCFCLK_CNTL),\
+ SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \
+ SRII(PIXEL_RATE_CNTL, OTG, 0), \
+ SRII(PIXEL_RATE_CNTL, OTG, 1),\
+ SRII(PIXEL_RATE_CNTL, OTG, 2),\
+ SRII(PIXEL_RATE_CNTL, OTG, 3),\
+ SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\
+ SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\
+ SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\
+ SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\
+ SR(MICROSECOND_TIME_BASE_DIV), \
+ SR(MILLISECOND_TIME_BASE_DIV), \
+ SR(DISPCLK_FREQ_CHANGE_CNTL), \
+ SR(RBBMIF_TIMEOUT_DIS), \
+ SR(RBBMIF_TIMEOUT_DIS_2), \
+ SR(DCHUBBUB_CRC_CTRL), \
+ SR(DPP_TOP0_DPP_CRC_CTRL), \
+ SR(DPP_TOP0_DPP_CRC_VAL_B_A), \
+ SR(DPP_TOP0_DPP_CRC_VAL_R_G), \
+ SR(MPC_CRC_CTRL), \
+ SR(MPC_CRC_RESULT_GB), \
+ SR(MPC_CRC_RESULT_C), \
+ SR(MPC_CRC_RESULT_AR), \
+ SR(DOMAIN0_PG_CONFIG), \
+ SR(DOMAIN1_PG_CONFIG), \
+ SR(DOMAIN2_PG_CONFIG), \
+ SR(DOMAIN3_PG_CONFIG), \
+ SR(DOMAIN16_PG_CONFIG), \
+ SR(DOMAIN17_PG_CONFIG), \
+ SR(DOMAIN18_PG_CONFIG), \
+ SR(DOMAIN0_PG_STATUS), \
+ SR(DOMAIN1_PG_STATUS), \
+ SR(DOMAIN2_PG_STATUS), \
+ SR(DOMAIN3_PG_STATUS), \
+ SR(DOMAIN16_PG_STATUS), \
+ SR(DOMAIN17_PG_STATUS), \
+ SR(DOMAIN18_PG_STATUS), \
+ SR(D1VGA_CONTROL), \
+ SR(D2VGA_CONTROL), \
+ SR(D3VGA_CONTROL), \
+ SR(D4VGA_CONTROL), \
+ SR(D5VGA_CONTROL), \
+ SR(D6VGA_CONTROL), \
+ SR(DC_IP_REQUEST_CNTL), \
+ SR(AZALIA_AUDIO_DTO), \
+ SR(AZALIA_CONTROLLER_CLOCK_GATING), \
+ SR(HPO_TOP_HW_CONTROL)
+
+static const struct dce_hwseq_registers hwseq_reg = {
+ HWSEQ_DCN31_REG_LIST()
+};
+
+#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\
+ HWSEQ_DCN_MASK_SH_LIST(mask_sh), \
+ HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \
+ HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \
+ HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \
+ HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \
+ HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \
+ HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \
+ HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \
+ HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \
+ HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \
+ HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh)
+
+static const struct dce_hwseq_shift hwseq_shift = {
+ HWSEQ_DCN31_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_hwseq_mask hwseq_mask = {
+ HWSEQ_DCN31_MASK_SH_LIST(_MASK)
+};
+#define vmid_regs(id)\
+[id] = {\
+ DCN20_VMID_REG_LIST(id)\
+}
+
+static const struct dcn_vmid_registers vmid_regs[] = {
+ vmid_regs(0),
+ vmid_regs(1),
+ vmid_regs(2),
+ vmid_regs(3),
+ vmid_regs(4),
+ vmid_regs(5),
+ vmid_regs(6),
+ vmid_regs(7),
+ vmid_regs(8),
+ vmid_regs(9),
+ vmid_regs(10),
+ vmid_regs(11),
+ vmid_regs(12),
+ vmid_regs(13),
+ vmid_regs(14),
+ vmid_regs(15)
+};
+
+static const struct dcn20_vmid_shift vmid_shifts = {
+ DCN20_VMID_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn20_vmid_mask vmid_masks = {
+ DCN20_VMID_MASK_SH_LIST(_MASK)
+};
+
+static const struct resource_caps res_cap_dcn31 = {
+ .num_timing_generator = 4,
+ .num_opp = 4,
+ .num_video_plane = 4,
+ .num_audio = 5,
+ .num_stream_encoder = 5,
+ .num_dig_link_enc = 5,
+ .num_hpo_dp_stream_encoder = 4,
+ .num_hpo_dp_link_encoder = 2,
+ .num_pll = 5,
+ .num_dwb = 1,
+ .num_ddc = 5,
+ .num_vmid = 16,
+ .num_mpc_3dlut = 2,
+ .num_dsc = 3,
+};
+
+static const struct dc_plane_cap plane_cap = {
+ .type = DC_PLANE_TYPE_DCN_UNIVERSAL,
+ .blends_with_above = true,
+ .blends_with_below = true,
+ .per_pixel_alpha = true,
+
+ .pixel_format_support = {
+ .argb8888 = true,
+ .nv12 = true,
+ .fp16 = true,
+ .p010 = true,
+ .ayuv = false,
+ },
+
+ .max_upscale_factor = {
+ .argb8888 = 16000,
+ .nv12 = 16000,
+ .fp16 = 16000
+ },
+
+ // 6:1 downscaling ratio: 1000/6 = 166.666
+ .max_downscale_factor = {
+ .argb8888 = 167,
+ .nv12 = 167,
+ .fp16 = 167
+ },
+ 64,
+ 64
+};
+
+static const struct dc_debug_options debug_defaults_drv = {
+ .disable_z10 = true, /*hw not support it*/
+ .disable_dmcu = true,
+ .force_abm_enable = false,
+ .timing_trace = false,
+ .clock_trace = true,
+ .disable_pplib_clock_request = false,
+ .pipe_split_policy = MPC_SPLIT_DYNAMIC,
+ .force_single_disp_pipe_split = false,
+ .disable_dcc = DCC_ENABLE,
+ .vsr_support = true,
+ .performance_trace = false,
+ .max_downscale_src_width = 4096,/*upto true 4k*/
+ .disable_pplib_wm_range = false,
+ .scl_reset_length10 = true,
+ .sanity_checks = false,
+ .underflow_assert_delay_us = 0xFFFFFFFF,
+ .dwb_fi_phase = -1, // -1 = disable,
+ .dmub_command_table = true,
+ .pstate_enabled = true,
+ .use_max_lb = true,
+ .enable_mem_low_power = {
+ .bits = {
+ .vga = true,
+ .i2c = true,
+ .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled
+ .dscl = true,
+ .cm = true,
+ .mpc = true,
+ .optc = true,
+ .vpg = true,
+ .afmt = true,
+ }
+ },
+ .optimize_edp_link_rate = true,
+ .enable_sw_cntl_psr = true,
+ .psr_power_use_phy_fsm = 0,
+};
+
+static const struct dc_debug_options debug_defaults_diags = {
+ .disable_dmcu = true,
+ .force_abm_enable = false,
+ .timing_trace = true,
+ .clock_trace = true,
+ .disable_dpp_power_gate = true,
+ .disable_hubp_power_gate = true,
+ .disable_clock_gate = true,
+ .disable_pplib_clock_request = true,
+ .disable_pplib_wm_range = true,
+ .disable_stutter = false,
+ .scl_reset_length10 = true,
+ .dwb_fi_phase = -1, // -1 = disable
+ .dmub_command_table = true,
+ .enable_tri_buf = true,
+ .use_max_lb = true
+};
+
+static void dcn31_dpp_destroy(struct dpp **dpp)
+{
+ kfree(TO_DCN20_DPP(*dpp));
+ *dpp = NULL;
+}
+
+static struct dpp *dcn31_dpp_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn3_dpp *dpp =
+ kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL);
+
+ if (!dpp)
+ return NULL;
+
+ if (dpp3_construct(dpp, ctx, inst,
+ &dpp_regs[inst], &tf_shift, &tf_mask))
+ return &dpp->base;
+
+ BREAK_TO_DEBUGGER();
+ kfree(dpp);
+ return NULL;
+}
+
+static struct output_pixel_processor *dcn31_opp_create(
+ struct dc_context *ctx, uint32_t inst)
+{
+ struct dcn20_opp *opp =
+ kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL);
+
+ if (!opp) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ dcn20_opp_construct(opp, ctx, inst,
+ &opp_regs[inst], &opp_shift, &opp_mask);
+ return &opp->base;
+}
+
+static struct dce_aux *dcn31_aux_engine_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct aux_engine_dce110 *aux_engine =
+ kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
+
+ if (!aux_engine)
+ return NULL;
+
+ dce110_aux_engine_construct(aux_engine, ctx, inst,
+ SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
+ &aux_engine_regs[inst],
+ &aux_mask,
+ &aux_shift,
+ ctx->dc->caps.extended_aux_timeout_support);
+
+ return &aux_engine->base;
+}
+#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) }
+
+static const struct dce_i2c_registers i2c_hw_regs[] = {
+ i2c_inst_regs(1),
+ i2c_inst_regs(2),
+ i2c_inst_regs(3),
+ i2c_inst_regs(4),
+ i2c_inst_regs(5),
+};
+
+static const struct dce_i2c_shift i2c_shifts = {
+ I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dce_i2c_mask i2c_masks = {
+ I2C_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+static struct dce_i2c_hw *dcn31_i2c_hw_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dce_i2c_hw *dce_i2c_hw =
+ kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL);
+
+ if (!dce_i2c_hw)
+ return NULL;
+
+ dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst,
+ &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks);
+
+ return dce_i2c_hw;
+}
+static struct mpc *dcn31_mpc_create(
+ struct dc_context *ctx,
+ int num_mpcc,
+ int num_rmu)
+{
+ struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc),
+ GFP_KERNEL);
+
+ if (!mpc30)
+ return NULL;
+
+ dcn30_mpc_construct(mpc30, ctx,
+ &mpc_regs,
+ &mpc_shift,
+ &mpc_mask,
+ num_mpcc,
+ num_rmu);
+
+ return &mpc30->base;
+}
+
+static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx)
+{
+ int i;
+
+ struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub),
+ GFP_KERNEL);
+
+ if (!hubbub3)
+ return NULL;
+
+ hubbub31_construct(hubbub3, ctx,
+ &hubbub_reg,
+ &hubbub_shift,
+ &hubbub_mask,
+ dcn3_15_ip.det_buffer_size_kbytes,
+ dcn3_15_ip.pixel_chunk_size_kbytes,
+ dcn3_15_ip.config_return_buffer_size_in_kbytes);
+
+
+ for (i = 0; i < res_cap_dcn31.num_vmid; i++) {
+ struct dcn20_vmid *vmid = &hubbub3->vmid[i];
+
+ vmid->ctx = ctx;
+
+ vmid->regs = &vmid_regs[i];
+ vmid->shifts = &vmid_shifts;
+ vmid->masks = &vmid_masks;
+ }
+
+ return &hubbub3->base;
+}
+
+static struct timing_generator *dcn31_timing_generator_create(
+ struct dc_context *ctx,
+ uint32_t instance)
+{
+ struct optc *tgn10 =
+ kzalloc(sizeof(struct optc), GFP_KERNEL);
+
+ if (!tgn10)
+ return NULL;
+
+ tgn10->base.inst = instance;
+ tgn10->base.ctx = ctx;
+
+ tgn10->tg_regs = &optc_regs[instance];
+ tgn10->tg_shift = &optc_shift;
+ tgn10->tg_mask = &optc_mask;
+
+ dcn31_timing_generator_init(tgn10);
+
+ return &tgn10->base;
+}
+
+static const struct encoder_feature_support link_enc_feature = {
+ .max_hdmi_deep_color = COLOR_DEPTH_121212,
+ .max_hdmi_pixel_clock = 600000,
+ .hdmi_ycbcr420_supported = true,
+ .dp_ycbcr420_supported = true,
+ .fec_supported = true,
+ .flags.bits.IS_HBR2_CAPABLE = true,
+ .flags.bits.IS_HBR3_CAPABLE = true,
+ .flags.bits.IS_TPS3_CAPABLE = true,
+ .flags.bits.IS_TPS4_CAPABLE = true
+};
+
+static struct link_encoder *dcn31_link_encoder_create(
+ const struct encoder_init_data *enc_init_data)
+{
+ struct dcn20_link_encoder *enc20 =
+ kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL);
+
+ if (!enc20)
+ return NULL;
+
+ dcn31_link_encoder_construct(enc20,
+ enc_init_data,
+ &link_enc_feature,
+ &link_enc_regs[enc_init_data->transmitter],
+ &link_enc_aux_regs[enc_init_data->channel - 1],
+ &link_enc_hpd_regs[enc_init_data->hpd_source],
+ &le_shift,
+ &le_mask);
+
+ return &enc20->enc10.base;
+}
+
+/* Create a minimal link encoder object not associated with a particular
+ * physical connector.
+ * resource_funcs.link_enc_create_minimal
+ */
+static struct link_encoder *dcn31_link_enc_create_minimal(
+ struct dc_context *ctx, enum engine_id eng_id)
+{
+ struct dcn20_link_encoder *enc20;
+
+ if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc)
+ return NULL;
+
+ enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL);
+ if (!enc20)
+ return NULL;
+
+ dcn31_link_encoder_construct_minimal(
+ enc20,
+ ctx,
+ &link_enc_feature,
+ &link_enc_regs[eng_id - ENGINE_ID_DIGA],
+ eng_id);
+
+ return &enc20->enc10.base;
+}
+
+static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data)
+{
+ struct dcn31_panel_cntl *panel_cntl =
+ kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL);
+
+ if (!panel_cntl)
+ return NULL;
+
+ dcn31_panel_cntl_construct(panel_cntl, init_data);
+
+ return &panel_cntl->base;
+}
+
+static void read_dce_straps(
+ struct dc_context *ctx,
+ struct resource_straps *straps)
+{
+ generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX),
+ FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio);
+
+}
+
+static struct audio *dcn31_create_audio(
+ struct dc_context *ctx, unsigned int inst)
+{
+ return dce_audio_create(ctx, inst,
+ &audio_regs[inst], &audio_shift, &audio_mask);
+}
+
+static struct vpg *dcn31_vpg_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL);
+
+ if (!vpg31)
+ return NULL;
+
+ vpg31_construct(vpg31, ctx, inst,
+ &vpg_regs[inst],
+ &vpg_shift,
+ &vpg_mask);
+
+ return &vpg31->base;
+}
+
+static struct afmt *dcn31_afmt_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL);
+
+ if (!afmt31)
+ return NULL;
+
+ afmt31_construct(afmt31, ctx, inst,
+ &afmt_regs[inst],
+ &afmt_shift,
+ &afmt_mask);
+
+ // Light sleep by default, no need to power down here
+
+ return &afmt31->base;
+}
+
+static struct apg *dcn31_apg_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL);
+
+ if (!apg31)
+ return NULL;
+
+ apg31_construct(apg31, ctx, inst,
+ &apg_regs[inst],
+ &apg_shift,
+ &apg_mask);
+
+ return &apg31->base;
+}
+
+static struct stream_encoder *dcn315_stream_encoder_create(
+ enum engine_id eng_id,
+ struct dc_context *ctx)
+{
+ struct dcn10_stream_encoder *enc1;
+ struct vpg *vpg;
+ struct afmt *afmt;
+ int vpg_inst;
+ int afmt_inst;
+
+ /*PHYB is wired off in HW, allow front end to remapping, otherwise needs more changes*/
+
+ /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
+ if (eng_id <= ENGINE_ID_DIGF) {
+ vpg_inst = eng_id;
+ afmt_inst = eng_id;
+ } else
+ return NULL;
+
+ enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
+ vpg = dcn31_vpg_create(ctx, vpg_inst);
+ afmt = dcn31_afmt_create(ctx, afmt_inst);
+
+ if (!enc1 || !vpg || !afmt) {
+ kfree(enc1);
+ kfree(vpg);
+ kfree(afmt);
+ return NULL;
+ }
+
+ dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios,
+ eng_id, vpg, afmt,
+ &stream_enc_regs[eng_id],
+ &se_shift, &se_mask);
+
+ return &enc1->base;
+}
+
+static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create(
+ enum engine_id eng_id,
+ struct dc_context *ctx)
+{
+ struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31;
+ struct vpg *vpg;
+ struct apg *apg;
+ uint32_t hpo_dp_inst;
+ uint32_t vpg_inst;
+ uint32_t apg_inst;
+
+ ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3));
+ hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0;
+
+ /* Mapping of VPG register blocks to HPO DP block instance:
+ * VPG[6] -> HPO_DP[0]
+ * VPG[7] -> HPO_DP[1]
+ * VPG[8] -> HPO_DP[2]
+ * VPG[9] -> HPO_DP[3]
+ */
+ vpg_inst = hpo_dp_inst + 6;
+
+ /* Mapping of APG register blocks to HPO DP block instance:
+ * APG[0] -> HPO_DP[0]
+ * APG[1] -> HPO_DP[1]
+ * APG[2] -> HPO_DP[2]
+ * APG[3] -> HPO_DP[3]
+ */
+ apg_inst = hpo_dp_inst;
+
+ /* allocate HPO stream encoder and create VPG sub-block */
+ hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL);
+ vpg = dcn31_vpg_create(ctx, vpg_inst);
+ apg = dcn31_apg_create(ctx, apg_inst);
+
+ if (!hpo_dp_enc31 || !vpg || !apg) {
+ kfree(hpo_dp_enc31);
+ kfree(vpg);
+ kfree(apg);
+ return NULL;
+ }
+
+ dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios,
+ hpo_dp_inst, eng_id, vpg, apg,
+ &hpo_dp_stream_enc_regs[hpo_dp_inst],
+ &hpo_dp_se_shift, &hpo_dp_se_mask);
+
+ return &hpo_dp_enc31->base;
+}
+
+static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create(
+ uint8_t inst,
+ struct dc_context *ctx)
+{
+ struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31;
+
+ /* allocate HPO link encoder */
+ hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL);
+
+ hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst,
+ &hpo_dp_link_enc_regs[inst],
+ &hpo_dp_le_shift, &hpo_dp_le_mask);
+
+ return &hpo_dp_enc31->base;
+}
+
+static struct dce_hwseq *dcn31_hwseq_create(
+ struct dc_context *ctx)
+{
+ struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL);
+
+ if (hws) {
+ hws->ctx = ctx;
+ hws->regs = &hwseq_reg;
+ hws->shifts = &hwseq_shift;
+ hws->masks = &hwseq_mask;
+ /* DCN3.1 FPGA Workaround
+ * Need to enable HPO DP Stream Encoder before setting OTG master enable.
+ * To do so, move calling function enable_stream_timing to only be done AFTER calling
+ * function core_link_enable_stream
+ */
+ if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
+ hws->wa.dp_hpo_and_otg_sequence = true;
+ }
+ return hws;
+}
+static const struct resource_create_funcs res_create_funcs = {
+ .read_dce_straps = read_dce_straps,
+ .create_audio = dcn31_create_audio,
+ .create_stream_encoder = dcn315_stream_encoder_create,
+ .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create,
+ .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create,
+ .create_hwseq = dcn31_hwseq_create,
+};
+
+static const struct resource_create_funcs res_create_maximus_funcs = {
+ .read_dce_straps = NULL,
+ .create_audio = NULL,
+ .create_stream_encoder = NULL,
+ .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create,
+ .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create,
+ .create_hwseq = dcn31_hwseq_create,
+};
+
+static void dcn315_resource_destruct(struct dcn315_resource_pool *pool)
+{
+ unsigned int i;
+
+ for (i = 0; i < pool->base.stream_enc_count; i++) {
+ if (pool->base.stream_enc[i] != NULL) {
+ if (pool->base.stream_enc[i]->vpg != NULL) {
+ kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg));
+ pool->base.stream_enc[i]->vpg = NULL;
+ }
+ if (pool->base.stream_enc[i]->afmt != NULL) {
+ kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt));
+ pool->base.stream_enc[i]->afmt = NULL;
+ }
+ kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i]));
+ pool->base.stream_enc[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) {
+ if (pool->base.hpo_dp_stream_enc[i] != NULL) {
+ if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) {
+ kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg));
+ pool->base.hpo_dp_stream_enc[i]->vpg = NULL;
+ }
+ if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) {
+ kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg));
+ pool->base.hpo_dp_stream_enc[i]->apg = NULL;
+ }
+ kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i]));
+ pool->base.hpo_dp_stream_enc[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) {
+ if (pool->base.hpo_dp_link_enc[i] != NULL) {
+ kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i]));
+ pool->base.hpo_dp_link_enc[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
+ if (pool->base.dscs[i] != NULL)
+ dcn20_dsc_destroy(&pool->base.dscs[i]);
+ }
+
+ if (pool->base.mpc != NULL) {
+ kfree(TO_DCN20_MPC(pool->base.mpc));
+ pool->base.mpc = NULL;
+ }
+ if (pool->base.hubbub != NULL) {
+ kfree(pool->base.hubbub);
+ pool->base.hubbub = NULL;
+ }
+ for (i = 0; i < pool->base.pipe_count; i++) {
+ if (pool->base.dpps[i] != NULL)
+ dcn31_dpp_destroy(&pool->base.dpps[i]);
+
+ if (pool->base.ipps[i] != NULL)
+ pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]);
+
+ if (pool->base.hubps[i] != NULL) {
+ kfree(TO_DCN20_HUBP(pool->base.hubps[i]));
+ pool->base.hubps[i] = NULL;
+ }
+
+ if (pool->base.irqs != NULL) {
+ dal_irq_service_destroy(&pool->base.irqs);
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_ddc; i++) {
+ if (pool->base.engines[i] != NULL)
+ dce110_engine_destroy(&pool->base.engines[i]);
+ if (pool->base.hw_i2cs[i] != NULL) {
+ kfree(pool->base.hw_i2cs[i]);
+ pool->base.hw_i2cs[i] = NULL;
+ }
+ if (pool->base.sw_i2cs[i] != NULL) {
+ kfree(pool->base.sw_i2cs[i]);
+ pool->base.sw_i2cs[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_opp; i++) {
+ if (pool->base.opps[i] != NULL)
+ pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]);
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+ if (pool->base.timing_generators[i] != NULL) {
+ kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i]));
+ pool->base.timing_generators[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_dwb; i++) {
+ if (pool->base.dwbc[i] != NULL) {
+ kfree(TO_DCN30_DWBC(pool->base.dwbc[i]));
+ pool->base.dwbc[i] = NULL;
+ }
+ if (pool->base.mcif_wb[i] != NULL) {
+ kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i]));
+ pool->base.mcif_wb[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.audio_count; i++) {
+ if (pool->base.audios[i])
+ dce_aud_destroy(&pool->base.audios[i]);
+ }
+
+ for (i = 0; i < pool->base.clk_src_count; i++) {
+ if (pool->base.clock_sources[i] != NULL) {
+ dcn20_clock_source_destroy(&pool->base.clock_sources[i]);
+ pool->base.clock_sources[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) {
+ if (pool->base.mpc_lut[i] != NULL) {
+ dc_3dlut_func_release(pool->base.mpc_lut[i]);
+ pool->base.mpc_lut[i] = NULL;
+ }
+ if (pool->base.mpc_shaper[i] != NULL) {
+ dc_transfer_func_release(pool->base.mpc_shaper[i]);
+ pool->base.mpc_shaper[i] = NULL;
+ }
+ }
+
+ if (pool->base.dp_clock_source != NULL) {
+ dcn20_clock_source_destroy(&pool->base.dp_clock_source);
+ pool->base.dp_clock_source = NULL;
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+ if (pool->base.multiple_abms[i] != NULL)
+ dce_abm_destroy(&pool->base.multiple_abms[i]);
+ }
+
+ if (pool->base.psr != NULL)
+ dmub_psr_destroy(&pool->base.psr);
+
+ if (pool->base.dccg != NULL)
+ dcn_dccg_destroy(&pool->base.dccg);
+}
+
+static struct hubp *dcn31_hubp_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn20_hubp *hubp2 =
+ kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL);
+
+ if (!hubp2)
+ return NULL;
+
+ if (hubp31_construct(hubp2, ctx, inst,
+ &hubp_regs[inst], &hubp_shift, &hubp_mask))
+ return &hubp2->base;
+
+ BREAK_TO_DEBUGGER();
+ kfree(hubp2);
+ return NULL;
+}
+
+static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool)
+{
+ int i;
+ uint32_t pipe_count = pool->res_cap->num_dwb;
+
+ for (i = 0; i < pipe_count; i++) {
+ struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc),
+ GFP_KERNEL);
+
+ if (!dwbc30) {
+ dm_error("DC: failed to create dwbc30!\n");
+ return false;
+ }
+
+ dcn30_dwbc_construct(dwbc30, ctx,
+ &dwbc30_regs[i],
+ &dwbc30_shift,
+ &dwbc30_mask,
+ i);
+
+ pool->dwbc[i] = &dwbc30->base;
+ }
+ return true;
+}
+
+static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool)
+{
+ int i;
+ uint32_t pipe_count = pool->res_cap->num_dwb;
+
+ for (i = 0; i < pipe_count; i++) {
+ struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub),
+ GFP_KERNEL);
+
+ if (!mcif_wb30) {
+ dm_error("DC: failed to create mcif_wb30!\n");
+ return false;
+ }
+
+ dcn30_mmhubbub_construct(mcif_wb30, ctx,
+ &mcif_wb30_regs[i],
+ &mcif_wb30_shift,
+ &mcif_wb30_mask,
+ i);
+
+ pool->mcif_wb[i] = &mcif_wb30->base;
+ }
+ return true;
+}
+
+static struct display_stream_compressor *dcn31_dsc_create(
+ struct dc_context *ctx, uint32_t inst)
+{
+ struct dcn20_dsc *dsc =
+ kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL);
+
+ if (!dsc) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask);
+ return &dsc->base;
+}
+
+static void dcn315_destroy_resource_pool(struct resource_pool **pool)
+{
+ struct dcn315_resource_pool *dcn31_pool = TO_DCN315_RES_POOL(*pool);
+
+ dcn315_resource_destruct(dcn31_pool);
+ kfree(dcn31_pool);
+ *pool = NULL;
+}
+
+static struct clock_source *dcn31_clock_source_create(
+ struct dc_context *ctx,
+ struct dc_bios *bios,
+ enum clock_source_id id,
+ const struct dce110_clk_src_regs *regs,
+ bool dp_clk_src)
+{
+ struct dce110_clk_src *clk_src =
+ kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL);
+
+ if (!clk_src)
+ return NULL;
+
+ if (dcn31_clk_src_construct(clk_src, ctx, bios, id,
+ regs, &cs_shift, &cs_mask)) {
+ clk_src->base.dp_clk_src = dp_clk_src;
+ return &clk_src->base;
+ }
+
+ BREAK_TO_DEBUGGER();
+ return NULL;
+}
+
+static bool is_dual_plane(enum surface_pixel_format format)
+{
+ return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA;
+}
+
+static int dcn315_populate_dml_pipes_from_context(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate)
+{
+ int i, pipe_cnt;
+ struct resource_context *res_ctx = &context->res_ctx;
+ struct pipe_ctx *pipe;
+ const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_15_MIN_COMPBUF_SIZE_KB;
+
+ DC_FP_START();
+ dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ DC_FP_END();
+
+ for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
+ struct dc_crtc_timing *timing;
+
+ if (!res_ctx->pipe_ctx[i].stream)
+ continue;
+ pipe = &res_ctx->pipe_ctx[i];
+ timing = &pipe->stream->timing;
+
+ /*
+ * Immediate flip can be set dynamically after enabling the plane.
+ * We need to require support for immediate flip or underflow can be
+ * intermittently experienced depending on peak b/w requirements.
+ */
+ pipes[pipe_cnt].pipe.src.immediate_flip = true;
+
+ pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
+ pipes[pipe_cnt].pipe.src.gpuvm = true;
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
+ pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
+ pipes[pipe_cnt].pipe.src.dcc_rate = 3;
+ pipes[pipe_cnt].dout.dsc_input_bpc = 0;
+
+ if (pipes[pipe_cnt].dout.dsc_enable) {
+ switch (timing->display_color_depth) {
+ case COLOR_DEPTH_888:
+ pipes[pipe_cnt].dout.dsc_input_bpc = 8;
+ break;
+ case COLOR_DEPTH_101010:
+ pipes[pipe_cnt].dout.dsc_input_bpc = 10;
+ break;
+ case COLOR_DEPTH_121212:
+ pipes[pipe_cnt].dout.dsc_input_bpc = 12;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ }
+
+ pipe_cnt++;
+ }
+
+ if (pipe_cnt)
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes =
+ (max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / pipe_cnt) * DCN3_15_CRB_SEGMENT_SIZE_KB;
+ if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_15_MAX_DET_SIZE)
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_15_MAX_DET_SIZE;
+ ASSERT(context->bw_ctx.dml.ip.det_buffer_size_kbytes >= DCN3_15_DEFAULT_DET_SIZE);
+ dc->config.enable_4to1MPC = false;
+ if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) {
+ if (is_dual_plane(pipe->plane_state->format)
+ && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) {
+ dc->config.enable_4to1MPC = true;
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes =
+ (max_usable_det / DCN3_15_CRB_SEGMENT_SIZE_KB / 4) * DCN3_15_CRB_SEGMENT_SIZE_KB;
+ } else if (!is_dual_plane(pipe->plane_state->format) && pipe->plane_state->src_rect.width <= 5120) {
+ /* Limit to 5k max to avoid forced pipe split when there is not enough detile for swath */
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192;
+ pipes[0].pipe.src.unbounded_req_mode = true;
+ }
+ }
+
+ return pipe_cnt;
+}
+
+static struct dc_cap_funcs cap_funcs = {
+ .get_dcc_compression_cap = dcn20_get_dcc_compression_cap
+};
+
+static struct resource_funcs dcn315_res_pool_funcs = {
+ .destroy = dcn315_destroy_resource_pool,
+ .link_enc_create = dcn31_link_encoder_create,
+ .link_enc_create_minimal = dcn31_link_enc_create_minimal,
+ .link_encs_assign = link_enc_cfg_link_encs_assign,
+ .link_enc_unassign = link_enc_cfg_link_enc_unassign,
+ .panel_cntl_create = dcn31_panel_cntl_create,
+ .validate_bandwidth = dcn31_validate_bandwidth,
+ .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg,
+ .update_soc_for_wm_a = dcn31_update_soc_for_wm_a,
+ .populate_dml_pipes = dcn315_populate_dml_pipes_from_context,
+ .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer,
+ .add_stream_to_ctx = dcn30_add_stream_to_ctx,
+ .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
+ .remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
+ .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context,
+ .set_mcif_arb_params = dcn31_set_mcif_arb_params,
+ .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
+ .acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut,
+ .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
+ .update_bw_bounding_box = dcn315_update_bw_bounding_box,
+ .patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
+};
+
+static bool dcn315_resource_construct(
+ uint8_t num_virtual_links,
+ struct dc *dc,
+ struct dcn315_resource_pool *pool)
+{
+ int i;
+ struct dc_context *ctx = dc->ctx;
+ struct irq_service_init_data init_data;
+
+ ctx->dc_bios->regs = &bios_regs;
+
+ pool->base.res_cap = &res_cap_dcn31;
+
+ pool->base.funcs = &dcn315_res_pool_funcs;
+
+ /*************************************************
+ * Resource + asic cap harcoding *
+ *************************************************/
+ pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE;
+ pool->base.pipe_count = pool->base.res_cap->num_timing_generator;
+ pool->base.mpcc_count = pool->base.res_cap->num_timing_generator;
+ dc->caps.max_downscale_ratio = 600;
+ dc->caps.i2c_speed_in_khz = 100;
+ dc->caps.i2c_speed_in_khz_hdcp = 100;
+ dc->caps.max_cursor_size = 256;
+ dc->caps.min_horizontal_blanking_period = 80;
+ dc->caps.dmdata_alloc_size = 2048;
+ dc->caps.max_slave_planes = 1;
+ dc->caps.max_slave_yuv_planes = 1;
+ dc->caps.max_slave_rgb_planes = 1;
+ dc->caps.post_blend_color_processing = true;
+ dc->caps.force_dp_tps4_for_cp2520 = true;
+ dc->caps.dp_hpo = true;
+ dc->caps.edp_dsc_support = true;
+ dc->caps.extended_aux_timeout_support = true;
+ dc->caps.dmcub_support = true;
+ dc->caps.is_apu = true;
+
+ /* Color pipeline capabilities */
+ dc->caps.color.dpp.dcn_arch = 1;
+ dc->caps.color.dpp.input_lut_shared = 0;
+ dc->caps.color.dpp.icsc = 1;
+ dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr
+ dc->caps.color.dpp.dgam_rom_caps.srgb = 1;
+ dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1;
+ dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1;
+ dc->caps.color.dpp.dgam_rom_caps.pq = 1;
+ dc->caps.color.dpp.dgam_rom_caps.hlg = 1;
+ dc->caps.color.dpp.post_csc = 1;
+ dc->caps.color.dpp.gamma_corr = 1;
+ dc->caps.color.dpp.dgam_rom_for_yuv = 0;
+
+ dc->caps.color.dpp.hw_3d_lut = 1;
+ dc->caps.color.dpp.ogam_ram = 1;
+ // no OGAM ROM on DCN301
+ dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
+ dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
+ dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0;
+ dc->caps.color.dpp.ogam_rom_caps.pq = 0;
+ dc->caps.color.dpp.ogam_rom_caps.hlg = 0;
+ dc->caps.color.dpp.ocsc = 0;
+
+ dc->caps.color.mpc.gamut_remap = 1;
+ dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2
+ dc->caps.color.mpc.ogam_ram = 1;
+ dc->caps.color.mpc.ogam_rom_caps.srgb = 0;
+ dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0;
+ dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0;
+ dc->caps.color.mpc.ogam_rom_caps.pq = 0;
+ dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
+ dc->caps.color.mpc.ocsc = 1;
+
+ /* read VBIOS LTTPR caps */
+ {
+ if (ctx->dc_bios->funcs->get_lttpr_caps) {
+ enum bp_result bp_query_result;
+ uint8_t is_vbios_lttpr_enable = 0;
+
+ bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable);
+ dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable;
+ }
+
+ /* interop bit is implicit */
+ {
+ dc->caps.vbios_lttpr_aware = true;
+ }
+ }
+
+ if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV)
+ dc->debug = debug_defaults_drv;
+ else if (dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) {
+ dc->debug = debug_defaults_diags;
+ } else
+ dc->debug = debug_defaults_diags;
+ // Init the vm_helper
+ if (dc->vm_helper)
+ vm_helper_init(dc->vm_helper, 16);
+
+ /*************************************************
+ * Create resources *
+ *************************************************/
+
+ /* Clock Sources for Pixel Clock*/
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL0] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL0,
+ &clk_src_regs[0], false);
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL1] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL1,
+ &clk_src_regs[1], false);
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL2] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL2,
+ &clk_src_regs[2], false);
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL3] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL3,
+ &clk_src_regs[3], false);
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL4] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL4,
+ &clk_src_regs[4], false);
+
+ pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL;
+
+ /* todo: not reuse phy_pll registers */
+ pool->base.dp_clock_source =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_ID_DP_DTO,
+ &clk_src_regs[0], true);
+
+ for (i = 0; i < pool->base.clk_src_count; i++) {
+ if (pool->base.clock_sources[i] == NULL) {
+ dm_error("DC: failed to create clock sources!\n");
+ BREAK_TO_DEBUGGER();
+ goto create_fail;
+ }
+ }
+
+ /* TODO: DCCG */
+ pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask);
+ if (pool->base.dccg == NULL) {
+ dm_error("DC: failed to create dccg!\n");
+ BREAK_TO_DEBUGGER();
+ goto create_fail;
+ }
+
+ /* TODO: IRQ */
+ init_data.ctx = dc->ctx;
+ pool->base.irqs = dal_irq_service_dcn315_create(&init_data);
+ if (!pool->base.irqs)
+ goto create_fail;
+
+ /* HUBBUB */
+ pool->base.hubbub = dcn31_hubbub_create(ctx);
+ if (pool->base.hubbub == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create hubbub!\n");
+ goto create_fail;
+ }
+
+ /* HUBPs, DPPs, OPPs and TGs */
+ for (i = 0; i < pool->base.pipe_count; i++) {
+ pool->base.hubps[i] = dcn31_hubp_create(ctx, i);
+ if (pool->base.hubps[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC: failed to create hubps!\n");
+ goto create_fail;
+ }
+
+ pool->base.dpps[i] = dcn31_dpp_create(ctx, i);
+ if (pool->base.dpps[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC: failed to create dpps!\n");
+ goto create_fail;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_opp; i++) {
+ pool->base.opps[i] = dcn31_opp_create(ctx, i);
+ if (pool->base.opps[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC: failed to create output pixel processor!\n");
+ goto create_fail;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+ pool->base.timing_generators[i] = dcn31_timing_generator_create(
+ ctx, i);
+ if (pool->base.timing_generators[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create tg!\n");
+ goto create_fail;
+ }
+ }
+ pool->base.timing_generator_count = i;
+
+ /* PSR */
+ pool->base.psr = dmub_psr_create(ctx);
+ if (pool->base.psr == NULL) {
+ dm_error("DC: failed to create psr obj!\n");
+ BREAK_TO_DEBUGGER();
+ goto create_fail;
+ }
+
+ /* ABM */
+ for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+ pool->base.multiple_abms[i] = dmub_abm_create(ctx,
+ &abm_regs[i],
+ &abm_shift,
+ &abm_mask);
+ if (pool->base.multiple_abms[i] == NULL) {
+ dm_error("DC: failed to create abm for pipe %d!\n", i);
+ BREAK_TO_DEBUGGER();
+ goto create_fail;
+ }
+ }
+
+ /* MPC and DSC */
+ pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut);
+ if (pool->base.mpc == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create mpc!\n");
+ goto create_fail;
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
+ pool->base.dscs[i] = dcn31_dsc_create(ctx, i);
+ if (pool->base.dscs[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create display stream compressor %d!\n", i);
+ goto create_fail;
+ }
+ }
+
+ /* DWB and MMHUBBUB */
+ if (!dcn31_dwbc_create(ctx, &pool->base)) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dwbc!\n");
+ goto create_fail;
+ }
+
+ if (!dcn31_mmhubbub_create(ctx, &pool->base)) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create mcif_wb!\n");
+ goto create_fail;
+ }
+
+ /* AUX and I2C */
+ for (i = 0; i < pool->base.res_cap->num_ddc; i++) {
+ pool->base.engines[i] = dcn31_aux_engine_create(ctx, i);
+ if (pool->base.engines[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC:failed to create aux engine!!\n");
+ goto create_fail;
+ }
+ pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i);
+ if (pool->base.hw_i2cs[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC:failed to create hw i2c!!\n");
+ goto create_fail;
+ }
+ pool->base.sw_i2cs[i] = NULL;
+ }
+
+ /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */
+ if (!resource_construct(num_virtual_links, dc, &pool->base,
+ (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) ?
+ &res_create_funcs : &res_create_maximus_funcs)))
+ goto create_fail;
+
+ /* HW Sequencer and Plane caps */
+ dcn31_hw_sequencer_construct(dc);
+
+ dc->caps.max_planes = pool->base.pipe_count;
+
+ for (i = 0; i < dc->caps.max_planes; ++i)
+ dc->caps.planes[i] = plane_cap;
+
+ dc->cap_funcs = cap_funcs;
+
+ dc->dcn_ip->max_num_dpp = dcn3_15_ip.max_num_dpp;
+
+ return true;
+
+create_fail:
+
+ dcn315_resource_destruct(pool);
+
+ return false;
+}
+
+struct resource_pool *dcn315_create_resource_pool(
+ const struct dc_init_data *init_data,
+ struct dc *dc)
+{
+ struct dcn315_resource_pool *pool =
+ kzalloc(sizeof(struct dcn315_resource_pool), GFP_KERNEL);
+
+ if (!pool)
+ return NULL;
+
+ if (dcn315_resource_construct(init_data->num_virtual_links, dc, pool))
+ return &pool->base;
+
+ BREAK_TO_DEBUGGER();
+ kfree(pool);
+ return NULL;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h
new file mode 100644
index 000000000000..39929fa67a51
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn315/dcn315_resource.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef _DCN315_RESOURCE_H_
+#define _DCN315_RESOURCE_H_
+
+#include "core_types.h"
+
+#define TO_DCN315_RES_POOL(pool)\
+ container_of(pool, struct dcn315_resource_pool, base)
+
+extern struct _vcs_dpi_ip_params_st dcn3_15_ip;
+extern struct _vcs_dpi_ip_params_st dcn3_15_soc;
+
+struct dcn315_resource_pool {
+ struct resource_pool base;
+};
+
+struct resource_pool *dcn315_create_resource_pool(
+ const struct dc_init_data *init_data,
+ struct dc *dc);
+
+#endif /* _DCN315_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/Makefile b/drivers/gpu/drm/amd/display/dc/dcn316/Makefile
new file mode 100644
index 000000000000..819d44a9439b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn316/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright 2021 Advanced Micro Devices, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Authors: AMD
+#
+# Makefile for dcn316.
+
+DCN316 = dcn316_resource.o
+
+AMD_DAL_DCN316 = $(addprefix $(AMDDALPATH)/dc/dcn316/,$(DCN316))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_DCN316)
diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
new file mode 100644
index 000000000000..ef16260b7f3f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.c
@@ -0,0 +1,2055 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+
+#include "dm_services.h"
+#include "dc.h"
+
+#include "dcn31/dcn31_init.h"
+
+#include "resource.h"
+#include "include/irq_service_interface.h"
+#include "dcn316_resource.h"
+
+#include "dcn20/dcn20_resource.h"
+#include "dcn30/dcn30_resource.h"
+#include "dcn31/dcn31_resource.h"
+
+#include "dcn10/dcn10_ipp.h"
+#include "dcn30/dcn30_hubbub.h"
+#include "dcn31/dcn31_hubbub.h"
+#include "dcn30/dcn30_mpc.h"
+#include "dcn31/dcn31_hubp.h"
+#include "irq/dcn31/irq_service_dcn31.h"
+#include "dcn30/dcn30_dpp.h"
+#include "dcn31/dcn31_optc.h"
+#include "dcn20/dcn20_hwseq.h"
+#include "dcn30/dcn30_hwseq.h"
+#include "dce110/dce110_hw_sequencer.h"
+#include "dcn30/dcn30_opp.h"
+#include "dcn20/dcn20_dsc.h"
+#include "dcn30/dcn30_vpg.h"
+#include "dcn30/dcn30_afmt.h"
+#include "dcn30/dcn30_dio_stream_encoder.h"
+#include "dcn31/dcn31_hpo_dp_stream_encoder.h"
+#include "dcn31/dcn31_hpo_dp_link_encoder.h"
+#include "dcn31/dcn31_apg.h"
+#include "dcn31/dcn31_dio_link_encoder.h"
+#include "dcn31/dcn31_vpg.h"
+#include "dcn31/dcn31_afmt.h"
+#include "dce/dce_clock_source.h"
+#include "dce/dce_audio.h"
+#include "dce/dce_hwseq.h"
+#include "clk_mgr.h"
+#include "virtual/virtual_stream_encoder.h"
+#include "dce110/dce110_resource.h"
+#include "dml/display_mode_vba.h"
+#include "dml/dcn31/dcn31_fpu.h"
+#include "dcn31/dcn31_dccg.h"
+#include "dcn10/dcn10_resource.h"
+#include "dcn31/dcn31_panel_cntl.h"
+
+#include "dcn30/dcn30_dwb.h"
+#include "dcn30/dcn30_mmhubbub.h"
+
+#include "dcn/dcn_3_1_6_offset.h"
+#include "dcn/dcn_3_1_6_sh_mask.h"
+#include "dpcs/dpcs_4_2_3_offset.h"
+#include "dpcs/dpcs_4_2_3_sh_mask.h"
+
+#define regBIF_BX1_BIOS_SCRATCH_2 0x003a
+#define regBIF_BX1_BIOS_SCRATCH_2_BASE_IDX 1
+#define regBIF_BX1_BIOS_SCRATCH_3 0x003b
+#define regBIF_BX1_BIOS_SCRATCH_3_BASE_IDX 1
+#define regBIF_BX1_BIOS_SCRATCH_6 0x003e
+#define regBIF_BX1_BIOS_SCRATCH_6_BASE_IDX 1
+
+#define regDCHUBBUB_DEBUG_CTRL_0 0x04d6
+#define regDCHUBBUB_DEBUG_CTRL_0_BASE_IDX 2
+#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH__SHIFT 0x10
+#define DCHUBBUB_DEBUG_CTRL_0__DET_DEPTH_MASK 0x01FF0000L
+
+#define DCN_BASE__INST0_SEG0 0x00000012
+#define DCN_BASE__INST0_SEG1 0x000000C0
+#define DCN_BASE__INST0_SEG2 0x000034C0
+#define DCN_BASE__INST0_SEG3 0x00009000
+#define DCN_BASE__INST0_SEG4 0x02403C00
+#define DCN_BASE__INST0_SEG5 0
+
+#define DPCS_BASE__INST0_SEG0 0x00000012
+#define DPCS_BASE__INST0_SEG1 0x000000C0
+#define DPCS_BASE__INST0_SEG2 0x000034C0
+#define DPCS_BASE__INST0_SEG3 0x00009000
+#define DPCS_BASE__INST0_SEG4 0x02403C00
+#define DPCS_BASE__INST0_SEG5 0
+
+#define NBIO_BASE__INST0_SEG0 0x00000000
+#define NBIO_BASE__INST0_SEG1 0x00000014
+#define NBIO_BASE__INST0_SEG2 0x00000D20
+#define NBIO_BASE__INST0_SEG3 0x00010400
+#define NBIO_BASE__INST0_SEG4 0x0241B000
+#define NBIO_BASE__INST0_SEG5 0x04040000
+
+#include "reg_helper.h"
+#include "dce/dmub_abm.h"
+#include "dce/dmub_psr.h"
+#include "dce/dce_aux.h"
+#include "dce/dce_i2c.h"
+
+#include "dml/dcn30/display_mode_vba_30.h"
+#include "vm_helper.h"
+#include "dcn20/dcn20_vmid.h"
+
+#include "link_enc_cfg.h"
+
+#define DCN3_16_MAX_DET_SIZE 384
+#define DCN3_16_MIN_COMPBUF_SIZE_KB 128
+#define DCN3_16_CRB_SEGMENT_SIZE_KB 64
+
+enum dcn31_clk_src_array_id {
+ DCN31_CLK_SRC_PLL0,
+ DCN31_CLK_SRC_PLL1,
+ DCN31_CLK_SRC_PLL2,
+ DCN31_CLK_SRC_PLL3,
+ DCN31_CLK_SRC_PLL4,
+ DCN30_CLK_SRC_TOTAL
+};
+
+/* begin *********************
+ * macros to expend register list macro defined in HW object header file
+ */
+
+/* DCN */
+/* TODO awful hack. fixup dcn20_dwb.h */
+#undef BASE_INNER
+#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
+
+#define BASE(seg) BASE_INNER(seg)
+
+#define SR(reg_name)\
+ .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \
+ reg ## reg_name
+
+#define SRI(reg_name, block, id)\
+ .reg_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRI2(reg_name, block, id)\
+ .reg_name = BASE(reg ## reg_name ## _BASE_IDX) + \
+ reg ## reg_name
+
+#define SRIR(var_name, reg_name, block, id)\
+ .var_name = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRII(reg_name, block, id)\
+ .reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRII_MPC_RMU(reg_name, block, id)\
+ .RMU##_##reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRII_DWB(reg_name, temp_name, block, id)\
+ .reg_name[id] = BASE(reg ## block ## id ## _ ## temp_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## temp_name
+
+#define DCCG_SRII(reg_name, block, id)\
+ .block ## _ ## reg_name[id] = BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define VUPDATE_SRII(reg_name, block, id)\
+ .reg_name[id] = BASE(reg ## reg_name ## _ ## block ## id ## _BASE_IDX) + \
+ reg ## reg_name ## _ ## block ## id
+
+/* NBIO */
+#define NBIO_BASE_INNER(seg) \
+ NBIO_BASE__INST0_SEG ## seg
+
+#define NBIO_BASE(seg) \
+ NBIO_BASE_INNER(seg)
+
+#define NBIO_SR(reg_name)\
+ .reg_name = NBIO_BASE(regBIF_BX1_ ## reg_name ## _BASE_IDX) + \
+ regBIF_BX1_ ## reg_name
+
+static const struct bios_registers bios_regs = {
+ NBIO_SR(BIOS_SCRATCH_3),
+ NBIO_SR(BIOS_SCRATCH_6)
+};
+
+#define clk_src_regs(index, pllid)\
+[index] = {\
+ CS_COMMON_REG_LIST_DCN3_0(index, pllid),\
+}
+
+static const struct dce110_clk_src_regs clk_src_regs[] = {
+ clk_src_regs(0, A),
+ clk_src_regs(1, B),
+ clk_src_regs(2, C),
+ clk_src_regs(3, D),
+ clk_src_regs(4, E)
+};
+
+static const struct dce110_clk_src_shift cs_shift = {
+ CS_COMMON_MASK_SH_LIST_DCN2_0(__SHIFT)
+};
+
+static const struct dce110_clk_src_mask cs_mask = {
+ CS_COMMON_MASK_SH_LIST_DCN2_0(_MASK)
+};
+
+#define abm_regs(id)\
+[id] = {\
+ ABM_DCN302_REG_LIST(id)\
+}
+
+static const struct dce_abm_registers abm_regs[] = {
+ abm_regs(0),
+ abm_regs(1),
+ abm_regs(2),
+ abm_regs(3),
+};
+
+static const struct dce_abm_shift abm_shift = {
+ ABM_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dce_abm_mask abm_mask = {
+ ABM_MASK_SH_LIST_DCN30(_MASK)
+};
+
+#define audio_regs(id)\
+[id] = {\
+ AUD_COMMON_REG_LIST(id)\
+}
+
+static const struct dce_audio_registers audio_regs[] = {
+ audio_regs(0),
+ audio_regs(1),
+ audio_regs(2),
+ audio_regs(3),
+ audio_regs(4),
+ audio_regs(5),
+ audio_regs(6)
+};
+
+#define DCE120_AUD_COMMON_MASK_SH_LIST(mask_sh)\
+ SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_INDEX, AZALIA_ENDPOINT_REG_INDEX, mask_sh),\
+ SF(AZF0ENDPOINT0_AZALIA_F0_CODEC_ENDPOINT_DATA, AZALIA_ENDPOINT_REG_DATA, mask_sh),\
+ AUD_COMMON_MASK_SH_LIST_BASE(mask_sh)
+
+static const struct dce_audio_shift audio_shift = {
+ DCE120_AUD_COMMON_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_audio_mask audio_mask = {
+ DCE120_AUD_COMMON_MASK_SH_LIST(_MASK)
+};
+
+#define vpg_regs(id)\
+[id] = {\
+ VPG_DCN31_REG_LIST(id)\
+}
+
+static const struct dcn31_vpg_registers vpg_regs[] = {
+ vpg_regs(0),
+ vpg_regs(1),
+ vpg_regs(2),
+ vpg_regs(3),
+ vpg_regs(4),
+ vpg_regs(5),
+ vpg_regs(6),
+ vpg_regs(7),
+ vpg_regs(8),
+ vpg_regs(9),
+};
+
+static const struct dcn31_vpg_shift vpg_shift = {
+ DCN31_VPG_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_vpg_mask vpg_mask = {
+ DCN31_VPG_MASK_SH_LIST(_MASK)
+};
+
+#define afmt_regs(id)\
+[id] = {\
+ AFMT_DCN31_REG_LIST(id)\
+}
+
+static const struct dcn31_afmt_registers afmt_regs[] = {
+ afmt_regs(0),
+ afmt_regs(1),
+ afmt_regs(2),
+ afmt_regs(3),
+ afmt_regs(4),
+ afmt_regs(5)
+};
+
+static const struct dcn31_afmt_shift afmt_shift = {
+ DCN31_AFMT_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_afmt_mask afmt_mask = {
+ DCN31_AFMT_MASK_SH_LIST(_MASK)
+};
+
+
+#define apg_regs(id)\
+[id] = {\
+ APG_DCN31_REG_LIST(id)\
+}
+
+static const struct dcn31_apg_registers apg_regs[] = {
+ apg_regs(0),
+ apg_regs(1),
+ apg_regs(2),
+ apg_regs(3)
+};
+
+static const struct dcn31_apg_shift apg_shift = {
+ DCN31_APG_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_apg_mask apg_mask = {
+ DCN31_APG_MASK_SH_LIST(_MASK)
+};
+
+
+#define stream_enc_regs(id)\
+[id] = {\
+ SE_DCN3_REG_LIST(id)\
+}
+
+static const struct dcn10_stream_enc_registers stream_enc_regs[] = {
+ stream_enc_regs(0),
+ stream_enc_regs(1),
+ stream_enc_regs(2),
+ stream_enc_regs(3),
+ stream_enc_regs(4)
+};
+
+static const struct dcn10_stream_encoder_shift se_shift = {
+ SE_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dcn10_stream_encoder_mask se_mask = {
+ SE_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+
+#define aux_regs(id)\
+[id] = {\
+ DCN2_AUX_REG_LIST(id)\
+}
+
+static const struct dcn10_link_enc_aux_registers link_enc_aux_regs[] = {
+ aux_regs(0),
+ aux_regs(1),
+ aux_regs(2),
+ aux_regs(3),
+ aux_regs(4)
+};
+
+#define hpd_regs(id)\
+[id] = {\
+ HPD_REG_LIST(id)\
+}
+
+static const struct dcn10_link_enc_hpd_registers link_enc_hpd_regs[] = {
+ hpd_regs(0),
+ hpd_regs(1),
+ hpd_regs(2),
+ hpd_regs(3),
+ hpd_regs(4)
+};
+
+#define link_regs(id, phyid)\
+[id] = {\
+ LE_DCN31_REG_LIST(id), \
+ UNIPHY_DCN2_REG_LIST(phyid), \
+ DPCS_DCN31_REG_LIST(id), \
+}
+
+static const struct dce110_aux_registers_shift aux_shift = {
+ DCN_AUX_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce110_aux_registers_mask aux_mask = {
+ DCN_AUX_MASK_SH_LIST(_MASK)
+};
+
+static const struct dcn10_link_enc_registers link_enc_regs[] = {
+ link_regs(0, A),
+ link_regs(1, B),
+ link_regs(2, C),
+ link_regs(3, D),
+ link_regs(4, E)
+};
+
+static const struct dcn10_link_enc_shift le_shift = {
+ LINK_ENCODER_MASK_SH_LIST_DCN31(__SHIFT), \
+ DPCS_DCN31_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn10_link_enc_mask le_mask = {
+ LINK_ENCODER_MASK_SH_LIST_DCN31(_MASK), \
+ DPCS_DCN31_MASK_SH_LIST(_MASK)
+};
+
+
+
+#define hpo_dp_stream_encoder_reg_list(id)\
+[id] = {\
+ DCN3_1_HPO_DP_STREAM_ENC_REG_LIST(id)\
+}
+
+static const struct dcn31_hpo_dp_stream_encoder_registers hpo_dp_stream_enc_regs[] = {
+ hpo_dp_stream_encoder_reg_list(0),
+ hpo_dp_stream_encoder_reg_list(1),
+ hpo_dp_stream_encoder_reg_list(2),
+ hpo_dp_stream_encoder_reg_list(3),
+};
+
+static const struct dcn31_hpo_dp_stream_encoder_shift hpo_dp_se_shift = {
+ DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_hpo_dp_stream_encoder_mask hpo_dp_se_mask = {
+ DCN3_1_HPO_DP_STREAM_ENC_MASK_SH_LIST(_MASK)
+};
+
+
+#define hpo_dp_link_encoder_reg_list(id)\
+[id] = {\
+ DCN3_1_HPO_DP_LINK_ENC_REG_LIST(id),\
+ DCN3_1_RDPCSTX_REG_LIST(0),\
+ DCN3_1_RDPCSTX_REG_LIST(1),\
+ DCN3_1_RDPCSTX_REG_LIST(2),\
+ DCN3_1_RDPCSTX_REG_LIST(3),\
+ DCN3_1_RDPCSTX_REG_LIST(4)\
+}
+
+static const struct dcn31_hpo_dp_link_encoder_registers hpo_dp_link_enc_regs[] = {
+ hpo_dp_link_encoder_reg_list(0),
+ hpo_dp_link_encoder_reg_list(1),
+};
+
+static const struct dcn31_hpo_dp_link_encoder_shift hpo_dp_le_shift = {
+ DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn31_hpo_dp_link_encoder_mask hpo_dp_le_mask = {
+ DCN3_1_HPO_DP_LINK_ENC_MASK_SH_LIST(_MASK)
+};
+
+
+#define dpp_regs(id)\
+[id] = {\
+ DPP_REG_LIST_DCN30(id),\
+}
+
+static const struct dcn3_dpp_registers dpp_regs[] = {
+ dpp_regs(0),
+ dpp_regs(1),
+ dpp_regs(2),
+ dpp_regs(3)
+};
+
+static const struct dcn3_dpp_shift tf_shift = {
+ DPP_REG_LIST_SH_MASK_DCN30(__SHIFT)
+};
+
+static const struct dcn3_dpp_mask tf_mask = {
+ DPP_REG_LIST_SH_MASK_DCN30(_MASK)
+};
+
+#define opp_regs(id)\
+[id] = {\
+ OPP_REG_LIST_DCN30(id),\
+}
+
+static const struct dcn20_opp_registers opp_regs[] = {
+ opp_regs(0),
+ opp_regs(1),
+ opp_regs(2),
+ opp_regs(3)
+};
+
+static const struct dcn20_opp_shift opp_shift = {
+ OPP_MASK_SH_LIST_DCN20(__SHIFT)
+};
+
+static const struct dcn20_opp_mask opp_mask = {
+ OPP_MASK_SH_LIST_DCN20(_MASK)
+};
+
+#define aux_engine_regs(id)\
+[id] = {\
+ AUX_COMMON_REG_LIST0(id), \
+ .AUXN_IMPCAL = 0, \
+ .AUXP_IMPCAL = 0, \
+ .AUX_RESET_MASK = DP_AUX0_AUX_CONTROL__AUX_RESET_MASK, \
+}
+
+static const struct dce110_aux_registers aux_engine_regs[] = {
+ aux_engine_regs(0),
+ aux_engine_regs(1),
+ aux_engine_regs(2),
+ aux_engine_regs(3),
+ aux_engine_regs(4)
+};
+
+#define dwbc_regs_dcn3(id)\
+[id] = {\
+ DWBC_COMMON_REG_LIST_DCN30(id),\
+}
+
+static const struct dcn30_dwbc_registers dwbc30_regs[] = {
+ dwbc_regs_dcn3(0),
+};
+
+static const struct dcn30_dwbc_shift dwbc30_shift = {
+ DWBC_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dcn30_dwbc_mask dwbc30_mask = {
+ DWBC_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+#define mcif_wb_regs_dcn3(id)\
+[id] = {\
+ MCIF_WB_COMMON_REG_LIST_DCN30(id),\
+}
+
+static const struct dcn30_mmhubbub_registers mcif_wb30_regs[] = {
+ mcif_wb_regs_dcn3(0)
+};
+
+static const struct dcn30_mmhubbub_shift mcif_wb30_shift = {
+ MCIF_WB_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dcn30_mmhubbub_mask mcif_wb30_mask = {
+ MCIF_WB_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+#define dsc_regsDCN20(id)\
+[id] = {\
+ DSC_REG_LIST_DCN20(id)\
+}
+
+static const struct dcn20_dsc_registers dsc_regs[] = {
+ dsc_regsDCN20(0),
+ dsc_regsDCN20(1),
+ dsc_regsDCN20(2)
+};
+
+static const struct dcn20_dsc_shift dsc_shift = {
+ DSC_REG_LIST_SH_MASK_DCN20(__SHIFT)
+};
+
+static const struct dcn20_dsc_mask dsc_mask = {
+ DSC_REG_LIST_SH_MASK_DCN20(_MASK)
+};
+
+static const struct dcn30_mpc_registers mpc_regs = {
+ MPC_REG_LIST_DCN3_0(0),
+ MPC_REG_LIST_DCN3_0(1),
+ MPC_REG_LIST_DCN3_0(2),
+ MPC_REG_LIST_DCN3_0(3),
+ MPC_OUT_MUX_REG_LIST_DCN3_0(0),
+ MPC_OUT_MUX_REG_LIST_DCN3_0(1),
+ MPC_OUT_MUX_REG_LIST_DCN3_0(2),
+ MPC_OUT_MUX_REG_LIST_DCN3_0(3),
+ MPC_RMU_GLOBAL_REG_LIST_DCN3AG,
+ MPC_RMU_REG_LIST_DCN3AG(0),
+ MPC_RMU_REG_LIST_DCN3AG(1),
+ //MPC_RMU_REG_LIST_DCN3AG(2),
+ MPC_DWB_MUX_REG_LIST_DCN3_0(0),
+};
+
+static const struct dcn30_mpc_shift mpc_shift = {
+ MPC_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dcn30_mpc_mask mpc_mask = {
+ MPC_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+#define optc_regs(id)\
+[id] = {OPTC_COMMON_REG_LIST_DCN3_1(id)}
+
+static const struct dcn_optc_registers optc_regs[] = {
+ optc_regs(0),
+ optc_regs(1),
+ optc_regs(2),
+ optc_regs(3)
+};
+
+static const struct dcn_optc_shift optc_shift = {
+ OPTC_COMMON_MASK_SH_LIST_DCN3_1(__SHIFT)
+};
+
+static const struct dcn_optc_mask optc_mask = {
+ OPTC_COMMON_MASK_SH_LIST_DCN3_1(_MASK)
+};
+
+#define hubp_regs(id)\
+[id] = {\
+ HUBP_REG_LIST_DCN30(id)\
+}
+
+static const struct dcn_hubp2_registers hubp_regs[] = {
+ hubp_regs(0),
+ hubp_regs(1),
+ hubp_regs(2),
+ hubp_regs(3)
+};
+
+
+static const struct dcn_hubp2_shift hubp_shift = {
+ HUBP_MASK_SH_LIST_DCN31(__SHIFT)
+};
+
+static const struct dcn_hubp2_mask hubp_mask = {
+ HUBP_MASK_SH_LIST_DCN31(_MASK)
+};
+static const struct dcn_hubbub_registers hubbub_reg = {
+ HUBBUB_REG_LIST_DCN31(0)
+};
+
+static const struct dcn_hubbub_shift hubbub_shift = {
+ HUBBUB_MASK_SH_LIST_DCN31(__SHIFT)
+};
+
+static const struct dcn_hubbub_mask hubbub_mask = {
+ HUBBUB_MASK_SH_LIST_DCN31(_MASK)
+};
+
+static const struct dccg_registers dccg_regs = {
+ DCCG_REG_LIST_DCN31()
+};
+
+static const struct dccg_shift dccg_shift = {
+ DCCG_MASK_SH_LIST_DCN31(__SHIFT)
+};
+
+static const struct dccg_mask dccg_mask = {
+ DCCG_MASK_SH_LIST_DCN31(_MASK)
+};
+
+
+#define SRII2(reg_name_pre, reg_name_post, id)\
+ .reg_name_pre ## _ ## reg_name_post[id] = BASE(reg ## reg_name_pre \
+ ## id ## _ ## reg_name_post ## _BASE_IDX) + \
+ reg ## reg_name_pre ## id ## _ ## reg_name_post
+
+
+#define HWSEQ_DCN31_REG_LIST()\
+ SR(DCHUBBUB_GLOBAL_TIMER_CNTL), \
+ SR(DCHUBBUB_ARB_HOSTVM_CNTL), \
+ SR(DIO_MEM_PWR_CTRL), \
+ SR(ODM_MEM_PWR_CTRL3), \
+ SR(DMU_MEM_PWR_CNTL), \
+ SR(MMHUBBUB_MEM_PWR_CNTL), \
+ SR(DCCG_GATE_DISABLE_CNTL), \
+ SR(DCCG_GATE_DISABLE_CNTL2), \
+ SR(DCFCLK_CNTL),\
+ SR(DC_MEM_GLOBAL_PWR_REQ_CNTL), \
+ SRII(PIXEL_RATE_CNTL, OTG, 0), \
+ SRII(PIXEL_RATE_CNTL, OTG, 1),\
+ SRII(PIXEL_RATE_CNTL, OTG, 2),\
+ SRII(PIXEL_RATE_CNTL, OTG, 3),\
+ SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 0),\
+ SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 1),\
+ SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 2),\
+ SRII(PHYPLL_PIXEL_RATE_CNTL, OTG, 3),\
+ SR(MICROSECOND_TIME_BASE_DIV), \
+ SR(MILLISECOND_TIME_BASE_DIV), \
+ SR(DISPCLK_FREQ_CHANGE_CNTL), \
+ SR(RBBMIF_TIMEOUT_DIS), \
+ SR(RBBMIF_TIMEOUT_DIS_2), \
+ SR(DCHUBBUB_CRC_CTRL), \
+ SR(DPP_TOP0_DPP_CRC_CTRL), \
+ SR(DPP_TOP0_DPP_CRC_VAL_B_A), \
+ SR(DPP_TOP0_DPP_CRC_VAL_R_G), \
+ SR(MPC_CRC_CTRL), \
+ SR(MPC_CRC_RESULT_GB), \
+ SR(MPC_CRC_RESULT_C), \
+ SR(MPC_CRC_RESULT_AR), \
+ SR(DOMAIN0_PG_CONFIG), \
+ SR(DOMAIN1_PG_CONFIG), \
+ SR(DOMAIN2_PG_CONFIG), \
+ SR(DOMAIN3_PG_CONFIG), \
+ SR(DOMAIN16_PG_CONFIG), \
+ SR(DOMAIN17_PG_CONFIG), \
+ SR(DOMAIN18_PG_CONFIG), \
+ SR(DOMAIN0_PG_STATUS), \
+ SR(DOMAIN1_PG_STATUS), \
+ SR(DOMAIN2_PG_STATUS), \
+ SR(DOMAIN3_PG_STATUS), \
+ SR(DOMAIN16_PG_STATUS), \
+ SR(DOMAIN17_PG_STATUS), \
+ SR(DOMAIN18_PG_STATUS), \
+ SR(D1VGA_CONTROL), \
+ SR(D2VGA_CONTROL), \
+ SR(D3VGA_CONTROL), \
+ SR(D4VGA_CONTROL), \
+ SR(D5VGA_CONTROL), \
+ SR(D6VGA_CONTROL), \
+ SR(DC_IP_REQUEST_CNTL), \
+ SR(AZALIA_AUDIO_DTO), \
+ SR(AZALIA_CONTROLLER_CLOCK_GATING), \
+ SR(HPO_TOP_HW_CONTROL)
+
+static const struct dce_hwseq_registers hwseq_reg = {
+ HWSEQ_DCN31_REG_LIST()
+};
+
+#define HWSEQ_DCN31_MASK_SH_LIST(mask_sh)\
+ HWSEQ_DCN_MASK_SH_LIST(mask_sh), \
+ HWS_SF(, DCHUBBUB_GLOBAL_TIMER_CNTL, DCHUBBUB_GLOBAL_TIMER_REFDIV, mask_sh), \
+ HWS_SF(, DCHUBBUB_ARB_HOSTVM_CNTL, DISABLE_HOSTVM_FORCE_ALLOW_PSTATE, mask_sh), \
+ HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN0_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN1_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN2_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN3_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN16_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN17_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_FORCEON, mask_sh), \
+ HWS_SF(, DOMAIN18_PG_CONFIG, DOMAIN_POWER_GATE, mask_sh), \
+ HWS_SF(, DOMAIN0_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN1_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN2_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN3_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN16_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN17_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DOMAIN18_PG_STATUS, DOMAIN_PGFSM_PWR_STATUS, mask_sh), \
+ HWS_SF(, DC_IP_REQUEST_CNTL, IP_REQUEST_EN, mask_sh), \
+ HWS_SF(, AZALIA_AUDIO_DTO, AZALIA_AUDIO_DTO_MODULE, mask_sh), \
+ HWS_SF(, HPO_TOP_CLOCK_CONTROL, HPO_HDMISTREAMCLK_G_GATE_DIS, mask_sh), \
+ HWS_SF(, DMU_MEM_PWR_CNTL, DMCU_ERAM_MEM_PWR_FORCE, mask_sh), \
+ HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_UNASSIGNED_PWR_MODE, mask_sh), \
+ HWS_SF(, ODM_MEM_PWR_CTRL3, ODM_MEM_VBLANK_PWR_MODE, mask_sh), \
+ HWS_SF(, MMHUBBUB_MEM_PWR_CNTL, VGA_MEM_PWR_FORCE, mask_sh), \
+ HWS_SF(, DIO_MEM_PWR_CTRL, I2C_LIGHT_SLEEP_FORCE, mask_sh), \
+ HWS_SF(, HPO_TOP_HW_CONTROL, HPO_IO_EN, mask_sh)
+
+static const struct dce_hwseq_shift hwseq_shift = {
+ HWSEQ_DCN31_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dce_hwseq_mask hwseq_mask = {
+ HWSEQ_DCN31_MASK_SH_LIST(_MASK)
+};
+#define vmid_regs(id)\
+[id] = {\
+ DCN20_VMID_REG_LIST(id)\
+}
+
+static const struct dcn_vmid_registers vmid_regs[] = {
+ vmid_regs(0),
+ vmid_regs(1),
+ vmid_regs(2),
+ vmid_regs(3),
+ vmid_regs(4),
+ vmid_regs(5),
+ vmid_regs(6),
+ vmid_regs(7),
+ vmid_regs(8),
+ vmid_regs(9),
+ vmid_regs(10),
+ vmid_regs(11),
+ vmid_regs(12),
+ vmid_regs(13),
+ vmid_regs(14),
+ vmid_regs(15)
+};
+
+static const struct dcn20_vmid_shift vmid_shifts = {
+ DCN20_VMID_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct dcn20_vmid_mask vmid_masks = {
+ DCN20_VMID_MASK_SH_LIST(_MASK)
+};
+
+static const struct resource_caps res_cap_dcn31 = {
+ .num_timing_generator = 4,
+ .num_opp = 4,
+ .num_video_plane = 4,
+ .num_audio = 5,
+ .num_stream_encoder = 5,
+ .num_dig_link_enc = 5,
+ .num_hpo_dp_stream_encoder = 4,
+ .num_hpo_dp_link_encoder = 2,
+ .num_pll = 5,
+ .num_dwb = 1,
+ .num_ddc = 5,
+ .num_vmid = 16,
+ .num_mpc_3dlut = 2,
+ .num_dsc = 3,
+};
+
+static const struct dc_plane_cap plane_cap = {
+ .type = DC_PLANE_TYPE_DCN_UNIVERSAL,
+ .blends_with_above = true,
+ .blends_with_below = true,
+ .per_pixel_alpha = true,
+
+ .pixel_format_support = {
+ .argb8888 = true,
+ .nv12 = true,
+ .fp16 = true,
+ .p010 = true,
+ .ayuv = false,
+ },
+
+ .max_upscale_factor = {
+ .argb8888 = 16000,
+ .nv12 = 16000,
+ .fp16 = 16000
+ },
+
+ // 6:1 downscaling ratio: 1000/6 = 166.666
+ .max_downscale_factor = {
+ .argb8888 = 167,
+ .nv12 = 167,
+ .fp16 = 167
+ },
+ 64,
+ 64
+};
+
+static const struct dc_debug_options debug_defaults_drv = {
+ .disable_z10 = true, /*hw not support it*/
+ .disable_dmcu = true,
+ .force_abm_enable = false,
+ .timing_trace = false,
+ .clock_trace = true,
+ .disable_pplib_clock_request = false,
+ .pipe_split_policy = MPC_SPLIT_DYNAMIC,
+ .force_single_disp_pipe_split = false,
+ .disable_dcc = DCC_ENABLE,
+ .vsr_support = true,
+ .performance_trace = false,
+ .max_downscale_src_width = 4096,/*upto true 4k*/
+ .disable_pplib_wm_range = false,
+ .scl_reset_length10 = true,
+ .sanity_checks = false,
+ .underflow_assert_delay_us = 0xFFFFFFFF,
+ .dwb_fi_phase = -1, // -1 = disable,
+ .dmub_command_table = true,
+ .pstate_enabled = true,
+ .use_max_lb = true,
+ .enable_mem_low_power = {
+ .bits = {
+ .vga = true,
+ .i2c = true,
+ .dmcu = false, // This is previously known to cause hang on S3 cycles if enabled
+ .dscl = true,
+ .cm = true,
+ .mpc = true,
+ .optc = true,
+ .vpg = true,
+ .afmt = true,
+ }
+ },
+ .optimize_edp_link_rate = true,
+ .enable_sw_cntl_psr = true,
+};
+
+static const struct dc_debug_options debug_defaults_diags = {
+ .disable_dmcu = true,
+ .force_abm_enable = false,
+ .timing_trace = true,
+ .clock_trace = true,
+ .disable_dpp_power_gate = true,
+ .disable_hubp_power_gate = true,
+ .disable_clock_gate = true,
+ .disable_pplib_clock_request = true,
+ .disable_pplib_wm_range = true,
+ .disable_stutter = false,
+ .scl_reset_length10 = true,
+ .dwb_fi_phase = -1, // -1 = disable
+ .dmub_command_table = true,
+ .enable_tri_buf = true,
+ .use_max_lb = true
+};
+
+static void dcn31_dpp_destroy(struct dpp **dpp)
+{
+ kfree(TO_DCN20_DPP(*dpp));
+ *dpp = NULL;
+}
+
+static struct dpp *dcn31_dpp_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn3_dpp *dpp =
+ kzalloc(sizeof(struct dcn3_dpp), GFP_KERNEL);
+
+ if (!dpp)
+ return NULL;
+
+ if (dpp3_construct(dpp, ctx, inst,
+ &dpp_regs[inst], &tf_shift, &tf_mask))
+ return &dpp->base;
+
+ BREAK_TO_DEBUGGER();
+ kfree(dpp);
+ return NULL;
+}
+
+static struct output_pixel_processor *dcn31_opp_create(
+ struct dc_context *ctx, uint32_t inst)
+{
+ struct dcn20_opp *opp =
+ kzalloc(sizeof(struct dcn20_opp), GFP_KERNEL);
+
+ if (!opp) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ dcn20_opp_construct(opp, ctx, inst,
+ &opp_regs[inst], &opp_shift, &opp_mask);
+ return &opp->base;
+}
+
+static struct dce_aux *dcn31_aux_engine_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct aux_engine_dce110 *aux_engine =
+ kzalloc(sizeof(struct aux_engine_dce110), GFP_KERNEL);
+
+ if (!aux_engine)
+ return NULL;
+
+ dce110_aux_engine_construct(aux_engine, ctx, inst,
+ SW_AUX_TIMEOUT_PERIOD_MULTIPLIER * AUX_TIMEOUT_PERIOD,
+ &aux_engine_regs[inst],
+ &aux_mask,
+ &aux_shift,
+ ctx->dc->caps.extended_aux_timeout_support);
+
+ return &aux_engine->base;
+}
+#define i2c_inst_regs(id) { I2C_HW_ENGINE_COMMON_REG_LIST_DCN30(id) }
+
+static const struct dce_i2c_registers i2c_hw_regs[] = {
+ i2c_inst_regs(1),
+ i2c_inst_regs(2),
+ i2c_inst_regs(3),
+ i2c_inst_regs(4),
+ i2c_inst_regs(5),
+};
+
+static const struct dce_i2c_shift i2c_shifts = {
+ I2C_COMMON_MASK_SH_LIST_DCN30(__SHIFT)
+};
+
+static const struct dce_i2c_mask i2c_masks = {
+ I2C_COMMON_MASK_SH_LIST_DCN30(_MASK)
+};
+
+static struct dce_i2c_hw *dcn31_i2c_hw_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dce_i2c_hw *dce_i2c_hw =
+ kzalloc(sizeof(struct dce_i2c_hw), GFP_KERNEL);
+
+ if (!dce_i2c_hw)
+ return NULL;
+
+ dcn2_i2c_hw_construct(dce_i2c_hw, ctx, inst,
+ &i2c_hw_regs[inst], &i2c_shifts, &i2c_masks);
+
+ return dce_i2c_hw;
+}
+static struct mpc *dcn31_mpc_create(
+ struct dc_context *ctx,
+ int num_mpcc,
+ int num_rmu)
+{
+ struct dcn30_mpc *mpc30 = kzalloc(sizeof(struct dcn30_mpc),
+ GFP_KERNEL);
+
+ if (!mpc30)
+ return NULL;
+
+ dcn30_mpc_construct(mpc30, ctx,
+ &mpc_regs,
+ &mpc_shift,
+ &mpc_mask,
+ num_mpcc,
+ num_rmu);
+
+ return &mpc30->base;
+}
+
+static struct hubbub *dcn31_hubbub_create(struct dc_context *ctx)
+{
+ int i;
+
+ struct dcn20_hubbub *hubbub3 = kzalloc(sizeof(struct dcn20_hubbub),
+ GFP_KERNEL);
+
+ if (!hubbub3)
+ return NULL;
+
+ hubbub31_construct(hubbub3, ctx,
+ &hubbub_reg,
+ &hubbub_shift,
+ &hubbub_mask,
+ dcn3_16_ip.det_buffer_size_kbytes,
+ dcn3_16_ip.pixel_chunk_size_kbytes,
+ dcn3_16_ip.config_return_buffer_size_in_kbytes);
+
+
+ for (i = 0; i < res_cap_dcn31.num_vmid; i++) {
+ struct dcn20_vmid *vmid = &hubbub3->vmid[i];
+
+ vmid->ctx = ctx;
+
+ vmid->regs = &vmid_regs[i];
+ vmid->shifts = &vmid_shifts;
+ vmid->masks = &vmid_masks;
+ }
+
+ return &hubbub3->base;
+}
+
+static struct timing_generator *dcn31_timing_generator_create(
+ struct dc_context *ctx,
+ uint32_t instance)
+{
+ struct optc *tgn10 =
+ kzalloc(sizeof(struct optc), GFP_KERNEL);
+
+ if (!tgn10)
+ return NULL;
+
+ tgn10->base.inst = instance;
+ tgn10->base.ctx = ctx;
+
+ tgn10->tg_regs = &optc_regs[instance];
+ tgn10->tg_shift = &optc_shift;
+ tgn10->tg_mask = &optc_mask;
+
+ dcn31_timing_generator_init(tgn10);
+
+ return &tgn10->base;
+}
+
+static const struct encoder_feature_support link_enc_feature = {
+ .max_hdmi_deep_color = COLOR_DEPTH_121212,
+ .max_hdmi_pixel_clock = 600000,
+ .hdmi_ycbcr420_supported = true,
+ .dp_ycbcr420_supported = true,
+ .fec_supported = true,
+ .flags.bits.IS_HBR2_CAPABLE = true,
+ .flags.bits.IS_HBR3_CAPABLE = true,
+ .flags.bits.IS_TPS3_CAPABLE = true,
+ .flags.bits.IS_TPS4_CAPABLE = true
+};
+
+static struct link_encoder *dcn31_link_encoder_create(
+ const struct encoder_init_data *enc_init_data)
+{
+ struct dcn20_link_encoder *enc20 =
+ kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL);
+
+ if (!enc20)
+ return NULL;
+
+ dcn31_link_encoder_construct(enc20,
+ enc_init_data,
+ &link_enc_feature,
+ &link_enc_regs[enc_init_data->transmitter],
+ &link_enc_aux_regs[enc_init_data->channel - 1],
+ &link_enc_hpd_regs[enc_init_data->hpd_source],
+ &le_shift,
+ &le_mask);
+
+ return &enc20->enc10.base;
+}
+
+/* Create a minimal link encoder object not associated with a particular
+ * physical connector.
+ * resource_funcs.link_enc_create_minimal
+ */
+static struct link_encoder *dcn31_link_enc_create_minimal(
+ struct dc_context *ctx, enum engine_id eng_id)
+{
+ struct dcn20_link_encoder *enc20;
+
+ if ((eng_id - ENGINE_ID_DIGA) > ctx->dc->res_pool->res_cap->num_dig_link_enc)
+ return NULL;
+
+ enc20 = kzalloc(sizeof(struct dcn20_link_encoder), GFP_KERNEL);
+ if (!enc20)
+ return NULL;
+
+ dcn31_link_encoder_construct_minimal(
+ enc20,
+ ctx,
+ &link_enc_feature,
+ &link_enc_regs[eng_id - ENGINE_ID_DIGA],
+ eng_id);
+
+ return &enc20->enc10.base;
+}
+
+static struct panel_cntl *dcn31_panel_cntl_create(const struct panel_cntl_init_data *init_data)
+{
+ struct dcn31_panel_cntl *panel_cntl =
+ kzalloc(sizeof(struct dcn31_panel_cntl), GFP_KERNEL);
+
+ if (!panel_cntl)
+ return NULL;
+
+ dcn31_panel_cntl_construct(panel_cntl, init_data);
+
+ return &panel_cntl->base;
+}
+
+static void read_dce_straps(
+ struct dc_context *ctx,
+ struct resource_straps *straps)
+{
+ generic_reg_get(ctx, regDC_PINSTRAPS + BASE(regDC_PINSTRAPS_BASE_IDX),
+ FN(DC_PINSTRAPS, DC_PINSTRAPS_AUDIO), &straps->dc_pinstraps_audio);
+
+}
+
+static struct audio *dcn31_create_audio(
+ struct dc_context *ctx, unsigned int inst)
+{
+ return dce_audio_create(ctx, inst,
+ &audio_regs[inst], &audio_shift, &audio_mask);
+}
+
+static struct vpg *dcn31_vpg_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn31_vpg *vpg31 = kzalloc(sizeof(struct dcn31_vpg), GFP_KERNEL);
+
+ if (!vpg31)
+ return NULL;
+
+ vpg31_construct(vpg31, ctx, inst,
+ &vpg_regs[inst],
+ &vpg_shift,
+ &vpg_mask);
+
+ return &vpg31->base;
+}
+
+static struct afmt *dcn31_afmt_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn31_afmt *afmt31 = kzalloc(sizeof(struct dcn31_afmt), GFP_KERNEL);
+
+ if (!afmt31)
+ return NULL;
+
+ afmt31_construct(afmt31, ctx, inst,
+ &afmt_regs[inst],
+ &afmt_shift,
+ &afmt_mask);
+
+ // Light sleep by default, no need to power down here
+
+ return &afmt31->base;
+}
+
+
+static struct apg *dcn31_apg_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn31_apg *apg31 = kzalloc(sizeof(struct dcn31_apg), GFP_KERNEL);
+
+ if (!apg31)
+ return NULL;
+
+ apg31_construct(apg31, ctx, inst,
+ &apg_regs[inst],
+ &apg_shift,
+ &apg_mask);
+
+ return &apg31->base;
+}
+
+
+static struct stream_encoder *dcn316_stream_encoder_create(
+ enum engine_id eng_id,
+ struct dc_context *ctx)
+{
+ struct dcn10_stream_encoder *enc1;
+ struct vpg *vpg;
+ struct afmt *afmt;
+ int vpg_inst;
+ int afmt_inst;
+
+ /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
+ if (eng_id <= ENGINE_ID_DIGF) {
+ vpg_inst = eng_id;
+ afmt_inst = eng_id;
+ } else
+ return NULL;
+
+ enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
+ vpg = dcn31_vpg_create(ctx, vpg_inst);
+ afmt = dcn31_afmt_create(ctx, afmt_inst);
+
+ if (!enc1 || !vpg || !afmt) {
+ kfree(enc1);
+ kfree(vpg);
+ kfree(afmt);
+ return NULL;
+ }
+
+ dcn30_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios,
+ eng_id, vpg, afmt,
+ &stream_enc_regs[eng_id],
+ &se_shift, &se_mask);
+
+ return &enc1->base;
+}
+
+
+static struct hpo_dp_stream_encoder *dcn31_hpo_dp_stream_encoder_create(
+ enum engine_id eng_id,
+ struct dc_context *ctx)
+{
+ struct dcn31_hpo_dp_stream_encoder *hpo_dp_enc31;
+ struct vpg *vpg;
+ struct apg *apg;
+ uint32_t hpo_dp_inst;
+ uint32_t vpg_inst;
+ uint32_t apg_inst;
+
+ ASSERT((eng_id >= ENGINE_ID_HPO_DP_0) && (eng_id <= ENGINE_ID_HPO_DP_3));
+ hpo_dp_inst = eng_id - ENGINE_ID_HPO_DP_0;
+
+ /* Mapping of VPG register blocks to HPO DP block instance:
+ * VPG[6] -> HPO_DP[0]
+ * VPG[7] -> HPO_DP[1]
+ * VPG[8] -> HPO_DP[2]
+ * VPG[9] -> HPO_DP[3]
+ */
+ vpg_inst = hpo_dp_inst + 6;
+
+ /* Mapping of APG register blocks to HPO DP block instance:
+ * APG[0] -> HPO_DP[0]
+ * APG[1] -> HPO_DP[1]
+ * APG[2] -> HPO_DP[2]
+ * APG[3] -> HPO_DP[3]
+ */
+ apg_inst = hpo_dp_inst;
+
+ /* allocate HPO stream encoder and create VPG sub-block */
+ hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_stream_encoder), GFP_KERNEL);
+ vpg = dcn31_vpg_create(ctx, vpg_inst);
+ apg = dcn31_apg_create(ctx, apg_inst);
+
+ if (!hpo_dp_enc31 || !vpg || !apg) {
+ kfree(hpo_dp_enc31);
+ kfree(vpg);
+ kfree(apg);
+ return NULL;
+ }
+
+ dcn31_hpo_dp_stream_encoder_construct(hpo_dp_enc31, ctx, ctx->dc_bios,
+ hpo_dp_inst, eng_id, vpg, apg,
+ &hpo_dp_stream_enc_regs[hpo_dp_inst],
+ &hpo_dp_se_shift, &hpo_dp_se_mask);
+
+ return &hpo_dp_enc31->base;
+}
+
+static struct hpo_dp_link_encoder *dcn31_hpo_dp_link_encoder_create(
+ uint8_t inst,
+ struct dc_context *ctx)
+{
+ struct dcn31_hpo_dp_link_encoder *hpo_dp_enc31;
+
+ /* allocate HPO link encoder */
+ hpo_dp_enc31 = kzalloc(sizeof(struct dcn31_hpo_dp_link_encoder), GFP_KERNEL);
+
+ hpo_dp_link_encoder31_construct(hpo_dp_enc31, ctx, inst,
+ &hpo_dp_link_enc_regs[inst],
+ &hpo_dp_le_shift, &hpo_dp_le_mask);
+
+ return &hpo_dp_enc31->base;
+}
+
+
+static struct dce_hwseq *dcn31_hwseq_create(
+ struct dc_context *ctx)
+{
+ struct dce_hwseq *hws = kzalloc(sizeof(struct dce_hwseq), GFP_KERNEL);
+
+ if (hws) {
+ hws->ctx = ctx;
+ hws->regs = &hwseq_reg;
+ hws->shifts = &hwseq_shift;
+ hws->masks = &hwseq_mask;
+ /* DCN3.1 FPGA Workaround
+ * Need to enable HPO DP Stream Encoder before setting OTG master enable.
+ * To do so, move calling function enable_stream_timing to only be done AFTER calling
+ * function core_link_enable_stream
+ */
+ if (IS_FPGA_MAXIMUS_DC(ctx->dce_environment))
+ hws->wa.dp_hpo_and_otg_sequence = true;
+ }
+ return hws;
+}
+static const struct resource_create_funcs res_create_funcs = {
+ .read_dce_straps = read_dce_straps,
+ .create_audio = dcn31_create_audio,
+ .create_stream_encoder = dcn316_stream_encoder_create,
+ .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create,
+ .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create,
+ .create_hwseq = dcn31_hwseq_create,
+};
+
+static const struct resource_create_funcs res_create_maximus_funcs = {
+ .read_dce_straps = NULL,
+ .create_audio = NULL,
+ .create_stream_encoder = NULL,
+ .create_hpo_dp_stream_encoder = dcn31_hpo_dp_stream_encoder_create,
+ .create_hpo_dp_link_encoder = dcn31_hpo_dp_link_encoder_create,
+ .create_hwseq = dcn31_hwseq_create,
+};
+
+static void dcn316_resource_destruct(struct dcn316_resource_pool *pool)
+{
+ unsigned int i;
+
+ for (i = 0; i < pool->base.stream_enc_count; i++) {
+ if (pool->base.stream_enc[i] != NULL) {
+ if (pool->base.stream_enc[i]->vpg != NULL) {
+ kfree(DCN30_VPG_FROM_VPG(pool->base.stream_enc[i]->vpg));
+ pool->base.stream_enc[i]->vpg = NULL;
+ }
+ if (pool->base.stream_enc[i]->afmt != NULL) {
+ kfree(DCN30_AFMT_FROM_AFMT(pool->base.stream_enc[i]->afmt));
+ pool->base.stream_enc[i]->afmt = NULL;
+ }
+ kfree(DCN10STRENC_FROM_STRENC(pool->base.stream_enc[i]));
+ pool->base.stream_enc[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.hpo_dp_stream_enc_count; i++) {
+ if (pool->base.hpo_dp_stream_enc[i] != NULL) {
+ if (pool->base.hpo_dp_stream_enc[i]->vpg != NULL) {
+ kfree(DCN30_VPG_FROM_VPG(pool->base.hpo_dp_stream_enc[i]->vpg));
+ pool->base.hpo_dp_stream_enc[i]->vpg = NULL;
+ }
+ if (pool->base.hpo_dp_stream_enc[i]->apg != NULL) {
+ kfree(DCN31_APG_FROM_APG(pool->base.hpo_dp_stream_enc[i]->apg));
+ pool->base.hpo_dp_stream_enc[i]->apg = NULL;
+ }
+ kfree(DCN3_1_HPO_DP_STREAM_ENC_FROM_HPO_STREAM_ENC(pool->base.hpo_dp_stream_enc[i]));
+ pool->base.hpo_dp_stream_enc[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.hpo_dp_link_enc_count; i++) {
+ if (pool->base.hpo_dp_link_enc[i] != NULL) {
+ kfree(DCN3_1_HPO_DP_LINK_ENC_FROM_HPO_LINK_ENC(pool->base.hpo_dp_link_enc[i]));
+ pool->base.hpo_dp_link_enc[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
+ if (pool->base.dscs[i] != NULL)
+ dcn20_dsc_destroy(&pool->base.dscs[i]);
+ }
+
+ if (pool->base.mpc != NULL) {
+ kfree(TO_DCN20_MPC(pool->base.mpc));
+ pool->base.mpc = NULL;
+ }
+ if (pool->base.hubbub != NULL) {
+ kfree(pool->base.hubbub);
+ pool->base.hubbub = NULL;
+ }
+ for (i = 0; i < pool->base.pipe_count; i++) {
+ if (pool->base.dpps[i] != NULL)
+ dcn31_dpp_destroy(&pool->base.dpps[i]);
+
+ if (pool->base.ipps[i] != NULL)
+ pool->base.ipps[i]->funcs->ipp_destroy(&pool->base.ipps[i]);
+
+ if (pool->base.hubps[i] != NULL) {
+ kfree(TO_DCN20_HUBP(pool->base.hubps[i]));
+ pool->base.hubps[i] = NULL;
+ }
+
+ if (pool->base.irqs != NULL) {
+ dal_irq_service_destroy(&pool->base.irqs);
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_ddc; i++) {
+ if (pool->base.engines[i] != NULL)
+ dce110_engine_destroy(&pool->base.engines[i]);
+ if (pool->base.hw_i2cs[i] != NULL) {
+ kfree(pool->base.hw_i2cs[i]);
+ pool->base.hw_i2cs[i] = NULL;
+ }
+ if (pool->base.sw_i2cs[i] != NULL) {
+ kfree(pool->base.sw_i2cs[i]);
+ pool->base.sw_i2cs[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_opp; i++) {
+ if (pool->base.opps[i] != NULL)
+ pool->base.opps[i]->funcs->opp_destroy(&pool->base.opps[i]);
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+ if (pool->base.timing_generators[i] != NULL) {
+ kfree(DCN10TG_FROM_TG(pool->base.timing_generators[i]));
+ pool->base.timing_generators[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_dwb; i++) {
+ if (pool->base.dwbc[i] != NULL) {
+ kfree(TO_DCN30_DWBC(pool->base.dwbc[i]));
+ pool->base.dwbc[i] = NULL;
+ }
+ if (pool->base.mcif_wb[i] != NULL) {
+ kfree(TO_DCN30_MMHUBBUB(pool->base.mcif_wb[i]));
+ pool->base.mcif_wb[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.audio_count; i++) {
+ if (pool->base.audios[i])
+ dce_aud_destroy(&pool->base.audios[i]);
+ }
+
+ for (i = 0; i < pool->base.clk_src_count; i++) {
+ if (pool->base.clock_sources[i] != NULL) {
+ dcn20_clock_source_destroy(&pool->base.clock_sources[i]);
+ pool->base.clock_sources[i] = NULL;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_mpc_3dlut; i++) {
+ if (pool->base.mpc_lut[i] != NULL) {
+ dc_3dlut_func_release(pool->base.mpc_lut[i]);
+ pool->base.mpc_lut[i] = NULL;
+ }
+ if (pool->base.mpc_shaper[i] != NULL) {
+ dc_transfer_func_release(pool->base.mpc_shaper[i]);
+ pool->base.mpc_shaper[i] = NULL;
+ }
+ }
+
+ if (pool->base.dp_clock_source != NULL) {
+ dcn20_clock_source_destroy(&pool->base.dp_clock_source);
+ pool->base.dp_clock_source = NULL;
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+ if (pool->base.multiple_abms[i] != NULL)
+ dce_abm_destroy(&pool->base.multiple_abms[i]);
+ }
+
+ if (pool->base.psr != NULL)
+ dmub_psr_destroy(&pool->base.psr);
+
+ if (pool->base.dccg != NULL)
+ dcn_dccg_destroy(&pool->base.dccg);
+}
+
+static struct hubp *dcn31_hubp_create(
+ struct dc_context *ctx,
+ uint32_t inst)
+{
+ struct dcn20_hubp *hubp2 =
+ kzalloc(sizeof(struct dcn20_hubp), GFP_KERNEL);
+
+ if (!hubp2)
+ return NULL;
+
+ if (hubp31_construct(hubp2, ctx, inst,
+ &hubp_regs[inst], &hubp_shift, &hubp_mask))
+ return &hubp2->base;
+
+ BREAK_TO_DEBUGGER();
+ kfree(hubp2);
+ return NULL;
+}
+
+static bool dcn31_dwbc_create(struct dc_context *ctx, struct resource_pool *pool)
+{
+ int i;
+ uint32_t pipe_count = pool->res_cap->num_dwb;
+
+ for (i = 0; i < pipe_count; i++) {
+ struct dcn30_dwbc *dwbc30 = kzalloc(sizeof(struct dcn30_dwbc),
+ GFP_KERNEL);
+
+ if (!dwbc30) {
+ dm_error("DC: failed to create dwbc30!\n");
+ return false;
+ }
+
+ dcn30_dwbc_construct(dwbc30, ctx,
+ &dwbc30_regs[i],
+ &dwbc30_shift,
+ &dwbc30_mask,
+ i);
+
+ pool->dwbc[i] = &dwbc30->base;
+ }
+ return true;
+}
+
+static bool dcn31_mmhubbub_create(struct dc_context *ctx, struct resource_pool *pool)
+{
+ int i;
+ uint32_t pipe_count = pool->res_cap->num_dwb;
+
+ for (i = 0; i < pipe_count; i++) {
+ struct dcn30_mmhubbub *mcif_wb30 = kzalloc(sizeof(struct dcn30_mmhubbub),
+ GFP_KERNEL);
+
+ if (!mcif_wb30) {
+ dm_error("DC: failed to create mcif_wb30!\n");
+ return false;
+ }
+
+ dcn30_mmhubbub_construct(mcif_wb30, ctx,
+ &mcif_wb30_regs[i],
+ &mcif_wb30_shift,
+ &mcif_wb30_mask,
+ i);
+
+ pool->mcif_wb[i] = &mcif_wb30->base;
+ }
+ return true;
+}
+
+static struct display_stream_compressor *dcn31_dsc_create(
+ struct dc_context *ctx, uint32_t inst)
+{
+ struct dcn20_dsc *dsc =
+ kzalloc(sizeof(struct dcn20_dsc), GFP_KERNEL);
+
+ if (!dsc) {
+ BREAK_TO_DEBUGGER();
+ return NULL;
+ }
+
+ dsc2_construct(dsc, ctx, inst, &dsc_regs[inst], &dsc_shift, &dsc_mask);
+ return &dsc->base;
+}
+
+static void dcn316_destroy_resource_pool(struct resource_pool **pool)
+{
+ struct dcn316_resource_pool *dcn31_pool = TO_DCN316_RES_POOL(*pool);
+
+ dcn316_resource_destruct(dcn31_pool);
+ kfree(dcn31_pool);
+ *pool = NULL;
+}
+
+static struct clock_source *dcn31_clock_source_create(
+ struct dc_context *ctx,
+ struct dc_bios *bios,
+ enum clock_source_id id,
+ const struct dce110_clk_src_regs *regs,
+ bool dp_clk_src)
+{
+ struct dce110_clk_src *clk_src =
+ kzalloc(sizeof(struct dce110_clk_src), GFP_KERNEL);
+
+ if (!clk_src)
+ return NULL;
+
+ if (dcn31_clk_src_construct(clk_src, ctx, bios, id,
+ regs, &cs_shift, &cs_mask)) {
+ clk_src->base.dp_clk_src = dp_clk_src;
+ return &clk_src->base;
+ }
+
+ kfree(clk_src);
+
+ BREAK_TO_DEBUGGER();
+ return NULL;
+}
+
+static bool is_dual_plane(enum surface_pixel_format format)
+{
+ return format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN || format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA;
+}
+
+static int dcn316_populate_dml_pipes_from_context(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate)
+{
+ int i, pipe_cnt;
+ struct resource_context *res_ctx = &context->res_ctx;
+ struct pipe_ctx *pipe;
+ const int max_usable_det = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes - DCN3_16_MIN_COMPBUF_SIZE_KB;
+
+ DC_FP_START();
+ dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+ DC_FP_END();
+
+ for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
+ struct dc_crtc_timing *timing;
+
+ if (!res_ctx->pipe_ctx[i].stream)
+ continue;
+ pipe = &res_ctx->pipe_ctx[i];
+ timing = &pipe->stream->timing;
+
+ /*
+ * Immediate flip can be set dynamically after enabling the plane.
+ * We need to require support for immediate flip or underflow can be
+ * intermittently experienced depending on peak b/w requirements.
+ */
+ pipes[pipe_cnt].pipe.src.immediate_flip = true;
+
+ pipes[pipe_cnt].pipe.src.unbounded_req_mode = false;
+ pipes[pipe_cnt].pipe.src.gpuvm = true;
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_luma = 0;
+ pipes[pipe_cnt].pipe.src.dcc_fraction_of_zs_req_chroma = 0;
+ pipes[pipe_cnt].pipe.dest.vfront_porch = timing->v_front_porch;
+ pipes[pipe_cnt].pipe.src.dcc_rate = 3;
+ pipes[pipe_cnt].dout.dsc_input_bpc = 0;
+
+ if (pipes[pipe_cnt].dout.dsc_enable) {
+ switch (timing->display_color_depth) {
+ case COLOR_DEPTH_888:
+ pipes[pipe_cnt].dout.dsc_input_bpc = 8;
+ break;
+ case COLOR_DEPTH_101010:
+ pipes[pipe_cnt].dout.dsc_input_bpc = 10;
+ break;
+ case COLOR_DEPTH_121212:
+ pipes[pipe_cnt].dout.dsc_input_bpc = 12;
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+ }
+
+ pipe_cnt++;
+ }
+
+ if (pipe_cnt)
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes =
+ (max_usable_det / DCN3_16_CRB_SEGMENT_SIZE_KB / pipe_cnt) * DCN3_16_CRB_SEGMENT_SIZE_KB;
+ if (context->bw_ctx.dml.ip.det_buffer_size_kbytes > DCN3_16_MAX_DET_SIZE)
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes = DCN3_16_MAX_DET_SIZE;
+ ASSERT(context->bw_ctx.dml.ip.det_buffer_size_kbytes >= DCN3_16_DEFAULT_DET_SIZE);
+ dc->config.enable_4to1MPC = false;
+ if (pipe_cnt == 1 && pipe->plane_state && !dc->debug.disable_z9_mpc) {
+ if (is_dual_plane(pipe->plane_state->format)
+ && pipe->plane_state->src_rect.width <= 1920 && pipe->plane_state->src_rect.height <= 1080) {
+ dc->config.enable_4to1MPC = true;
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes =
+ (max_usable_det / DCN3_16_CRB_SEGMENT_SIZE_KB / 4) * DCN3_16_CRB_SEGMENT_SIZE_KB;
+ } else if (!is_dual_plane(pipe->plane_state->format)) {
+ context->bw_ctx.dml.ip.det_buffer_size_kbytes = 192;
+ pipes[0].pipe.src.unbounded_req_mode = true;
+ }
+ }
+
+ return pipe_cnt;
+}
+
+static struct dc_cap_funcs cap_funcs = {
+ .get_dcc_compression_cap = dcn20_get_dcc_compression_cap
+};
+
+static struct resource_funcs dcn316_res_pool_funcs = {
+ .destroy = dcn316_destroy_resource_pool,
+ .link_enc_create = dcn31_link_encoder_create,
+ .link_enc_create_minimal = dcn31_link_enc_create_minimal,
+ .link_encs_assign = link_enc_cfg_link_encs_assign,
+ .link_enc_unassign = link_enc_cfg_link_enc_unassign,
+ .panel_cntl_create = dcn31_panel_cntl_create,
+ .validate_bandwidth = dcn31_validate_bandwidth,
+ .calculate_wm_and_dlg = dcn31_calculate_wm_and_dlg,
+ .update_soc_for_wm_a = dcn31_update_soc_for_wm_a,
+ .populate_dml_pipes = dcn316_populate_dml_pipes_from_context,
+ .acquire_idle_pipe_for_layer = dcn20_acquire_idle_pipe_for_layer,
+ .add_stream_to_ctx = dcn30_add_stream_to_ctx,
+ .add_dsc_to_stream_resource = dcn20_add_dsc_to_stream_resource,
+ .remove_stream_from_ctx = dcn20_remove_stream_from_ctx,
+ .populate_dml_writeback_from_context = dcn31_populate_dml_writeback_from_context,
+ .set_mcif_arb_params = dcn31_set_mcif_arb_params,
+ .find_first_free_match_stream_enc_for_link = dcn10_find_first_free_match_stream_enc_for_link,
+ .acquire_post_bldn_3dlut = dcn30_acquire_post_bldn_3dlut,
+ .release_post_bldn_3dlut = dcn30_release_post_bldn_3dlut,
+ .update_bw_bounding_box = dcn316_update_bw_bounding_box,
+ .patch_unknown_plane_state = dcn20_patch_unknown_plane_state,
+};
+
+static bool dcn316_resource_construct(
+ uint8_t num_virtual_links,
+ struct dc *dc,
+ struct dcn316_resource_pool *pool)
+{
+ int i;
+ struct dc_context *ctx = dc->ctx;
+ struct irq_service_init_data init_data;
+
+ ctx->dc_bios->regs = &bios_regs;
+
+ pool->base.res_cap = &res_cap_dcn31;
+
+ pool->base.funcs = &dcn316_res_pool_funcs;
+
+ /*************************************************
+ * Resource + asic cap harcoding *
+ *************************************************/
+ pool->base.underlay_pipe_index = NO_UNDERLAY_PIPE;
+ pool->base.pipe_count = pool->base.res_cap->num_timing_generator;
+ pool->base.mpcc_count = pool->base.res_cap->num_timing_generator;
+ dc->caps.max_downscale_ratio = 600;
+ dc->caps.i2c_speed_in_khz = 100;
+ dc->caps.i2c_speed_in_khz_hdcp = 100;
+ dc->caps.max_cursor_size = 256;
+ dc->caps.min_horizontal_blanking_period = 80;
+ dc->caps.dmdata_alloc_size = 2048;
+ dc->caps.max_slave_planes = 1;
+ dc->caps.max_slave_yuv_planes = 1;
+ dc->caps.max_slave_rgb_planes = 1;
+ dc->caps.post_blend_color_processing = true;
+ dc->caps.force_dp_tps4_for_cp2520 = true;
+ dc->caps.dp_hpo = true;
+ dc->caps.edp_dsc_support = true;
+ dc->caps.extended_aux_timeout_support = true;
+ dc->caps.dmcub_support = true;
+ dc->caps.is_apu = true;
+
+ /* Color pipeline capabilities */
+ dc->caps.color.dpp.dcn_arch = 1;
+ dc->caps.color.dpp.input_lut_shared = 0;
+ dc->caps.color.dpp.icsc = 1;
+ dc->caps.color.dpp.dgam_ram = 0; // must use gamma_corr
+ dc->caps.color.dpp.dgam_rom_caps.srgb = 1;
+ dc->caps.color.dpp.dgam_rom_caps.bt2020 = 1;
+ dc->caps.color.dpp.dgam_rom_caps.gamma2_2 = 1;
+ dc->caps.color.dpp.dgam_rom_caps.pq = 1;
+ dc->caps.color.dpp.dgam_rom_caps.hlg = 1;
+ dc->caps.color.dpp.post_csc = 1;
+ dc->caps.color.dpp.gamma_corr = 1;
+ dc->caps.color.dpp.dgam_rom_for_yuv = 0;
+
+ dc->caps.color.dpp.hw_3d_lut = 1;
+ dc->caps.color.dpp.ogam_ram = 1;
+ // no OGAM ROM on DCN301
+ dc->caps.color.dpp.ogam_rom_caps.srgb = 0;
+ dc->caps.color.dpp.ogam_rom_caps.bt2020 = 0;
+ dc->caps.color.dpp.ogam_rom_caps.gamma2_2 = 0;
+ dc->caps.color.dpp.ogam_rom_caps.pq = 0;
+ dc->caps.color.dpp.ogam_rom_caps.hlg = 0;
+ dc->caps.color.dpp.ocsc = 0;
+
+ dc->caps.color.mpc.gamut_remap = 1;
+ dc->caps.color.mpc.num_3dluts = pool->base.res_cap->num_mpc_3dlut; //2
+ dc->caps.color.mpc.ogam_ram = 1;
+ dc->caps.color.mpc.ogam_rom_caps.srgb = 0;
+ dc->caps.color.mpc.ogam_rom_caps.bt2020 = 0;
+ dc->caps.color.mpc.ogam_rom_caps.gamma2_2 = 0;
+ dc->caps.color.mpc.ogam_rom_caps.pq = 0;
+ dc->caps.color.mpc.ogam_rom_caps.hlg = 0;
+ dc->caps.color.mpc.ocsc = 1;
+
+ /* read VBIOS LTTPR caps */
+ {
+ if (ctx->dc_bios->funcs->get_lttpr_caps) {
+ enum bp_result bp_query_result;
+ uint8_t is_vbios_lttpr_enable = 0;
+
+ bp_query_result = ctx->dc_bios->funcs->get_lttpr_caps(ctx->dc_bios, &is_vbios_lttpr_enable);
+ dc->caps.vbios_lttpr_enable = (bp_query_result == BP_RESULT_OK) && !!is_vbios_lttpr_enable;
+ }
+
+ /* interop bit is implicit */
+ {
+ dc->caps.vbios_lttpr_aware = true;
+ }
+ }
+
+ if (dc->ctx->dce_environment == DCE_ENV_PRODUCTION_DRV)
+ dc->debug = debug_defaults_drv;
+ else if (dc->ctx->dce_environment == DCE_ENV_FPGA_MAXIMUS) {
+ dc->debug = debug_defaults_diags;
+ } else
+ dc->debug = debug_defaults_diags;
+ // Init the vm_helper
+ if (dc->vm_helper)
+ vm_helper_init(dc->vm_helper, 16);
+
+ /*************************************************
+ * Create resources *
+ *************************************************/
+
+ /* Clock Sources for Pixel Clock*/
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL0] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL0,
+ &clk_src_regs[0], false);
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL1] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL1,
+ &clk_src_regs[1], false);
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL2] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL2,
+ &clk_src_regs[2], false);
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL3] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL3,
+ &clk_src_regs[3], false);
+ pool->base.clock_sources[DCN31_CLK_SRC_PLL4] =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_COMBO_PHY_PLL4,
+ &clk_src_regs[4], false);
+
+ pool->base.clk_src_count = DCN30_CLK_SRC_TOTAL;
+
+ /* todo: not reuse phy_pll registers */
+ pool->base.dp_clock_source =
+ dcn31_clock_source_create(ctx, ctx->dc_bios,
+ CLOCK_SOURCE_ID_DP_DTO,
+ &clk_src_regs[0], true);
+
+ for (i = 0; i < pool->base.clk_src_count; i++) {
+ if (pool->base.clock_sources[i] == NULL) {
+ dm_error("DC: failed to create clock sources!\n");
+ BREAK_TO_DEBUGGER();
+ goto create_fail;
+ }
+ }
+
+ /* TODO: DCCG */
+ pool->base.dccg = dccg31_create(ctx, &dccg_regs, &dccg_shift, &dccg_mask);
+ if (pool->base.dccg == NULL) {
+ dm_error("DC: failed to create dccg!\n");
+ BREAK_TO_DEBUGGER();
+ goto create_fail;
+ }
+
+ /* TODO: IRQ */
+ init_data.ctx = dc->ctx;
+ pool->base.irqs = dal_irq_service_dcn31_create(&init_data);
+ if (!pool->base.irqs)
+ goto create_fail;
+
+ /* HUBBUB */
+ pool->base.hubbub = dcn31_hubbub_create(ctx);
+ if (pool->base.hubbub == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create hubbub!\n");
+ goto create_fail;
+ }
+
+ /* HUBPs, DPPs, OPPs and TGs */
+ for (i = 0; i < pool->base.pipe_count; i++) {
+ pool->base.hubps[i] = dcn31_hubp_create(ctx, i);
+ if (pool->base.hubps[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC: failed to create hubps!\n");
+ goto create_fail;
+ }
+
+ pool->base.dpps[i] = dcn31_dpp_create(ctx, i);
+ if (pool->base.dpps[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC: failed to create dpps!\n");
+ goto create_fail;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_opp; i++) {
+ pool->base.opps[i] = dcn31_opp_create(ctx, i);
+ if (pool->base.opps[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC: failed to create output pixel processor!\n");
+ goto create_fail;
+ }
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+ pool->base.timing_generators[i] = dcn31_timing_generator_create(
+ ctx, i);
+ if (pool->base.timing_generators[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create tg!\n");
+ goto create_fail;
+ }
+ }
+ pool->base.timing_generator_count = i;
+
+ /* PSR */
+ pool->base.psr = dmub_psr_create(ctx);
+ if (pool->base.psr == NULL) {
+ dm_error("DC: failed to create psr obj!\n");
+ BREAK_TO_DEBUGGER();
+ goto create_fail;
+ }
+
+ /* ABM */
+ for (i = 0; i < pool->base.res_cap->num_timing_generator; i++) {
+ pool->base.multiple_abms[i] = dmub_abm_create(ctx,
+ &abm_regs[i],
+ &abm_shift,
+ &abm_mask);
+ if (pool->base.multiple_abms[i] == NULL) {
+ dm_error("DC: failed to create abm for pipe %d!\n", i);
+ BREAK_TO_DEBUGGER();
+ goto create_fail;
+ }
+ }
+
+ /* MPC and DSC */
+ pool->base.mpc = dcn31_mpc_create(ctx, pool->base.mpcc_count, pool->base.res_cap->num_mpc_3dlut);
+ if (pool->base.mpc == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create mpc!\n");
+ goto create_fail;
+ }
+
+ for (i = 0; i < pool->base.res_cap->num_dsc; i++) {
+ pool->base.dscs[i] = dcn31_dsc_create(ctx, i);
+ if (pool->base.dscs[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create display stream compressor %d!\n", i);
+ goto create_fail;
+ }
+ }
+
+ /* DWB and MMHUBBUB */
+ if (!dcn31_dwbc_create(ctx, &pool->base)) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create dwbc!\n");
+ goto create_fail;
+ }
+
+ if (!dcn31_mmhubbub_create(ctx, &pool->base)) {
+ BREAK_TO_DEBUGGER();
+ dm_error("DC: failed to create mcif_wb!\n");
+ goto create_fail;
+ }
+
+ /* AUX and I2C */
+ for (i = 0; i < pool->base.res_cap->num_ddc; i++) {
+ pool->base.engines[i] = dcn31_aux_engine_create(ctx, i);
+ if (pool->base.engines[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC:failed to create aux engine!!\n");
+ goto create_fail;
+ }
+ pool->base.hw_i2cs[i] = dcn31_i2c_hw_create(ctx, i);
+ if (pool->base.hw_i2cs[i] == NULL) {
+ BREAK_TO_DEBUGGER();
+ dm_error(
+ "DC:failed to create hw i2c!!\n");
+ goto create_fail;
+ }
+ pool->base.sw_i2cs[i] = NULL;
+ }
+
+ /* Audio, Stream Encoders including HPO and virtual, MPC 3D LUTs */
+ if (!resource_construct(num_virtual_links, dc, &pool->base,
+ (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment) ?
+ &res_create_funcs : &res_create_maximus_funcs)))
+ goto create_fail;
+
+ /* HW Sequencer and Plane caps */
+ dcn31_hw_sequencer_construct(dc);
+
+ dc->caps.max_planes = pool->base.pipe_count;
+
+ for (i = 0; i < dc->caps.max_planes; ++i)
+ dc->caps.planes[i] = plane_cap;
+
+ dc->cap_funcs = cap_funcs;
+
+ dc->dcn_ip->max_num_dpp = dcn3_16_ip.max_num_dpp;
+
+ return true;
+
+create_fail:
+
+ dcn316_resource_destruct(pool);
+
+ return false;
+}
+
+struct resource_pool *dcn316_create_resource_pool(
+ const struct dc_init_data *init_data,
+ struct dc *dc)
+{
+ struct dcn316_resource_pool *pool =
+ kzalloc(sizeof(struct dcn316_resource_pool), GFP_KERNEL);
+
+ if (!pool)
+ return NULL;
+
+ if (dcn316_resource_construct(init_data->num_virtual_links, dc, pool))
+ return &pool->base;
+
+ BREAK_TO_DEBUGGER();
+ kfree(pool);
+ return NULL;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h
new file mode 100644
index 000000000000..0dc5a6c13ae7
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dcn316/dcn316_resource.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef _DCN316_RESOURCE_H_
+#define _DCN316_RESOURCE_H_
+
+#include "core_types.h"
+
+#define TO_DCN316_RES_POOL(pool)\
+ container_of(pool, struct dcn316_resource_pool, base)
+
+extern struct _vcs_dpi_ip_params_st dcn3_16_ip;
+extern struct _vcs_dpi_ip_params_st dcn3_16_soc;
+
+struct dcn316_resource_pool {
+ struct resource_pool base;
+};
+
+struct resource_pool *dcn316_create_resource_pool(
+ const struct dc_init_data *init_data,
+ struct dc *dc);
+
+#endif /* _DCN316_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/dm_helpers.h b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
index 7f94e3f70d7f..fb6a2d7b6470 100644
--- a/drivers/gpu/drm/amd/display/dc/dm_helpers.h
+++ b/drivers/gpu/drm/amd/display/dc/dm_helpers.h
@@ -113,7 +113,7 @@ bool dm_helpers_dp_mst_start_top_mgr(
const struct dc_link *link,
bool boot);
-void dm_helpers_dp_mst_stop_top_mgr(
+bool dm_helpers_dp_mst_stop_top_mgr(
struct dc_context *ctx,
struct dc_link *link);
/**
@@ -160,9 +160,7 @@ void dm_set_dcn_clocks(
struct dc_context *ctx,
struct dc_clocks *clks);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
void dm_helpers_enable_periodic_detection(struct dc_context *ctx, bool enable);
-#endif
void dm_set_phyd32clk(struct dc_context *ctx, int freq_khz);
@@ -170,9 +168,9 @@ bool dm_helpers_dmub_outbox_interrupt_control(struct dc_context *ctx, bool enabl
void dm_helpers_smu_timeout(struct dc_context *ctx, unsigned int msg_id, unsigned int param, unsigned int timeout_us);
-// 0x1 = Result_OK, 0xFE = Result_UnkmownCmd
+// 0x1 = Result_OK, 0xFE = Result_UnkmownCmd, 0x0 = Status_Busy
#define IS_SMU_TIMEOUT(result) \
- (!(result == 0x1 || result == 0xFE))
+ (result == 0x0)
int dm_helper_dmub_aux_transfer_sync(
struct dc_context *ctx,
@@ -184,4 +182,7 @@ int dm_helpers_dmub_set_config_sync(struct dc_context *ctx,
const struct dc_link *link,
struct set_config_cmd_payload *payload,
enum set_config_status *operation_result);
+
+enum dc_edid_status dm_helpers_get_sbios_edid(struct dc_link *link, struct dc_edid *edid);
+
#endif /* __DM_HELPERS__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml/Makefile b/drivers/gpu/drm/amd/display/dc/dml/Makefile
index eee6672bd32d..a64b88ca01a9 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/dml/Makefile
@@ -58,6 +58,7 @@ CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags)
ifdef CONFIG_DRM_AMD_DC_DCN
CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn10/dcn10_fpu.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/dcn20_fpu.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_ccflags)
@@ -70,9 +71,16 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_mode_vba_30.o := $(dml_ccflags) $(fram
CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/display_rq_dlg_calc_30.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_mode_vba_31.o := $(dml_ccflags) $(frame_warn_flag)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/display_rq_dlg_calc_31.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn30/dcn30_fpu.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn31/dcn31_fpu.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dcn301/dcn301_fpu.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn302/dcn302_fpu.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/dcn303/dcn303_fpu.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/dsc/rc_calc_fpu.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/display_mode_lib.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calcs.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_auto.o := $(dml_ccflags)
+CFLAGS_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_math.o := $(dml_ccflags) -Wno-tautological-compare
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_mode_vba.o := $(dml_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn2x/dcn2x.o := $(dml_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dcn20/display_mode_vba_20.o := $(dml_rcflags)
@@ -93,18 +101,27 @@ CFLAGS_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_ccflags)
CFLAGS_$(AMDDALPATH)/dc/dml/display_rq_dlg_helpers.o := $(dml_ccflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/dml1_display_rq_dlg_calc.o := $(dml_rcflags)
CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/display_rq_dlg_helpers.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/calcs/dcn_calcs.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_auto.o := $(dml_rcflags)
+CFLAGS_REMOVE_$(AMDDALPATH)/dc/dml/calcs/dcn_calc_math.o := $(dml_rcflags)
-DML = display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o \
+DML = calcs/dce_calcs.o calcs/custom_float.o calcs/bw_fixed.o
ifdef CONFIG_DRM_AMD_DC_DCN
+DML += display_mode_lib.o display_rq_dlg_helpers.o dml1_display_rq_dlg_calc.o
+DML += dcn10/dcn10_fpu.o
DML += dcn20/dcn20_fpu.o
DML += display_mode_vba.o dcn20/display_rq_dlg_calc_20.o dcn20/display_mode_vba_20.o
DML += dcn20/display_rq_dlg_calc_20v2.o dcn20/display_mode_vba_20v2.o
DML += dcn21/display_rq_dlg_calc_21.o dcn21/display_mode_vba_21.o
-DML += dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_30.o
+DML += dcn30/dcn30_fpu.o dcn30/display_mode_vba_30.o dcn30/display_rq_dlg_calc_30.o
DML += dcn31/display_mode_vba_31.o dcn31/display_rq_dlg_calc_31.o
+DML += dcn31/dcn31_fpu.o
DML += dcn301/dcn301_fpu.o
+DML += dcn302/dcn302_fpu.o
+DML += dcn303/dcn303_fpu.o
DML += dsc/rc_calc_fpu.o
+DML += calcs/dcn_calcs.o calcs/dcn_calc_math.o calcs/dcn_calc_auto.o
endif
AMD_DAL_DML = $(addprefix $(AMDDALPATH)/dc/dml/,$(DML))
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/bw_fixed.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/bw_fixed.c
index 6ca288fb5fb9..6ca288fb5fb9 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/bw_fixed.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/bw_fixed.c
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/calcs_logger.h b/drivers/gpu/drm/amd/display/dc/dml/calcs/calcs_logger.h
index 62435bfc274d..62435bfc274d 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/calcs_logger.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/calcs_logger.h
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/custom_float.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/custom_float.c
index 31d167bc548f..31d167bc548f 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/custom_float.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/custom_float.c
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c
index e6ef36de0825..0100a6053ab6 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dce_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c
@@ -3411,35 +3411,33 @@ bool bw_calcs(struct dc_context *ctx,
calcs_output->stutter_exit_wm_ns[5].c_mark =
bw_fixed_to_int(bw_mul(data->
stutter_exit_watermark[9], bw_int_to_fixed(1000)));
-
- calcs_output->stutter_entry_wm_ns[0].c_mark =
- bw_fixed_to_int(bw_mul(data->
- stutter_entry_watermark[4], bw_int_to_fixed(1000)));
- calcs_output->stutter_entry_wm_ns[1].c_mark =
- bw_fixed_to_int(bw_mul(data->
- stutter_entry_watermark[5], bw_int_to_fixed(1000)));
- calcs_output->stutter_entry_wm_ns[2].c_mark =
- bw_fixed_to_int(bw_mul(data->
- stutter_entry_watermark[6], bw_int_to_fixed(1000)));
- if (ctx->dc->caps.max_slave_planes) {
- calcs_output->stutter_entry_wm_ns[3].c_mark =
+ calcs_output->stutter_entry_wm_ns[0].c_mark =
bw_fixed_to_int(bw_mul(data->
- stutter_entry_watermark[0], bw_int_to_fixed(1000)));
- calcs_output->stutter_entry_wm_ns[4].c_mark =
+ stutter_entry_watermark[4], bw_int_to_fixed(1000)));
+ calcs_output->stutter_entry_wm_ns[1].c_mark =
bw_fixed_to_int(bw_mul(data->
- stutter_entry_watermark[1], bw_int_to_fixed(1000)));
- } else {
- calcs_output->stutter_entry_wm_ns[3].c_mark =
+ stutter_entry_watermark[5], bw_int_to_fixed(1000)));
+ calcs_output->stutter_entry_wm_ns[2].c_mark =
bw_fixed_to_int(bw_mul(data->
- stutter_entry_watermark[7], bw_int_to_fixed(1000)));
- calcs_output->stutter_entry_wm_ns[4].c_mark =
+ stutter_entry_watermark[6], bw_int_to_fixed(1000)));
+ if (ctx->dc->caps.max_slave_planes) {
+ calcs_output->stutter_entry_wm_ns[3].c_mark =
+ bw_fixed_to_int(bw_mul(data->stutter_entry_watermark[0],
+ bw_int_to_fixed(1000)));
+ calcs_output->stutter_entry_wm_ns[4].c_mark =
+ bw_fixed_to_int(bw_mul(data->stutter_entry_watermark[1],
+ bw_int_to_fixed(1000)));
+ } else {
+ calcs_output->stutter_entry_wm_ns[3].c_mark =
+ bw_fixed_to_int(bw_mul(data->stutter_entry_watermark[7],
+ bw_int_to_fixed(1000)));
+ calcs_output->stutter_entry_wm_ns[4].c_mark =
+ bw_fixed_to_int(bw_mul(data->stutter_entry_watermark[8],
+ bw_int_to_fixed(1000)));
+ }
+ calcs_output->stutter_entry_wm_ns[5].c_mark =
bw_fixed_to_int(bw_mul(data->
- stutter_entry_watermark[8], bw_int_to_fixed(1000)));
- }
- calcs_output->stutter_entry_wm_ns[5].c_mark =
- bw_fixed_to_int(bw_mul(data->
- stutter_entry_watermark[9], bw_int_to_fixed(1000)));
-
+ stutter_entry_watermark[9], bw_int_to_fixed(1000)));
calcs_output->urgent_wm_ns[0].c_mark =
bw_fixed_to_int(bw_mul(data->
urgent_watermark[4], bw_int_to_fixed(1000)));
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_auto.c
index 41284e263325..41284e263325 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_auto.c
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.h b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_auto.h
index ce35de79a6c7..ce35de79a6c7 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_auto.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_auto.h
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_math.c
index 07d18e78de49..07d18e78de49 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calc_math.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calc_math.c
diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c
index e447c74be713..db3b16b77034 100644
--- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c
@@ -639,7 +639,6 @@ static bool dcn_bw_apply_registry_override(struct dc *dc)
{
bool updated = false;
- DC_FP_START();
if ((int)(dc->dcn_soc->sr_exit_time * 1000) != dc->debug.sr_exit_time_ns
&& dc->debug.sr_exit_time_ns) {
updated = true;
@@ -675,7 +674,6 @@ static bool dcn_bw_apply_registry_override(struct dc *dc)
dc->dcn_soc->dram_clock_change_latency =
dc->debug.dram_clock_change_latency_ns / 1000.0;
}
- DC_FP_END();
return updated;
}
@@ -764,7 +762,7 @@ static unsigned int get_highest_allowed_voltage_level(uint32_t chip_family,
return 4;
}
-bool dcn10_validate_bandwidth(
+bool dcn_validate_bandwidth(
struct dc *dc,
struct dc_state *context,
bool fast_validate)
@@ -790,7 +788,6 @@ bool dcn10_validate_bandwidth(
dcn_bw_sync_calcs_and_dml(dc);
memset(v, 0, sizeof(*v));
- DC_FP_START();
v->sr_exit_time = dc->dcn_soc->sr_exit_time;
v->sr_enter_plus_exit_time = dc->dcn_soc->sr_enter_plus_exit_time;
@@ -1323,8 +1320,6 @@ bool dcn10_validate_bandwidth(
bw_limit = dc->dcn_soc->percent_disp_bw_limit * v->fabric_and_dram_bandwidth_vmax0p9;
bw_limit_pass = (v->total_data_read_bandwidth / 1000.0) < bw_limit;
- DC_FP_END();
-
PERFORMANCE_TRACE_END();
BW_VAL_TRACE_FINISH();
@@ -1495,8 +1490,6 @@ void dcn_bw_update_from_pplib(struct dc *dc)
res = dm_pp_get_clock_levels_by_type_with_voltage(
ctx, DM_PP_CLOCK_TYPE_FCLK, &fclks);
- DC_FP_START();
-
if (res)
res = verify_clock_values(&fclks);
@@ -1526,13 +1519,9 @@ void dcn_bw_update_from_pplib(struct dc *dc)
} else
BREAK_TO_DEBUGGER();
- DC_FP_END();
-
res = dm_pp_get_clock_levels_by_type_with_voltage(
ctx, DM_PP_CLOCK_TYPE_DCFCLK, &dcfclks);
- DC_FP_START();
-
if (res)
res = verify_clock_values(&dcfclks);
@@ -1543,8 +1532,6 @@ void dcn_bw_update_from_pplib(struct dc *dc)
dc->dcn_soc->dcfclkv_max0p9 = dcfclks.data[dcfclks.num_levels - 1].clocks_in_khz / 1000.0;
} else
BREAK_TO_DEBUGGER();
-
- DC_FP_END();
}
void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc)
@@ -1559,11 +1546,9 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc)
if (!pp || !pp->set_wm_ranges)
return;
- DC_FP_START();
min_fclk_khz = dc->dcn_soc->fabric_and_dram_bandwidth_vmin0p65 * 1000000 / 32;
min_dcfclk_khz = dc->dcn_soc->dcfclkv_min0p65 * 1000;
socclk_khz = dc->dcn_soc->socclk * 1000;
- DC_FP_END();
/* Now notify PPLib/SMU about which Watermarks sets they should select
* depending on DPM state they are in. And update BW MGR GFX Engine and
@@ -1614,7 +1599,6 @@ void dcn_bw_notify_pplib_of_wm_ranges(struct dc *dc)
void dcn_bw_sync_calcs_and_dml(struct dc *dc)
{
- DC_FP_START();
DC_LOG_BANDWIDTH_CALCS("sr_exit_time: %f ns\n"
"sr_enter_plus_exit_time: %f ns\n"
"urgent_latency: %f ns\n"
@@ -1803,5 +1787,4 @@ void dcn_bw_sync_calcs_and_dml(struct dc *dc)
dc->dml.ip.bug_forcing_LC_req_same_size_fixed =
dc->dcn_ip->bug_forcing_luma_and_chroma_request_to_same_size_fixed == dcn_bw_yes;
dc->dml.ip.dcfclk_cstate_latency = dc->dcn_ip->dcfclk_cstate_latency;
- DC_FP_END();
}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c
new file mode 100644
index 000000000000..99644d896222
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: MIT
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "dcn10/dcn10_resource.h"
+
+#include "dcn10_fpu.h"
+
+/**
+ * DOC: DCN10 FPU manipulation Overview
+ *
+ * The DCN architecture relies on FPU operations, which require special
+ * compilation flags and the use of kernel_fpu_begin/end functions; ideally, we
+ * want to avoid spreading FPU access across multiple files. With this idea in
+ * mind, this file aims to centralize DCN10 functions that require FPU access
+ * in a single place. Code in this file follows the following code pattern:
+ *
+ * 1. Functions that use FPU operations should be isolated in static functions.
+ * 2. The FPU functions should have the noinline attribute to ensure anything
+ * that deals with FP register is contained within this call.
+ * 3. All function that needs to be accessed outside this file requires a
+ * public interface that not uses any FPU reference.
+ * 4. Developers **must not** use DC_FP_START/END in this file, but they need
+ * to ensure that the caller invokes it before access any function available
+ * in this file. For this reason, public functions in this file must invoke
+ * dc_assert_fp_enabled();
+ *
+ * Let's expand a little bit more the idea in the code pattern. To fully
+ * isolate FPU operations in a single place, we must avoid situations where
+ * compilers spill FP values to registers due to FP enable in a specific C
+ * file. Note that even if we isolate all FPU functions in a single file and
+ * call its interface from other files, the compiler might enable the use of
+ * FPU before we call DC_FP_START. Nevertheless, it is the programmer's
+ * responsibility to invoke DC_FP_START/END in the correct place. To highlight
+ * situations where developers forgot to use the FP protection before calling
+ * the DC FPU interface functions, we introduce a helper that checks if the
+ * function is invoked under FP protection. If not, it will trigger a kernel
+ * warning.
+ */
+
+struct _vcs_dpi_ip_params_st dcn1_0_ip = {
+ .rob_buffer_size_kbytes = 64,
+ .det_buffer_size_kbytes = 164,
+ .dpte_buffer_size_in_pte_reqs_luma = 42,
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .pte_enable = 1,
+ .pte_chunk_size_kbytes = 2,
+ .meta_chunk_size_kbytes = 2,
+ .writeback_chunk_size_kbytes = 2,
+ .line_buffer_size_bits = 589824,
+ .max_line_buffer_lines = 12,
+ .IsLineBufferBppFixed = 0,
+ .LineBufferFixedBpp = -1,
+ .writeback_luma_buffer_size_kbytes = 12,
+ .writeback_chroma_buffer_size_kbytes = 8,
+ .max_num_dpp = 4,
+ .max_num_wb = 2,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 4,
+ .max_vscl_ratio = 4,
+ .hscl_mults = 4,
+ .vscl_mults = 4,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dispclk_ramp_margin_percent = 1,
+ .underscan_factor = 1.10,
+ .min_vblank_lines = 14,
+ .dppclk_delay_subtotal = 90,
+ .dispclk_delay_subtotal = 42,
+ .dcfclk_cstate_latency = 10,
+ .max_inter_dcn_tile_repeaters = 8,
+ .can_vstartup_lines_exceed_vsync_plus_back_porch_lines_minus_one = 0,
+ .bug_forcing_LC_req_same_size_fixed = 0,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn1_0_soc = {
+ .sr_exit_time_us = 9.0,
+ .sr_enter_plus_exit_time_us = 11.0,
+ .urgent_latency_us = 4.0,
+ .writeback_latency_us = 12.0,
+ .ideal_dram_bw_after_urgent_percent = 80.0,
+ .max_request_size_bytes = 256,
+ .downspread_percent = 0.5,
+ .dram_page_open_time_ns = 50.0,
+ .dram_rw_turnaround_time_ns = 17.5,
+ .dram_return_buffer_per_channel_bytes = 8192,
+ .round_trip_ping_latency_dcfclk_cycles = 128,
+ .urgent_out_of_order_return_per_channel_bytes = 256,
+ .channel_interleave_bytes = 256,
+ .num_banks = 8,
+ .num_chans = 2,
+ .vmm_page_size_bytes = 4096,
+ .dram_clock_change_latency_us = 17.0,
+ .writeback_dram_clock_change_latency_us = 23.0,
+ .return_bus_width_bytes = 64,
+};
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h
new file mode 100644
index 000000000000..e74ed4b4ce5b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn10/dcn10_fpu.h
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN10_FPU_H__
+#define __DCN10_FPU_H__
+
+#endif /* __DCN20_FPU_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
index d590dc917363..f79dd40f8d81 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
@@ -25,9 +25,23 @@
*/
#include "resource.h"
+#include "clk_mgr.h"
+#include "dc_link_dp.h"
+#include "dchubbub.h"
+#include "dcn20/dcn20_resource.h"
+#include "dcn21/dcn21_resource.h"
#include "dcn20_fpu.h"
+#define DC_LOGGER_INIT(logger)
+
+#ifndef MAX
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+#endif
+#ifndef MIN
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#endif
+
/**
* DOC: DCN2x FPU manipulation Overview
*
@@ -61,6 +75,581 @@
* warning.
*/
+struct _vcs_dpi_ip_params_st dcn2_0_ip = {
+ .odm_capable = 1,
+ .gpuvm_enable = 0,
+ .hostvm_enable = 0,
+ .gpuvm_max_page_table_levels = 4,
+ .hostvm_max_page_table_levels = 4,
+ .hostvm_cached_page_table_levels = 0,
+ .pte_group_size_bytes = 2048,
+ .num_dsc = 6,
+ .rob_buffer_size_kbytes = 168,
+ .det_buffer_size_kbytes = 164,
+ .dpte_buffer_size_in_pte_reqs_luma = 84,
+ .pde_proc_buffer_size_64k_reqs = 48,
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .pte_chunk_size_kbytes = 2,
+ .meta_chunk_size_kbytes = 2,
+ .writeback_chunk_size_kbytes = 2,
+ .line_buffer_size_bits = 789504,
+ .is_line_buffer_bpp_fixed = 0,
+ .line_buffer_fixed_bpp = 0,
+ .dcc_supported = true,
+ .max_line_buffer_lines = 12,
+ .writeback_luma_buffer_size_kbytes = 12,
+ .writeback_chroma_buffer_size_kbytes = 8,
+ .writeback_chroma_line_buffer_width_pixels = 4,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 12,
+ .writeback_max_vscl_taps = 12,
+ .writeback_line_buffer_luma_buffer_size = 0,
+ .writeback_line_buffer_chroma_buffer_size = 14643,
+ .cursor_buffer_size = 8,
+ .cursor_chunk_size = 2,
+ .max_num_otg = 6,
+ .max_num_dpp = 6,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 8,
+ .max_vscl_ratio = 8,
+ .hscl_mults = 4,
+ .vscl_mults = 4,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dispclk_ramp_margin_percent = 1,
+ .underscan_factor = 1.10,
+ .min_vblank_lines = 32, //
+ .dppclk_delay_subtotal = 77, //
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_cnvc_formatter = 8,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 87, //
+ .dcfclk_cstate_latency = 10, // SRExitTime
+ .max_inter_dcn_tile_repeaters = 8,
+ .xfc_supported = true,
+ .xfc_fill_bw_overhead_percent = 10.0,
+ .xfc_fill_constant_bytes = 0,
+ .number_of_cursors = 1,
+};
+
+struct _vcs_dpi_ip_params_st dcn2_0_nv14_ip = {
+ .odm_capable = 1,
+ .gpuvm_enable = 0,
+ .hostvm_enable = 0,
+ .gpuvm_max_page_table_levels = 4,
+ .hostvm_max_page_table_levels = 4,
+ .hostvm_cached_page_table_levels = 0,
+ .num_dsc = 5,
+ .rob_buffer_size_kbytes = 168,
+ .det_buffer_size_kbytes = 164,
+ .dpte_buffer_size_in_pte_reqs_luma = 84,
+ .dpte_buffer_size_in_pte_reqs_chroma = 42,//todo
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .pte_enable = 1,
+ .max_page_table_levels = 4,
+ .pte_chunk_size_kbytes = 2,
+ .meta_chunk_size_kbytes = 2,
+ .writeback_chunk_size_kbytes = 2,
+ .line_buffer_size_bits = 789504,
+ .is_line_buffer_bpp_fixed = 0,
+ .line_buffer_fixed_bpp = 0,
+ .dcc_supported = true,
+ .max_line_buffer_lines = 12,
+ .writeback_luma_buffer_size_kbytes = 12,
+ .writeback_chroma_buffer_size_kbytes = 8,
+ .writeback_chroma_line_buffer_width_pixels = 4,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 12,
+ .writeback_max_vscl_taps = 12,
+ .writeback_line_buffer_luma_buffer_size = 0,
+ .writeback_line_buffer_chroma_buffer_size = 14643,
+ .cursor_buffer_size = 8,
+ .cursor_chunk_size = 2,
+ .max_num_otg = 5,
+ .max_num_dpp = 5,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 8,
+ .max_vscl_ratio = 8,
+ .hscl_mults = 4,
+ .vscl_mults = 4,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dispclk_ramp_margin_percent = 1,
+ .underscan_factor = 1.10,
+ .min_vblank_lines = 32, //
+ .dppclk_delay_subtotal = 77, //
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_cnvc_formatter = 8,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 87, //
+ .dcfclk_cstate_latency = 10, // SRExitTime
+ .max_inter_dcn_tile_repeaters = 8,
+ .xfc_supported = true,
+ .xfc_fill_bw_overhead_percent = 10.0,
+ .xfc_fill_constant_bytes = 0,
+ .ptoi_supported = 0,
+ .number_of_cursors = 1,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn2_0_soc = {
+ /* Defaults that get patched on driver load from firmware. */
+ .clock_limits = {
+ {
+ .state = 0,
+ .dcfclk_mhz = 560.0,
+ .fabricclk_mhz = 560.0,
+ .dispclk_mhz = 513.0,
+ .dppclk_mhz = 513.0,
+ .phyclk_mhz = 540.0,
+ .socclk_mhz = 560.0,
+ .dscclk_mhz = 171.0,
+ .dram_speed_mts = 8960.0,
+ },
+ {
+ .state = 1,
+ .dcfclk_mhz = 694.0,
+ .fabricclk_mhz = 694.0,
+ .dispclk_mhz = 642.0,
+ .dppclk_mhz = 642.0,
+ .phyclk_mhz = 600.0,
+ .socclk_mhz = 694.0,
+ .dscclk_mhz = 214.0,
+ .dram_speed_mts = 11104.0,
+ },
+ {
+ .state = 2,
+ .dcfclk_mhz = 875.0,
+ .fabricclk_mhz = 875.0,
+ .dispclk_mhz = 734.0,
+ .dppclk_mhz = 734.0,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 875.0,
+ .dscclk_mhz = 245.0,
+ .dram_speed_mts = 14000.0,
+ },
+ {
+ .state = 3,
+ .dcfclk_mhz = 1000.0,
+ .fabricclk_mhz = 1000.0,
+ .dispclk_mhz = 1100.0,
+ .dppclk_mhz = 1100.0,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 1000.0,
+ .dscclk_mhz = 367.0,
+ .dram_speed_mts = 16000.0,
+ },
+ {
+ .state = 4,
+ .dcfclk_mhz = 1200.0,
+ .fabricclk_mhz = 1200.0,
+ .dispclk_mhz = 1284.0,
+ .dppclk_mhz = 1284.0,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 1200.0,
+ .dscclk_mhz = 428.0,
+ .dram_speed_mts = 16000.0,
+ },
+ /*Extra state, no dispclk ramping*/
+ {
+ .state = 5,
+ .dcfclk_mhz = 1200.0,
+ .fabricclk_mhz = 1200.0,
+ .dispclk_mhz = 1284.0,
+ .dppclk_mhz = 1284.0,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 1200.0,
+ .dscclk_mhz = 428.0,
+ .dram_speed_mts = 16000.0,
+ },
+ },
+ .num_states = 5,
+ .sr_exit_time_us = 8.6,
+ .sr_enter_plus_exit_time_us = 10.9,
+ .urgent_latency_us = 4.0,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
+ .max_avg_sdp_bw_use_normal_percent = 40.0,
+ .max_avg_dram_bw_use_normal_percent = 40.0,
+ .writeback_latency_us = 12.0,
+ .ideal_dram_bw_after_urgent_percent = 40.0,
+ .max_request_size_bytes = 256,
+ .dram_channel_width_bytes = 2,
+ .fabric_datapath_to_dcn_data_return_bytes = 64,
+ .dcn_downspread_percent = 0.5,
+ .downspread_percent = 0.38,
+ .dram_page_open_time_ns = 50.0,
+ .dram_rw_turnaround_time_ns = 17.5,
+ .dram_return_buffer_per_channel_bytes = 8192,
+ .round_trip_ping_latency_dcfclk_cycles = 131,
+ .urgent_out_of_order_return_per_channel_bytes = 256,
+ .channel_interleave_bytes = 256,
+ .num_banks = 8,
+ .num_chans = 16,
+ .vmm_page_size_bytes = 4096,
+ .dram_clock_change_latency_us = 404.0,
+ .dummy_pstate_latency_us = 5.0,
+ .writeback_dram_clock_change_latency_us = 23.0,
+ .return_bus_width_bytes = 64,
+ .dispclk_dppclk_vco_speed_mhz = 3850,
+ .xfc_bus_transport_time_us = 20,
+ .xfc_xbuf_latency_tolerance_us = 4,
+ .use_urgent_burst_bw = 0
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv14_soc = {
+ .clock_limits = {
+ {
+ .state = 0,
+ .dcfclk_mhz = 560.0,
+ .fabricclk_mhz = 560.0,
+ .dispclk_mhz = 513.0,
+ .dppclk_mhz = 513.0,
+ .phyclk_mhz = 540.0,
+ .socclk_mhz = 560.0,
+ .dscclk_mhz = 171.0,
+ .dram_speed_mts = 8960.0,
+ },
+ {
+ .state = 1,
+ .dcfclk_mhz = 694.0,
+ .fabricclk_mhz = 694.0,
+ .dispclk_mhz = 642.0,
+ .dppclk_mhz = 642.0,
+ .phyclk_mhz = 600.0,
+ .socclk_mhz = 694.0,
+ .dscclk_mhz = 214.0,
+ .dram_speed_mts = 11104.0,
+ },
+ {
+ .state = 2,
+ .dcfclk_mhz = 875.0,
+ .fabricclk_mhz = 875.0,
+ .dispclk_mhz = 734.0,
+ .dppclk_mhz = 734.0,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 875.0,
+ .dscclk_mhz = 245.0,
+ .dram_speed_mts = 14000.0,
+ },
+ {
+ .state = 3,
+ .dcfclk_mhz = 1000.0,
+ .fabricclk_mhz = 1000.0,
+ .dispclk_mhz = 1100.0,
+ .dppclk_mhz = 1100.0,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 1000.0,
+ .dscclk_mhz = 367.0,
+ .dram_speed_mts = 16000.0,
+ },
+ {
+ .state = 4,
+ .dcfclk_mhz = 1200.0,
+ .fabricclk_mhz = 1200.0,
+ .dispclk_mhz = 1284.0,
+ .dppclk_mhz = 1284.0,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 1200.0,
+ .dscclk_mhz = 428.0,
+ .dram_speed_mts = 16000.0,
+ },
+ /*Extra state, no dispclk ramping*/
+ {
+ .state = 5,
+ .dcfclk_mhz = 1200.0,
+ .fabricclk_mhz = 1200.0,
+ .dispclk_mhz = 1284.0,
+ .dppclk_mhz = 1284.0,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 1200.0,
+ .dscclk_mhz = 428.0,
+ .dram_speed_mts = 16000.0,
+ },
+ },
+ .num_states = 5,
+ .sr_exit_time_us = 11.6,
+ .sr_enter_plus_exit_time_us = 13.9,
+ .urgent_latency_us = 4.0,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 40.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 40.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
+ .max_avg_sdp_bw_use_normal_percent = 40.0,
+ .max_avg_dram_bw_use_normal_percent = 40.0,
+ .writeback_latency_us = 12.0,
+ .ideal_dram_bw_after_urgent_percent = 40.0,
+ .max_request_size_bytes = 256,
+ .dram_channel_width_bytes = 2,
+ .fabric_datapath_to_dcn_data_return_bytes = 64,
+ .dcn_downspread_percent = 0.5,
+ .downspread_percent = 0.38,
+ .dram_page_open_time_ns = 50.0,
+ .dram_rw_turnaround_time_ns = 17.5,
+ .dram_return_buffer_per_channel_bytes = 8192,
+ .round_trip_ping_latency_dcfclk_cycles = 131,
+ .urgent_out_of_order_return_per_channel_bytes = 256,
+ .channel_interleave_bytes = 256,
+ .num_banks = 8,
+ .num_chans = 8,
+ .vmm_page_size_bytes = 4096,
+ .dram_clock_change_latency_us = 404.0,
+ .dummy_pstate_latency_us = 5.0,
+ .writeback_dram_clock_change_latency_us = 23.0,
+ .return_bus_width_bytes = 64,
+ .dispclk_dppclk_vco_speed_mhz = 3850,
+ .xfc_bus_transport_time_us = 20,
+ .xfc_xbuf_latency_tolerance_us = 4,
+ .use_urgent_burst_bw = 0
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn2_0_nv12_soc = { 0 };
+
+struct _vcs_dpi_ip_params_st dcn2_1_ip = {
+ .odm_capable = 1,
+ .gpuvm_enable = 1,
+ .hostvm_enable = 1,
+ .gpuvm_max_page_table_levels = 1,
+ .hostvm_max_page_table_levels = 4,
+ .hostvm_cached_page_table_levels = 2,
+ .num_dsc = 3,
+ .rob_buffer_size_kbytes = 168,
+ .det_buffer_size_kbytes = 164,
+ .dpte_buffer_size_in_pte_reqs_luma = 44,
+ .dpte_buffer_size_in_pte_reqs_chroma = 42,//todo
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .pte_enable = 1,
+ .max_page_table_levels = 4,
+ .pte_chunk_size_kbytes = 2,
+ .meta_chunk_size_kbytes = 2,
+ .min_meta_chunk_size_bytes = 256,
+ .writeback_chunk_size_kbytes = 2,
+ .line_buffer_size_bits = 789504,
+ .is_line_buffer_bpp_fixed = 0,
+ .line_buffer_fixed_bpp = 0,
+ .dcc_supported = true,
+ .max_line_buffer_lines = 12,
+ .writeback_luma_buffer_size_kbytes = 12,
+ .writeback_chroma_buffer_size_kbytes = 8,
+ .writeback_chroma_line_buffer_width_pixels = 4,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 12,
+ .writeback_max_vscl_taps = 12,
+ .writeback_line_buffer_luma_buffer_size = 0,
+ .writeback_line_buffer_chroma_buffer_size = 14643,
+ .cursor_buffer_size = 8,
+ .cursor_chunk_size = 2,
+ .max_num_otg = 4,
+ .max_num_dpp = 4,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 4,
+ .max_vscl_ratio = 4,
+ .hscl_mults = 4,
+ .vscl_mults = 4,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dispclk_ramp_margin_percent = 1,
+ .underscan_factor = 1.10,
+ .min_vblank_lines = 32, //
+ .dppclk_delay_subtotal = 77, //
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_cnvc_formatter = 8,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 87, //
+ .dcfclk_cstate_latency = 10, // SRExitTime
+ .max_inter_dcn_tile_repeaters = 8,
+
+ .xfc_supported = false,
+ .xfc_fill_bw_overhead_percent = 10.0,
+ .xfc_fill_constant_bytes = 0,
+ .ptoi_supported = 0,
+ .number_of_cursors = 1,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn2_1_soc = {
+ .clock_limits = {
+ {
+ .state = 0,
+ .dcfclk_mhz = 400.0,
+ .fabricclk_mhz = 400.0,
+ .dispclk_mhz = 600.0,
+ .dppclk_mhz = 400.00,
+ .phyclk_mhz = 600.0,
+ .socclk_mhz = 278.0,
+ .dscclk_mhz = 205.67,
+ .dram_speed_mts = 1600.0,
+ },
+ {
+ .state = 1,
+ .dcfclk_mhz = 464.52,
+ .fabricclk_mhz = 800.0,
+ .dispclk_mhz = 654.55,
+ .dppclk_mhz = 626.09,
+ .phyclk_mhz = 600.0,
+ .socclk_mhz = 278.0,
+ .dscclk_mhz = 205.67,
+ .dram_speed_mts = 1600.0,
+ },
+ {
+ .state = 2,
+ .dcfclk_mhz = 514.29,
+ .fabricclk_mhz = 933.0,
+ .dispclk_mhz = 757.89,
+ .dppclk_mhz = 685.71,
+ .phyclk_mhz = 600.0,
+ .socclk_mhz = 278.0,
+ .dscclk_mhz = 287.67,
+ .dram_speed_mts = 1866.0,
+ },
+ {
+ .state = 3,
+ .dcfclk_mhz = 576.00,
+ .fabricclk_mhz = 1067.0,
+ .dispclk_mhz = 847.06,
+ .dppclk_mhz = 757.89,
+ .phyclk_mhz = 600.0,
+ .socclk_mhz = 715.0,
+ .dscclk_mhz = 318.334,
+ .dram_speed_mts = 2134.0,
+ },
+ {
+ .state = 4,
+ .dcfclk_mhz = 626.09,
+ .fabricclk_mhz = 1200.0,
+ .dispclk_mhz = 900.00,
+ .dppclk_mhz = 847.06,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 953.0,
+ .dscclk_mhz = 489.0,
+ .dram_speed_mts = 2400.0,
+ },
+ {
+ .state = 5,
+ .dcfclk_mhz = 685.71,
+ .fabricclk_mhz = 1333.0,
+ .dispclk_mhz = 1028.57,
+ .dppclk_mhz = 960.00,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 278.0,
+ .dscclk_mhz = 287.67,
+ .dram_speed_mts = 2666.0,
+ },
+ {
+ .state = 6,
+ .dcfclk_mhz = 757.89,
+ .fabricclk_mhz = 1467.0,
+ .dispclk_mhz = 1107.69,
+ .dppclk_mhz = 1028.57,
+ .phyclk_mhz = 810.0,
+ .socclk_mhz = 715.0,
+ .dscclk_mhz = 318.334,
+ .dram_speed_mts = 3200.0,
+ },
+ {
+ .state = 7,
+ .dcfclk_mhz = 847.06,
+ .fabricclk_mhz = 1600.0,
+ .dispclk_mhz = 1395.0,
+ .dppclk_mhz = 1285.00,
+ .phyclk_mhz = 1325.0,
+ .socclk_mhz = 953.0,
+ .dscclk_mhz = 489.0,
+ .dram_speed_mts = 4266.0,
+ },
+ /*Extra state, no dispclk ramping*/
+ {
+ .state = 8,
+ .dcfclk_mhz = 847.06,
+ .fabricclk_mhz = 1600.0,
+ .dispclk_mhz = 1395.0,
+ .dppclk_mhz = 1285.0,
+ .phyclk_mhz = 1325.0,
+ .socclk_mhz = 953.0,
+ .dscclk_mhz = 489.0,
+ .dram_speed_mts = 4266.0,
+ },
+
+ },
+
+ .sr_exit_time_us = 12.5,
+ .sr_enter_plus_exit_time_us = 17.0,
+ .urgent_latency_us = 4.0,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 75.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
+ .max_avg_sdp_bw_use_normal_percent = 60.0,
+ .max_avg_dram_bw_use_normal_percent = 100.0,
+ .writeback_latency_us = 12.0,
+ .max_request_size_bytes = 256,
+ .dram_channel_width_bytes = 4,
+ .fabric_datapath_to_dcn_data_return_bytes = 32,
+ .dcn_downspread_percent = 0.5,
+ .downspread_percent = 0.38,
+ .dram_page_open_time_ns = 50.0,
+ .dram_rw_turnaround_time_ns = 17.5,
+ .dram_return_buffer_per_channel_bytes = 8192,
+ .round_trip_ping_latency_dcfclk_cycles = 128,
+ .urgent_out_of_order_return_per_channel_bytes = 4096,
+ .channel_interleave_bytes = 256,
+ .num_banks = 8,
+ .num_chans = 4,
+ .vmm_page_size_bytes = 4096,
+ .dram_clock_change_latency_us = 23.84,
+ .return_bus_width_bytes = 64,
+ .dispclk_dppclk_vco_speed_mhz = 3600,
+ .xfc_bus_transport_time_us = 4,
+ .xfc_xbuf_latency_tolerance_us = 4,
+ .use_urgent_burst_bw = 1,
+ .num_states = 8
+};
+
void dcn20_populate_dml_writeback_from_context(struct dc *dc,
struct resource_context *res_ctx,
display_e2e_pipe_params_st *pipes)
@@ -100,3 +689,1350 @@ void dcn20_populate_dml_writeback_from_context(struct dc *dc,
pipe_cnt++;
}
}
+
+void dcn20_fpu_set_wb_arb_params(struct mcif_arb_params *wb_arb_params,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt, int i)
+{
+ int k;
+
+ dc_assert_fp_enabled();
+
+ for (k = 0; k < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); k++) {
+ wb_arb_params->cli_watermark[k] = get_wm_writeback_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ wb_arb_params->pstate_watermark[k] = get_wm_writeback_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ }
+ wb_arb_params->time_per_pixel = 16.0 * 1000 / (context->res_ctx.pipe_ctx[i].stream->phy_pix_clk / 1000); /* 4 bit fraction, ms */
+}
+
+static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
+{
+ int i;
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ if (!context->res_ctx.pipe_ctx[i].stream)
+ continue;
+ if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
+ return true;
+ }
+ return false;
+}
+
+static enum dcn_zstate_support_state decide_zstate_support(struct dc *dc, struct dc_state *context)
+{
+ int plane_count;
+ int i;
+ unsigned int optimized_min_dst_y_next_start_us;
+
+ plane_count = 0;
+ optimized_min_dst_y_next_start_us = 0;
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ if (context->res_ctx.pipe_ctx[i].plane_state)
+ plane_count++;
+ }
+
+ /*
+ * Z9 and Z10 allowed cases:
+ * 1. 0 Planes enabled
+ * 2. single eDP, on link 0, 1 plane and stutter period > 5ms
+ * Z10 only cases:
+ * 1. single eDP, on link 0, 1 plane and stutter period >= 5ms
+ * Zstate not allowed cases:
+ * 1. Everything else
+ */
+ if (plane_count == 0)
+ return DCN_ZSTATE_SUPPORT_ALLOW;
+ else if (context->stream_count == 1 && context->streams[0]->signal == SIGNAL_TYPE_EDP) {
+ struct dc_link *link = context->streams[0]->sink->link;
+ struct dc_stream_status *stream_status = &context->stream_status[0];
+
+ if (dc_extended_blank_supported(dc)) {
+ for (i = 0; i < dc->res_pool->pipe_count; i++) {
+ if (context->res_ctx.pipe_ctx[i].stream == context->streams[0]
+ && context->res_ctx.pipe_ctx[i].stream->adjust.v_total_min == context->res_ctx.pipe_ctx[i].stream->adjust.v_total_max
+ && context->res_ctx.pipe_ctx[i].stream->adjust.v_total_min > context->res_ctx.pipe_ctx[i].stream->timing.v_total) {
+ optimized_min_dst_y_next_start_us =
+ context->res_ctx.pipe_ctx[i].dlg_regs.optimized_min_dst_y_next_start_us;
+ break;
+ }
+ }
+ }
+ /* zstate only supported on PWRSEQ0 and when there's <2 planes*/
+ if (link->link_index != 0 || stream_status->plane_count > 1)
+ return DCN_ZSTATE_SUPPORT_DISALLOW;
+
+ if (context->bw_ctx.dml.vba.StutterPeriod > 5000.0 || optimized_min_dst_y_next_start_us > 5000)
+ return DCN_ZSTATE_SUPPORT_ALLOW;
+ else if (link->psr_settings.psr_version == DC_PSR_VERSION_1 && !dc->debug.disable_psr)
+ return DCN_ZSTATE_SUPPORT_ALLOW_Z10_ONLY;
+ else
+ return DCN_ZSTATE_SUPPORT_DISALLOW;
+ } else
+ return DCN_ZSTATE_SUPPORT_DISALLOW;
+}
+
+void dcn20_calculate_dlg_params(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt,
+ int vlevel)
+{
+ int i, pipe_idx;
+
+ dc_assert_fp_enabled();
+
+ /* Writeback MCIF_WB arbitration parameters */
+ dc->res_pool->funcs->set_mcif_arb_params(dc, context, pipes, pipe_cnt);
+
+ context->bw_ctx.bw.dcn.clk.dispclk_khz = context->bw_ctx.dml.vba.DISPCLK * 1000;
+ context->bw_ctx.bw.dcn.clk.dcfclk_khz = context->bw_ctx.dml.vba.DCFCLK * 1000;
+ context->bw_ctx.bw.dcn.clk.socclk_khz = context->bw_ctx.dml.vba.SOCCLK * 1000;
+ context->bw_ctx.bw.dcn.clk.dramclk_khz = context->bw_ctx.dml.vba.DRAMSpeed * 1000 / 16;
+
+ if (dc->debug.min_dram_clk_khz > context->bw_ctx.bw.dcn.clk.dramclk_khz)
+ context->bw_ctx.bw.dcn.clk.dramclk_khz = dc->debug.min_dram_clk_khz;
+
+ context->bw_ctx.bw.dcn.clk.dcfclk_deep_sleep_khz = context->bw_ctx.dml.vba.DCFCLKDeepSleep * 1000;
+ context->bw_ctx.bw.dcn.clk.fclk_khz = context->bw_ctx.dml.vba.FabricClock * 1000;
+ context->bw_ctx.bw.dcn.clk.p_state_change_support =
+ context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb]
+ != dm_dram_clock_change_unsupported;
+ context->bw_ctx.bw.dcn.clk.dppclk_khz = 0;
+
+ context->bw_ctx.bw.dcn.clk.dtbclk_en = is_dtbclk_required(dc, context);
+
+ if (context->bw_ctx.bw.dcn.clk.dispclk_khz < dc->debug.min_disp_clk_khz)
+ context->bw_ctx.bw.dcn.clk.dispclk_khz = dc->debug.min_disp_clk_khz;
+
+ for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+ if (!context->res_ctx.pipe_ctx[i].stream)
+ continue;
+ pipes[pipe_idx].pipe.dest.vstartup_start = get_vstartup(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+ pipes[pipe_idx].pipe.dest.vupdate_offset = get_vupdate_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+ pipes[pipe_idx].pipe.dest.vupdate_width = get_vupdate_width(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+ pipes[pipe_idx].pipe.dest.vready_offset = get_vready_offset(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+ context->res_ctx.pipe_ctx[i].det_buffer_size_kb = context->bw_ctx.dml.ip.det_buffer_size_kbytes;
+ context->res_ctx.pipe_ctx[i].unbounded_req = pipes[pipe_idx].pipe.src.unbounded_req_mode;
+
+ if (context->bw_ctx.bw.dcn.clk.dppclk_khz < pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
+ context->bw_ctx.bw.dcn.clk.dppclk_khz = pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
+ context->res_ctx.pipe_ctx[i].plane_res.bw.dppclk_khz =
+ pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000;
+ context->res_ctx.pipe_ctx[i].pipe_dlg_param = pipes[pipe_idx].pipe.dest;
+ pipe_idx++;
+ }
+ /*save a original dppclock copy*/
+ context->bw_ctx.bw.dcn.clk.bw_dppclk_khz = context->bw_ctx.bw.dcn.clk.dppclk_khz;
+ context->bw_ctx.bw.dcn.clk.bw_dispclk_khz = context->bw_ctx.bw.dcn.clk.dispclk_khz;
+ context->bw_ctx.bw.dcn.clk.max_supported_dppclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dppclk_mhz * 1000;
+ context->bw_ctx.bw.dcn.clk.max_supported_dispclk_khz = context->bw_ctx.dml.soc.clock_limits[vlevel].dispclk_mhz * 1000;
+
+ context->bw_ctx.bw.dcn.compbuf_size_kb = context->bw_ctx.dml.ip.config_return_buffer_size_in_kbytes
+ - context->bw_ctx.dml.ip.det_buffer_size_kbytes * pipe_idx;
+
+ for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+ bool cstate_en = context->bw_ctx.dml.vba.PrefetchMode[vlevel][context->bw_ctx.dml.vba.maxMpcComb] != 2;
+
+ if (!context->res_ctx.pipe_ctx[i].stream)
+ continue;
+
+ if (dc->ctx->dce_version == DCN_VERSION_2_01)
+ cstate_en = false;
+
+ context->bw_ctx.dml.funcs.rq_dlg_get_dlg_reg(&context->bw_ctx.dml,
+ &context->res_ctx.pipe_ctx[i].dlg_regs,
+ &context->res_ctx.pipe_ctx[i].ttu_regs,
+ pipes,
+ pipe_cnt,
+ pipe_idx,
+ cstate_en,
+ context->bw_ctx.bw.dcn.clk.p_state_change_support,
+ false, false, true);
+
+ context->bw_ctx.dml.funcs.rq_dlg_get_rq_reg(&context->bw_ctx.dml,
+ &context->res_ctx.pipe_ctx[i].rq_regs,
+ &pipes[pipe_idx].pipe);
+ pipe_idx++;
+ }
+ context->bw_ctx.bw.dcn.clk.zstate_support = decide_zstate_support(dc, context);
+}
+
+static void swizzle_to_dml_params(
+ enum swizzle_mode_values swizzle,
+ unsigned int *sw_mode)
+{
+ switch (swizzle) {
+ case DC_SW_LINEAR:
+ *sw_mode = dm_sw_linear;
+ break;
+ case DC_SW_4KB_S:
+ *sw_mode = dm_sw_4kb_s;
+ break;
+ case DC_SW_4KB_S_X:
+ *sw_mode = dm_sw_4kb_s_x;
+ break;
+ case DC_SW_4KB_D:
+ *sw_mode = dm_sw_4kb_d;
+ break;
+ case DC_SW_4KB_D_X:
+ *sw_mode = dm_sw_4kb_d_x;
+ break;
+ case DC_SW_64KB_S:
+ *sw_mode = dm_sw_64kb_s;
+ break;
+ case DC_SW_64KB_S_X:
+ *sw_mode = dm_sw_64kb_s_x;
+ break;
+ case DC_SW_64KB_S_T:
+ *sw_mode = dm_sw_64kb_s_t;
+ break;
+ case DC_SW_64KB_D:
+ *sw_mode = dm_sw_64kb_d;
+ break;
+ case DC_SW_64KB_D_X:
+ *sw_mode = dm_sw_64kb_d_x;
+ break;
+ case DC_SW_64KB_D_T:
+ *sw_mode = dm_sw_64kb_d_t;
+ break;
+ case DC_SW_64KB_R_X:
+ *sw_mode = dm_sw_64kb_r_x;
+ break;
+ case DC_SW_VAR_S:
+ *sw_mode = dm_sw_var_s;
+ break;
+ case DC_SW_VAR_S_X:
+ *sw_mode = dm_sw_var_s_x;
+ break;
+ case DC_SW_VAR_D:
+ *sw_mode = dm_sw_var_d;
+ break;
+ case DC_SW_VAR_D_X:
+ *sw_mode = dm_sw_var_d_x;
+ break;
+ case DC_SW_VAR_R_X:
+ *sw_mode = dm_sw_var_r_x;
+ break;
+ default:
+ ASSERT(0); /* Not supported */
+ break;
+ }
+}
+
+int dcn20_populate_dml_pipes_from_context(
+ struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate)
+{
+ int pipe_cnt, i;
+ bool synchronized_vblank = true;
+ struct resource_context *res_ctx = &context->res_ctx;
+
+ dc_assert_fp_enabled();
+
+ for (i = 0, pipe_cnt = -1; i < dc->res_pool->pipe_count; i++) {
+ if (!res_ctx->pipe_ctx[i].stream)
+ continue;
+
+ if (pipe_cnt < 0) {
+ pipe_cnt = i;
+ continue;
+ }
+
+ if (res_ctx->pipe_ctx[pipe_cnt].stream == res_ctx->pipe_ctx[i].stream)
+ continue;
+
+ if (dc->debug.disable_timing_sync ||
+ (!resource_are_streams_timing_synchronizable(
+ res_ctx->pipe_ctx[pipe_cnt].stream,
+ res_ctx->pipe_ctx[i].stream) &&
+ !resource_are_vblanks_synchronizable(
+ res_ctx->pipe_ctx[pipe_cnt].stream,
+ res_ctx->pipe_ctx[i].stream))) {
+ synchronized_vblank = false;
+ break;
+ }
+ }
+
+ for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
+ struct dc_crtc_timing *timing = &res_ctx->pipe_ctx[i].stream->timing;
+ unsigned int v_total;
+ unsigned int front_porch;
+ int output_bpc;
+ struct audio_check aud_check = {0};
+
+ if (!res_ctx->pipe_ctx[i].stream)
+ continue;
+
+ v_total = timing->v_total;
+ front_porch = timing->v_front_porch;
+
+ /* todo:
+ pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = 0;
+ pipes[pipe_cnt].pipe.src.dcc = 0;
+ pipes[pipe_cnt].pipe.src.vm = 0;*/
+
+ pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0;
+
+ pipes[pipe_cnt].dout.dsc_enable = res_ctx->pipe_ctx[i].stream->timing.flags.DSC;
+ /* todo: rotation?*/
+ pipes[pipe_cnt].dout.dsc_slices = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.num_slices_h;
+ if (res_ctx->pipe_ctx[i].stream->use_dynamic_meta) {
+ pipes[pipe_cnt].pipe.src.dynamic_metadata_enable = true;
+ /* 1/2 vblank */
+ pipes[pipe_cnt].pipe.src.dynamic_metadata_lines_before_active =
+ (v_total - timing->v_addressable
+ - timing->v_border_top - timing->v_border_bottom) / 2;
+ /* 36 bytes dp, 32 hdmi */
+ pipes[pipe_cnt].pipe.src.dynamic_metadata_xmit_bytes =
+ dc_is_dp_signal(res_ctx->pipe_ctx[i].stream->signal) ? 36 : 32;
+ }
+ pipes[pipe_cnt].pipe.src.dcc = false;
+ pipes[pipe_cnt].pipe.src.dcc_rate = 1;
+ pipes[pipe_cnt].pipe.dest.synchronized_vblank_all_planes = synchronized_vblank;
+ pipes[pipe_cnt].pipe.dest.hblank_start = timing->h_total - timing->h_front_porch;
+ pipes[pipe_cnt].pipe.dest.hblank_end = pipes[pipe_cnt].pipe.dest.hblank_start
+ - timing->h_addressable
+ - timing->h_border_left
+ - timing->h_border_right;
+ pipes[pipe_cnt].pipe.dest.vblank_start = v_total - front_porch;
+ pipes[pipe_cnt].pipe.dest.vblank_end = pipes[pipe_cnt].pipe.dest.vblank_start
+ - timing->v_addressable
+ - timing->v_border_top
+ - timing->v_border_bottom;
+ pipes[pipe_cnt].pipe.dest.htotal = timing->h_total;
+ pipes[pipe_cnt].pipe.dest.vtotal = v_total;
+ pipes[pipe_cnt].pipe.dest.hactive =
+ timing->h_addressable + timing->h_border_left + timing->h_border_right;
+ pipes[pipe_cnt].pipe.dest.vactive =
+ timing->v_addressable + timing->v_border_top + timing->v_border_bottom;
+ pipes[pipe_cnt].pipe.dest.interlaced = timing->flags.INTERLACE;
+ pipes[pipe_cnt].pipe.dest.pixel_rate_mhz = timing->pix_clk_100hz/10000.0;
+ if (timing->timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
+ pipes[pipe_cnt].pipe.dest.pixel_rate_mhz *= 2;
+ pipes[pipe_cnt].pipe.dest.otg_inst = res_ctx->pipe_ctx[i].stream_res.tg->inst;
+ pipes[pipe_cnt].dout.dp_lanes = 4;
+ pipes[pipe_cnt].dout.is_virtual = 0;
+ pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min;
+ pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max;
+ switch (get_num_odm_splits(&res_ctx->pipe_ctx[i])) {
+ case 1:
+ pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_2to1;
+ break;
+ case 3:
+ pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_4to1;
+ break;
+ default:
+ pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_disabled;
+ }
+ pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx;
+ if (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state
+ == res_ctx->pipe_ctx[i].plane_state) {
+ struct pipe_ctx *first_pipe = res_ctx->pipe_ctx[i].top_pipe;
+ int split_idx = 0;
+
+ while (first_pipe->top_pipe && first_pipe->top_pipe->plane_state
+ == res_ctx->pipe_ctx[i].plane_state) {
+ first_pipe = first_pipe->top_pipe;
+ split_idx++;
+ }
+ /* Treat 4to1 mpc combine as an mpo of 2 2-to-1 combines */
+ if (split_idx == 0)
+ pipes[pipe_cnt].pipe.src.hsplit_grp = first_pipe->pipe_idx;
+ else if (split_idx == 1)
+ pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx;
+ else if (split_idx == 2)
+ pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].top_pipe->pipe_idx;
+ } else if (res_ctx->pipe_ctx[i].prev_odm_pipe) {
+ struct pipe_ctx *first_pipe = res_ctx->pipe_ctx[i].prev_odm_pipe;
+
+ while (first_pipe->prev_odm_pipe)
+ first_pipe = first_pipe->prev_odm_pipe;
+ pipes[pipe_cnt].pipe.src.hsplit_grp = first_pipe->pipe_idx;
+ }
+
+ switch (res_ctx->pipe_ctx[i].stream->signal) {
+ case SIGNAL_TYPE_DISPLAY_PORT_MST:
+ case SIGNAL_TYPE_DISPLAY_PORT:
+ pipes[pipe_cnt].dout.output_type = dm_dp;
+ break;
+ case SIGNAL_TYPE_EDP:
+ pipes[pipe_cnt].dout.output_type = dm_edp;
+ break;
+ case SIGNAL_TYPE_HDMI_TYPE_A:
+ case SIGNAL_TYPE_DVI_SINGLE_LINK:
+ case SIGNAL_TYPE_DVI_DUAL_LINK:
+ pipes[pipe_cnt].dout.output_type = dm_hdmi;
+ break;
+ default:
+ /* In case there is no signal, set dp with 4 lanes to allow max config */
+ pipes[pipe_cnt].dout.is_virtual = 1;
+ pipes[pipe_cnt].dout.output_type = dm_dp;
+ pipes[pipe_cnt].dout.dp_lanes = 4;
+ }
+
+ switch (res_ctx->pipe_ctx[i].stream->timing.display_color_depth) {
+ case COLOR_DEPTH_666:
+ output_bpc = 6;
+ break;
+ case COLOR_DEPTH_888:
+ output_bpc = 8;
+ break;
+ case COLOR_DEPTH_101010:
+ output_bpc = 10;
+ break;
+ case COLOR_DEPTH_121212:
+ output_bpc = 12;
+ break;
+ case COLOR_DEPTH_141414:
+ output_bpc = 14;
+ break;
+ case COLOR_DEPTH_161616:
+ output_bpc = 16;
+ break;
+ case COLOR_DEPTH_999:
+ output_bpc = 9;
+ break;
+ case COLOR_DEPTH_111111:
+ output_bpc = 11;
+ break;
+ default:
+ output_bpc = 8;
+ break;
+ }
+
+ switch (res_ctx->pipe_ctx[i].stream->timing.pixel_encoding) {
+ case PIXEL_ENCODING_RGB:
+ case PIXEL_ENCODING_YCBCR444:
+ pipes[pipe_cnt].dout.output_format = dm_444;
+ pipes[pipe_cnt].dout.output_bpp = output_bpc * 3;
+ break;
+ case PIXEL_ENCODING_YCBCR420:
+ pipes[pipe_cnt].dout.output_format = dm_420;
+ pipes[pipe_cnt].dout.output_bpp = (output_bpc * 3.0) / 2;
+ break;
+ case PIXEL_ENCODING_YCBCR422:
+ if (res_ctx->pipe_ctx[i].stream->timing.flags.DSC &&
+ !res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.ycbcr422_simple)
+ pipes[pipe_cnt].dout.output_format = dm_n422;
+ else
+ pipes[pipe_cnt].dout.output_format = dm_s422;
+ pipes[pipe_cnt].dout.output_bpp = output_bpc * 2;
+ break;
+ default:
+ pipes[pipe_cnt].dout.output_format = dm_444;
+ pipes[pipe_cnt].dout.output_bpp = output_bpc * 3;
+ }
+
+ if (res_ctx->pipe_ctx[i].stream->timing.flags.DSC)
+ pipes[pipe_cnt].dout.output_bpp = res_ctx->pipe_ctx[i].stream->timing.dsc_cfg.bits_per_pixel / 16.0;
+
+ /* todo: default max for now, until there is logic reflecting this in dc*/
+ pipes[pipe_cnt].dout.dsc_input_bpc = 12;
+ /*fill up the audio sample rate (unit in kHz)*/
+ get_audio_check(&res_ctx->pipe_ctx[i].stream->audio_info, &aud_check);
+ pipes[pipe_cnt].dout.max_audio_sample_rate = aud_check.max_audiosample_rate / 1000;
+ /*
+ * For graphic plane, cursor number is 1, nv12 is 0
+ * bw calculations due to cursor on/off
+ */
+ if (res_ctx->pipe_ctx[i].plane_state &&
+ res_ctx->pipe_ctx[i].plane_state->address.type == PLN_ADDR_TYPE_VIDEO_PROGRESSIVE)
+ pipes[pipe_cnt].pipe.src.num_cursors = 0;
+ else
+ pipes[pipe_cnt].pipe.src.num_cursors = dc->dml.ip.number_of_cursors;
+
+ pipes[pipe_cnt].pipe.src.cur0_src_width = 256;
+ pipes[pipe_cnt].pipe.src.cur0_bpp = dm_cur_32bit;
+
+ if (!res_ctx->pipe_ctx[i].plane_state) {
+ pipes[pipe_cnt].pipe.src.is_hsplit = pipes[pipe_cnt].pipe.dest.odm_combine != dm_odm_combine_mode_disabled;
+ pipes[pipe_cnt].pipe.src.source_scan = dm_horz;
+ pipes[pipe_cnt].pipe.src.sw_mode = dm_sw_4kb_s;
+ pipes[pipe_cnt].pipe.src.macro_tile_size = dm_64k_tile;
+ pipes[pipe_cnt].pipe.src.viewport_width = timing->h_addressable;
+ if (pipes[pipe_cnt].pipe.src.viewport_width > 1920)
+ pipes[pipe_cnt].pipe.src.viewport_width = 1920;
+ pipes[pipe_cnt].pipe.src.viewport_height = timing->v_addressable;
+ if (pipes[pipe_cnt].pipe.src.viewport_height > 1080)
+ pipes[pipe_cnt].pipe.src.viewport_height = 1080;
+ pipes[pipe_cnt].pipe.src.surface_height_y = pipes[pipe_cnt].pipe.src.viewport_height;
+ pipes[pipe_cnt].pipe.src.surface_width_y = pipes[pipe_cnt].pipe.src.viewport_width;
+ pipes[pipe_cnt].pipe.src.surface_height_c = pipes[pipe_cnt].pipe.src.viewport_height;
+ pipes[pipe_cnt].pipe.src.surface_width_c = pipes[pipe_cnt].pipe.src.viewport_width;
+ pipes[pipe_cnt].pipe.src.data_pitch = ((pipes[pipe_cnt].pipe.src.viewport_width + 255) / 256) * 256;
+ pipes[pipe_cnt].pipe.src.source_format = dm_444_32;
+ pipes[pipe_cnt].pipe.dest.recout_width = pipes[pipe_cnt].pipe.src.viewport_width; /*vp_width/hratio*/
+ pipes[pipe_cnt].pipe.dest.recout_height = pipes[pipe_cnt].pipe.src.viewport_height; /*vp_height/vratio*/
+ pipes[pipe_cnt].pipe.dest.full_recout_width = pipes[pipe_cnt].pipe.dest.recout_width; /*when is_hsplit != 1*/
+ pipes[pipe_cnt].pipe.dest.full_recout_height = pipes[pipe_cnt].pipe.dest.recout_height; /*when is_hsplit != 1*/
+ pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_16;
+ pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio = 1.0;
+ pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio = 1.0;
+ pipes[pipe_cnt].pipe.scale_ratio_depth.scl_enable = 0; /*Lb only or Full scl*/
+ pipes[pipe_cnt].pipe.scale_taps.htaps = 1;
+ pipes[pipe_cnt].pipe.scale_taps.vtaps = 1;
+ pipes[pipe_cnt].pipe.dest.vtotal_min = v_total;
+ pipes[pipe_cnt].pipe.dest.vtotal_max = v_total;
+
+ if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_2to1) {
+ pipes[pipe_cnt].pipe.src.viewport_width /= 2;
+ pipes[pipe_cnt].pipe.dest.recout_width /= 2;
+ } else if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_4to1) {
+ pipes[pipe_cnt].pipe.src.viewport_width /= 4;
+ pipes[pipe_cnt].pipe.dest.recout_width /= 4;
+ }
+ } else {
+ struct dc_plane_state *pln = res_ctx->pipe_ctx[i].plane_state;
+ struct scaler_data *scl = &res_ctx->pipe_ctx[i].plane_res.scl_data;
+
+ pipes[pipe_cnt].pipe.src.immediate_flip = pln->flip_immediate;
+ pipes[pipe_cnt].pipe.src.is_hsplit = (res_ctx->pipe_ctx[i].bottom_pipe && res_ctx->pipe_ctx[i].bottom_pipe->plane_state == pln)
+ || (res_ctx->pipe_ctx[i].top_pipe && res_ctx->pipe_ctx[i].top_pipe->plane_state == pln)
+ || pipes[pipe_cnt].pipe.dest.odm_combine != dm_odm_combine_mode_disabled;
+
+ /* stereo is not split */
+ if (pln->stereo_format == PLANE_STEREO_FORMAT_SIDE_BY_SIDE ||
+ pln->stereo_format == PLANE_STEREO_FORMAT_TOP_AND_BOTTOM) {
+ pipes[pipe_cnt].pipe.src.is_hsplit = false;
+ pipes[pipe_cnt].pipe.src.hsplit_grp = res_ctx->pipe_ctx[i].pipe_idx;
+ }
+
+ pipes[pipe_cnt].pipe.src.source_scan = pln->rotation == ROTATION_ANGLE_90
+ || pln->rotation == ROTATION_ANGLE_270 ? dm_vert : dm_horz;
+ pipes[pipe_cnt].pipe.src.viewport_y_y = scl->viewport.y;
+ pipes[pipe_cnt].pipe.src.viewport_y_c = scl->viewport_c.y;
+ pipes[pipe_cnt].pipe.src.viewport_width = scl->viewport.width;
+ pipes[pipe_cnt].pipe.src.viewport_width_c = scl->viewport_c.width;
+ pipes[pipe_cnt].pipe.src.viewport_height = scl->viewport.height;
+ pipes[pipe_cnt].pipe.src.viewport_height_c = scl->viewport_c.height;
+ pipes[pipe_cnt].pipe.src.viewport_width_max = pln->src_rect.width;
+ pipes[pipe_cnt].pipe.src.viewport_height_max = pln->src_rect.height;
+ pipes[pipe_cnt].pipe.src.surface_width_y = pln->plane_size.surface_size.width;
+ pipes[pipe_cnt].pipe.src.surface_height_y = pln->plane_size.surface_size.height;
+ pipes[pipe_cnt].pipe.src.surface_width_c = pln->plane_size.chroma_size.width;
+ pipes[pipe_cnt].pipe.src.surface_height_c = pln->plane_size.chroma_size.height;
+ if (pln->format == SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA
+ || pln->format >= SURFACE_PIXEL_FORMAT_VIDEO_BEGIN) {
+ pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.surface_pitch;
+ pipes[pipe_cnt].pipe.src.data_pitch_c = pln->plane_size.chroma_pitch;
+ pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.meta_pitch;
+ pipes[pipe_cnt].pipe.src.meta_pitch_c = pln->dcc.meta_pitch_c;
+ } else {
+ pipes[pipe_cnt].pipe.src.data_pitch = pln->plane_size.surface_pitch;
+ pipes[pipe_cnt].pipe.src.meta_pitch = pln->dcc.meta_pitch;
+ }
+ pipes[pipe_cnt].pipe.src.dcc = pln->dcc.enable;
+ pipes[pipe_cnt].pipe.dest.recout_width = scl->recout.width;
+ pipes[pipe_cnt].pipe.dest.recout_height = scl->recout.height;
+ pipes[pipe_cnt].pipe.dest.full_recout_height = scl->recout.height;
+ pipes[pipe_cnt].pipe.dest.full_recout_width = scl->recout.width;
+ if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_2to1)
+ pipes[pipe_cnt].pipe.dest.full_recout_width *= 2;
+ else if (pipes[pipe_cnt].pipe.dest.odm_combine == dm_odm_combine_mode_4to1)
+ pipes[pipe_cnt].pipe.dest.full_recout_width *= 4;
+ else {
+ struct pipe_ctx *split_pipe = res_ctx->pipe_ctx[i].bottom_pipe;
+
+ while (split_pipe && split_pipe->plane_state == pln) {
+ pipes[pipe_cnt].pipe.dest.full_recout_width += split_pipe->plane_res.scl_data.recout.width;
+ split_pipe = split_pipe->bottom_pipe;
+ }
+ split_pipe = res_ctx->pipe_ctx[i].top_pipe;
+ while (split_pipe && split_pipe->plane_state == pln) {
+ pipes[pipe_cnt].pipe.dest.full_recout_width += split_pipe->plane_res.scl_data.recout.width;
+ split_pipe = split_pipe->top_pipe;
+ }
+ }
+
+ pipes[pipe_cnt].pipe.scale_ratio_depth.lb_depth = dm_lb_16;
+ pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio = (double) scl->ratios.horz.value / (1ULL<<32);
+ pipes[pipe_cnt].pipe.scale_ratio_depth.hscl_ratio_c = (double) scl->ratios.horz_c.value / (1ULL<<32);
+ pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio = (double) scl->ratios.vert.value / (1ULL<<32);
+ pipes[pipe_cnt].pipe.scale_ratio_depth.vscl_ratio_c = (double) scl->ratios.vert_c.value / (1ULL<<32);
+ pipes[pipe_cnt].pipe.scale_ratio_depth.scl_enable =
+ scl->ratios.vert.value != dc_fixpt_one.value
+ || scl->ratios.horz.value != dc_fixpt_one.value
+ || scl->ratios.vert_c.value != dc_fixpt_one.value
+ || scl->ratios.horz_c.value != dc_fixpt_one.value /*Lb only or Full scl*/
+ || dc->debug.always_scale; /*support always scale*/
+ pipes[pipe_cnt].pipe.scale_taps.htaps = scl->taps.h_taps;
+ pipes[pipe_cnt].pipe.scale_taps.htaps_c = scl->taps.h_taps_c;
+ pipes[pipe_cnt].pipe.scale_taps.vtaps = scl->taps.v_taps;
+ pipes[pipe_cnt].pipe.scale_taps.vtaps_c = scl->taps.v_taps_c;
+
+ pipes[pipe_cnt].pipe.src.macro_tile_size =
+ swizzle_mode_to_macro_tile_size(pln->tiling_info.gfx9.swizzle);
+ swizzle_to_dml_params(pln->tiling_info.gfx9.swizzle,
+ &pipes[pipe_cnt].pipe.src.sw_mode);
+
+ switch (pln->format) {
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_YCbCr:
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_YCrCb:
+ pipes[pipe_cnt].pipe.src.source_format = dm_420_8;
+ break;
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCbCr:
+ case SURFACE_PIXEL_FORMAT_VIDEO_420_10bpc_YCrCb:
+ pipes[pipe_cnt].pipe.src.source_format = dm_420_10;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616:
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616:
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB16161616F:
+ case SURFACE_PIXEL_FORMAT_GRPH_ABGR16161616F:
+ pipes[pipe_cnt].pipe.src.source_format = dm_444_64;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_ARGB1555:
+ case SURFACE_PIXEL_FORMAT_GRPH_RGB565:
+ pipes[pipe_cnt].pipe.src.source_format = dm_444_16;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_PALETA_256_COLORS:
+ pipes[pipe_cnt].pipe.src.source_format = dm_444_8;
+ break;
+ case SURFACE_PIXEL_FORMAT_GRPH_RGBE_ALPHA:
+ pipes[pipe_cnt].pipe.src.source_format = dm_rgbe_alpha;
+ break;
+ default:
+ pipes[pipe_cnt].pipe.src.source_format = dm_444_32;
+ break;
+ }
+ }
+
+ pipe_cnt++;
+ }
+
+ /* populate writeback information */
+ dc->res_pool->funcs->populate_dml_writeback_from_context(dc, res_ctx, pipes);
+
+ return pipe_cnt;
+}
+
+void dcn20_calculate_wm(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int *out_pipe_cnt,
+ int *pipe_split_from,
+ int vlevel,
+ bool fast_validate)
+{
+ int pipe_cnt, i, pipe_idx;
+
+ dc_assert_fp_enabled();
+
+ for (i = 0, pipe_idx = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
+ if (!context->res_ctx.pipe_ctx[i].stream)
+ continue;
+
+ pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0;
+ pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.vba.RequiredDISPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
+
+ if (pipe_split_from[i] < 0) {
+ pipes[pipe_cnt].clks_cfg.dppclk_mhz =
+ context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx];
+ if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_idx] == pipe_idx)
+ pipes[pipe_cnt].pipe.dest.odm_combine =
+ context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx];
+ else
+ pipes[pipe_cnt].pipe.dest.odm_combine = 0;
+ pipe_idx++;
+ } else {
+ pipes[pipe_cnt].clks_cfg.dppclk_mhz =
+ context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel][context->bw_ctx.dml.vba.maxMpcComb][pipe_split_from[i]];
+ if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_split_from[i]] == pipe_split_from[i])
+ pipes[pipe_cnt].pipe.dest.odm_combine =
+ context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_split_from[i]];
+ else
+ pipes[pipe_cnt].pipe.dest.odm_combine = 0;
+ }
+
+ if (dc->config.forced_clocks) {
+ pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
+ pipes[pipe_cnt].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
+ }
+ if (dc->debug.min_disp_clk_khz > pipes[pipe_cnt].clks_cfg.dispclk_mhz * 1000)
+ pipes[pipe_cnt].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
+ if (dc->debug.min_dpp_clk_khz > pipes[pipe_cnt].clks_cfg.dppclk_mhz * 1000)
+ pipes[pipe_cnt].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
+
+ pipe_cnt++;
+ }
+
+ if (pipe_cnt != pipe_idx) {
+ if (dc->res_pool->funcs->populate_dml_pipes)
+ pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc,
+ context, pipes, fast_validate);
+ else
+ pipe_cnt = dcn20_populate_dml_pipes_from_context(dc,
+ context, pipes, fast_validate);
+ }
+
+ *out_pipe_cnt = pipe_cnt;
+
+ pipes[0].clks_cfg.voltage = vlevel;
+ pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].dcfclk_mhz;
+ pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
+
+ /* only pipe 0 is read for voltage and dcf/soc clocks */
+ if (vlevel < 1) {
+ pipes[0].clks_cfg.voltage = 1;
+ pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[1].dcfclk_mhz;
+ pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[1].socclk_mhz;
+ }
+ context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+ if (vlevel < 2) {
+ pipes[0].clks_cfg.voltage = 2;
+ pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].dcfclk_mhz;
+ pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].socclk_mhz;
+ }
+ context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+ if (vlevel < 3) {
+ pipes[0].clks_cfg.voltage = 3;
+ pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].dcfclk_mhz;
+ pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[2].socclk_mhz;
+ }
+ context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+ pipes[0].clks_cfg.voltage = vlevel;
+ pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].dcfclk_mhz;
+ pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
+ context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+}
+
+void dcn20_update_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb,
+ struct pp_smu_nv_clock_table *max_clocks, unsigned int *uclk_states, unsigned int num_states)
+{
+ struct _vcs_dpi_voltage_scaling_st calculated_states[DC__VOLTAGE_STATES];
+ int i;
+ int num_calculated_states = 0;
+ int min_dcfclk = 0;
+
+ dc_assert_fp_enabled();
+
+ if (num_states == 0)
+ return;
+
+ memset(calculated_states, 0, sizeof(calculated_states));
+
+ if (dc->bb_overrides.min_dcfclk_mhz > 0)
+ min_dcfclk = dc->bb_overrides.min_dcfclk_mhz;
+ else {
+ if (ASICREV_IS_NAVI12_P(dc->ctx->asic_id.hw_internal_rev))
+ min_dcfclk = 310;
+ else
+ // Accounting for SOC/DCF relationship, we can go as high as
+ // 506Mhz in Vmin.
+ min_dcfclk = 506;
+ }
+
+ for (i = 0; i < num_states; i++) {
+ int min_fclk_required_by_uclk;
+ calculated_states[i].state = i;
+ calculated_states[i].dram_speed_mts = uclk_states[i] * 16 / 1000;
+
+ // FCLK:UCLK ratio is 1.08
+ min_fclk_required_by_uclk = div_u64(((unsigned long long)uclk_states[i]) * 1080,
+ 1000000);
+
+ calculated_states[i].fabricclk_mhz = (min_fclk_required_by_uclk < min_dcfclk) ?
+ min_dcfclk : min_fclk_required_by_uclk;
+
+ calculated_states[i].socclk_mhz = (calculated_states[i].fabricclk_mhz > max_clocks->socClockInKhz / 1000) ?
+ max_clocks->socClockInKhz / 1000 : calculated_states[i].fabricclk_mhz;
+
+ calculated_states[i].dcfclk_mhz = (calculated_states[i].fabricclk_mhz > max_clocks->dcfClockInKhz / 1000) ?
+ max_clocks->dcfClockInKhz / 1000 : calculated_states[i].fabricclk_mhz;
+
+ calculated_states[i].dispclk_mhz = max_clocks->displayClockInKhz / 1000;
+ calculated_states[i].dppclk_mhz = max_clocks->displayClockInKhz / 1000;
+ calculated_states[i].dscclk_mhz = max_clocks->displayClockInKhz / (1000 * 3);
+
+ calculated_states[i].phyclk_mhz = max_clocks->phyClockInKhz / 1000;
+
+ num_calculated_states++;
+ }
+
+ calculated_states[num_calculated_states - 1].socclk_mhz = max_clocks->socClockInKhz / 1000;
+ calculated_states[num_calculated_states - 1].fabricclk_mhz = max_clocks->socClockInKhz / 1000;
+ calculated_states[num_calculated_states - 1].dcfclk_mhz = max_clocks->dcfClockInKhz / 1000;
+
+ memcpy(bb->clock_limits, calculated_states, sizeof(bb->clock_limits));
+ bb->num_states = num_calculated_states;
+
+ // Duplicate the last state, DML always an extra state identical to max state to work
+ memcpy(&bb->clock_limits[num_calculated_states], &bb->clock_limits[num_calculated_states - 1], sizeof(struct _vcs_dpi_voltage_scaling_st));
+ bb->clock_limits[num_calculated_states].state = bb->num_states;
+}
+
+void dcn20_cap_soc_clocks(
+ struct _vcs_dpi_soc_bounding_box_st *bb,
+ struct pp_smu_nv_clock_table max_clocks)
+{
+ int i;
+
+ dc_assert_fp_enabled();
+
+ // First pass - cap all clocks higher than the reported max
+ for (i = 0; i < bb->num_states; i++) {
+ if ((bb->clock_limits[i].dcfclk_mhz > (max_clocks.dcfClockInKhz / 1000))
+ && max_clocks.dcfClockInKhz != 0)
+ bb->clock_limits[i].dcfclk_mhz = (max_clocks.dcfClockInKhz / 1000);
+
+ if ((bb->clock_limits[i].dram_speed_mts > (max_clocks.uClockInKhz / 1000) * 16)
+ && max_clocks.uClockInKhz != 0)
+ bb->clock_limits[i].dram_speed_mts = (max_clocks.uClockInKhz / 1000) * 16;
+
+ if ((bb->clock_limits[i].fabricclk_mhz > (max_clocks.fabricClockInKhz / 1000))
+ && max_clocks.fabricClockInKhz != 0)
+ bb->clock_limits[i].fabricclk_mhz = (max_clocks.fabricClockInKhz / 1000);
+
+ if ((bb->clock_limits[i].dispclk_mhz > (max_clocks.displayClockInKhz / 1000))
+ && max_clocks.displayClockInKhz != 0)
+ bb->clock_limits[i].dispclk_mhz = (max_clocks.displayClockInKhz / 1000);
+
+ if ((bb->clock_limits[i].dppclk_mhz > (max_clocks.dppClockInKhz / 1000))
+ && max_clocks.dppClockInKhz != 0)
+ bb->clock_limits[i].dppclk_mhz = (max_clocks.dppClockInKhz / 1000);
+
+ if ((bb->clock_limits[i].phyclk_mhz > (max_clocks.phyClockInKhz / 1000))
+ && max_clocks.phyClockInKhz != 0)
+ bb->clock_limits[i].phyclk_mhz = (max_clocks.phyClockInKhz / 1000);
+
+ if ((bb->clock_limits[i].socclk_mhz > (max_clocks.socClockInKhz / 1000))
+ && max_clocks.socClockInKhz != 0)
+ bb->clock_limits[i].socclk_mhz = (max_clocks.socClockInKhz / 1000);
+
+ if ((bb->clock_limits[i].dscclk_mhz > (max_clocks.dscClockInKhz / 1000))
+ && max_clocks.dscClockInKhz != 0)
+ bb->clock_limits[i].dscclk_mhz = (max_clocks.dscClockInKhz / 1000);
+ }
+
+ // Second pass - remove all duplicate clock states
+ for (i = bb->num_states - 1; i > 1; i--) {
+ bool duplicate = true;
+
+ if (bb->clock_limits[i-1].dcfclk_mhz != bb->clock_limits[i].dcfclk_mhz)
+ duplicate = false;
+ if (bb->clock_limits[i-1].dispclk_mhz != bb->clock_limits[i].dispclk_mhz)
+ duplicate = false;
+ if (bb->clock_limits[i-1].dppclk_mhz != bb->clock_limits[i].dppclk_mhz)
+ duplicate = false;
+ if (bb->clock_limits[i-1].dram_speed_mts != bb->clock_limits[i].dram_speed_mts)
+ duplicate = false;
+ if (bb->clock_limits[i-1].dscclk_mhz != bb->clock_limits[i].dscclk_mhz)
+ duplicate = false;
+ if (bb->clock_limits[i-1].fabricclk_mhz != bb->clock_limits[i].fabricclk_mhz)
+ duplicate = false;
+ if (bb->clock_limits[i-1].phyclk_mhz != bb->clock_limits[i].phyclk_mhz)
+ duplicate = false;
+ if (bb->clock_limits[i-1].socclk_mhz != bb->clock_limits[i].socclk_mhz)
+ duplicate = false;
+
+ if (duplicate)
+ bb->num_states--;
+ }
+}
+
+void dcn20_patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb)
+{
+ dc_assert_fp_enabled();
+
+ if ((int)(bb->sr_exit_time_us * 1000) != dc->bb_overrides.sr_exit_time_ns
+ && dc->bb_overrides.sr_exit_time_ns) {
+ bb->sr_exit_time_us = dc->bb_overrides.sr_exit_time_ns / 1000.0;
+ }
+
+ if ((int)(bb->sr_enter_plus_exit_time_us * 1000)
+ != dc->bb_overrides.sr_enter_plus_exit_time_ns
+ && dc->bb_overrides.sr_enter_plus_exit_time_ns) {
+ bb->sr_enter_plus_exit_time_us =
+ dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
+ }
+
+ if ((int)(bb->urgent_latency_us * 1000) != dc->bb_overrides.urgent_latency_ns
+ && dc->bb_overrides.urgent_latency_ns) {
+ bb->urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0;
+ }
+
+ if ((int)(bb->dram_clock_change_latency_us * 1000)
+ != dc->bb_overrides.dram_clock_change_latency_ns
+ && dc->bb_overrides.dram_clock_change_latency_ns) {
+ bb->dram_clock_change_latency_us =
+ dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
+ }
+
+ if ((int)(bb->dummy_pstate_latency_us * 1000)
+ != dc->bb_overrides.dummy_clock_change_latency_ns
+ && dc->bb_overrides.dummy_clock_change_latency_ns) {
+ bb->dummy_pstate_latency_us =
+ dc->bb_overrides.dummy_clock_change_latency_ns / 1000.0;
+ }
+}
+
+static bool dcn20_validate_bandwidth_internal(struct dc *dc, struct dc_state *context,
+ bool fast_validate)
+{
+ bool out = false;
+
+ BW_VAL_TRACE_SETUP();
+
+ int vlevel = 0;
+ int pipe_split_from[MAX_PIPES];
+ int pipe_cnt = 0;
+ display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
+ DC_LOGGER_INIT(dc->ctx->logger);
+
+ BW_VAL_TRACE_COUNT();
+
+ out = dcn20_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel, fast_validate);
+
+ if (pipe_cnt == 0)
+ goto validate_out;
+
+ if (!out)
+ goto validate_fail;
+
+ BW_VAL_TRACE_END_VOLTAGE_LEVEL();
+
+ if (fast_validate) {
+ BW_VAL_TRACE_SKIP(fast);
+ goto validate_out;
+ }
+
+ dcn20_calculate_wm(dc, context, pipes, &pipe_cnt, pipe_split_from, vlevel, fast_validate);
+ dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
+
+ BW_VAL_TRACE_END_WATERMARKS();
+
+ goto validate_out;
+
+validate_fail:
+ DC_LOG_WARNING("Mode Validation Warning: %s failed validation.\n",
+ dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states]));
+
+ BW_VAL_TRACE_SKIP(fail);
+ out = false;
+
+validate_out:
+ kfree(pipes);
+
+ BW_VAL_TRACE_FINISH();
+
+ return out;
+}
+
+bool dcn20_validate_bandwidth_fp(struct dc *dc,
+ struct dc_state *context,
+ bool fast_validate)
+{
+ bool voltage_supported = false;
+ bool full_pstate_supported = false;
+ bool dummy_pstate_supported = false;
+ double p_state_latency_us;
+
+ dc_assert_fp_enabled();
+
+ p_state_latency_us = context->bw_ctx.dml.soc.dram_clock_change_latency_us;
+ context->bw_ctx.dml.soc.disable_dram_clock_change_vactive_support =
+ dc->debug.disable_dram_clock_change_vactive_support;
+ context->bw_ctx.dml.soc.allow_dram_clock_one_display_vactive =
+ dc->debug.enable_dram_clock_change_one_display_vactive;
+
+ /*Unsafe due to current pipe merge and split logic*/
+ ASSERT(context != dc->current_state);
+
+ if (fast_validate) {
+ return dcn20_validate_bandwidth_internal(dc, context, true);
+ }
+
+ // Best case, we support full UCLK switch latency
+ voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
+ full_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;
+
+ if (context->bw_ctx.dml.soc.dummy_pstate_latency_us == 0 ||
+ (voltage_supported && full_pstate_supported)) {
+ context->bw_ctx.bw.dcn.clk.p_state_change_support = full_pstate_supported;
+ goto restore_dml_state;
+ }
+
+ // Fallback: Try to only support G6 temperature read latency
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = context->bw_ctx.dml.soc.dummy_pstate_latency_us;
+
+ voltage_supported = dcn20_validate_bandwidth_internal(dc, context, false);
+ dummy_pstate_supported = context->bw_ctx.bw.dcn.clk.p_state_change_support;
+
+ if (voltage_supported && (dummy_pstate_supported || !(context->stream_count))) {
+ context->bw_ctx.bw.dcn.clk.p_state_change_support = false;
+ goto restore_dml_state;
+ }
+
+ // ERROR: fallback is supposed to always work.
+ ASSERT(false);
+
+restore_dml_state:
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = p_state_latency_us;
+ return voltage_supported;
+}
+
+void dcn20_fpu_set_wm_ranges(int i,
+ struct pp_smu_wm_range_sets *ranges,
+ struct _vcs_dpi_soc_bounding_box_st *loaded_bb)
+{
+ dc_assert_fp_enabled();
+
+ ranges->reader_wm_sets[i].min_fill_clk_mhz = (i > 0) ? (loaded_bb->clock_limits[i - 1].dram_speed_mts / 16) + 1 : 0;
+ ranges->reader_wm_sets[i].max_fill_clk_mhz = loaded_bb->clock_limits[i].dram_speed_mts / 16;
+}
+
+void dcn20_fpu_adjust_dppclk(struct vba_vars_st *v,
+ int vlevel,
+ int max_mpc_comb,
+ int pipe_idx,
+ bool is_validating_bw)
+{
+ dc_assert_fp_enabled();
+
+ if (is_validating_bw)
+ v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] *= 2;
+ else
+ v->RequiredDPPCLK[vlevel][max_mpc_comb][pipe_idx] /= 2;
+}
+
+int dcn21_populate_dml_pipes_from_context(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate)
+{
+ uint32_t pipe_cnt;
+ int i;
+
+ dc_assert_fp_enabled();
+
+ pipe_cnt = dcn20_populate_dml_pipes_from_context(dc, context, pipes, fast_validate);
+
+ for (i = 0; i < pipe_cnt; i++) {
+
+ pipes[i].pipe.src.hostvm = dc->res_pool->hubbub->riommu_active;
+ pipes[i].pipe.src.gpuvm = 1;
+ }
+
+ return pipe_cnt;
+}
+
+static void patch_bounding_box(struct dc *dc, struct _vcs_dpi_soc_bounding_box_st *bb)
+{
+ int i;
+
+ if (dc->bb_overrides.sr_exit_time_ns) {
+ for (i = 0; i < WM_SET_COUNT; i++) {
+ dc->clk_mgr->bw_params->wm_table.entries[i].sr_exit_time_us =
+ dc->bb_overrides.sr_exit_time_ns / 1000.0;
+ }
+ }
+
+ if (dc->bb_overrides.sr_enter_plus_exit_time_ns) {
+ for (i = 0; i < WM_SET_COUNT; i++) {
+ dc->clk_mgr->bw_params->wm_table.entries[i].sr_enter_plus_exit_time_us =
+ dc->bb_overrides.sr_enter_plus_exit_time_ns / 1000.0;
+ }
+ }
+
+ if (dc->bb_overrides.urgent_latency_ns) {
+ bb->urgent_latency_us = dc->bb_overrides.urgent_latency_ns / 1000.0;
+ }
+
+ if (dc->bb_overrides.dram_clock_change_latency_ns) {
+ for (i = 0; i < WM_SET_COUNT; i++) {
+ dc->clk_mgr->bw_params->wm_table.entries[i].pstate_latency_us =
+ dc->bb_overrides.dram_clock_change_latency_ns / 1000.0;
+ }
+ }
+}
+
+static void calculate_wm_set_for_vlevel(int vlevel,
+ struct wm_range_table_entry *table_entry,
+ struct dcn_watermarks *wm_set,
+ struct display_mode_lib *dml,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt)
+{
+ double dram_clock_change_latency_cached = dml->soc.dram_clock_change_latency_us;
+
+ ASSERT(vlevel < dml->soc.num_states);
+ /* only pipe 0 is read for voltage and dcf/soc clocks */
+ pipes[0].clks_cfg.voltage = vlevel;
+ pipes[0].clks_cfg.dcfclk_mhz = dml->soc.clock_limits[vlevel].dcfclk_mhz;
+ pipes[0].clks_cfg.socclk_mhz = dml->soc.clock_limits[vlevel].socclk_mhz;
+
+ dml->soc.dram_clock_change_latency_us = table_entry->pstate_latency_us;
+ dml->soc.sr_exit_time_us = table_entry->sr_exit_time_us;
+ dml->soc.sr_enter_plus_exit_time_us = table_entry->sr_enter_plus_exit_time_us;
+
+ wm_set->urgent_ns = get_wm_urgent(dml, pipes, pipe_cnt) * 1000;
+ wm_set->cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(dml, pipes, pipe_cnt) * 1000;
+ wm_set->cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(dml, pipes, pipe_cnt) * 1000;
+ wm_set->cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(dml, pipes, pipe_cnt) * 1000;
+ wm_set->pte_meta_urgent_ns = get_wm_memory_trip(dml, pipes, pipe_cnt) * 1000;
+ wm_set->frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(dml, pipes, pipe_cnt) * 1000;
+ wm_set->frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(dml, pipes, pipe_cnt) * 1000;
+ wm_set->urgent_latency_ns = get_urgent_latency(dml, pipes, pipe_cnt) * 1000;
+ dml->soc.dram_clock_change_latency_us = dram_clock_change_latency_cached;
+}
+
+static void dcn21_calculate_wm(struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int *out_pipe_cnt,
+ int *pipe_split_from,
+ int vlevel_req,
+ bool fast_validate)
+{
+ int pipe_cnt, i, pipe_idx;
+ int vlevel, vlevel_max;
+ struct wm_range_table_entry *table_entry;
+ struct clk_bw_params *bw_params = dc->clk_mgr->bw_params;
+
+ ASSERT(bw_params);
+
+ patch_bounding_box(dc, &context->bw_ctx.dml.soc);
+
+ for (i = 0, pipe_idx = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
+ if (!context->res_ctx.pipe_ctx[i].stream)
+ continue;
+
+ pipes[pipe_cnt].clks_cfg.refclk_mhz = dc->res_pool->ref_clocks.dchub_ref_clock_inKhz / 1000.0;
+ pipes[pipe_cnt].clks_cfg.dispclk_mhz = context->bw_ctx.dml.vba.RequiredDISPCLK[vlevel_req][context->bw_ctx.dml.vba.maxMpcComb];
+
+ if (pipe_split_from[i] < 0) {
+ pipes[pipe_cnt].clks_cfg.dppclk_mhz =
+ context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel_req][context->bw_ctx.dml.vba.maxMpcComb][pipe_idx];
+ if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_idx] == pipe_idx)
+ pipes[pipe_cnt].pipe.dest.odm_combine =
+ context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel_req][pipe_idx];
+ else
+ pipes[pipe_cnt].pipe.dest.odm_combine = 0;
+ pipe_idx++;
+ } else {
+ pipes[pipe_cnt].clks_cfg.dppclk_mhz =
+ context->bw_ctx.dml.vba.RequiredDPPCLK[vlevel_req][context->bw_ctx.dml.vba.maxMpcComb][pipe_split_from[i]];
+ if (context->bw_ctx.dml.vba.BlendingAndTiming[pipe_split_from[i]] == pipe_split_from[i])
+ pipes[pipe_cnt].pipe.dest.odm_combine =
+ context->bw_ctx.dml.vba.ODMCombineEnablePerState[vlevel_req][pipe_split_from[i]];
+ else
+ pipes[pipe_cnt].pipe.dest.odm_combine = 0;
+ }
+ pipe_cnt++;
+ }
+
+ if (pipe_cnt != pipe_idx) {
+ if (dc->res_pool->funcs->populate_dml_pipes)
+ pipe_cnt = dc->res_pool->funcs->populate_dml_pipes(dc,
+ context, pipes, fast_validate);
+ else
+ pipe_cnt = dcn21_populate_dml_pipes_from_context(dc,
+ context, pipes, fast_validate);
+ }
+
+ *out_pipe_cnt = pipe_cnt;
+
+ vlevel_max = bw_params->clk_table.num_entries - 1;
+
+
+ /* WM Set D */
+ table_entry = &bw_params->wm_table.entries[WM_D];
+ if (table_entry->wm_type == WM_TYPE_RETRAINING)
+ vlevel = 0;
+ else
+ vlevel = vlevel_max;
+ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.d,
+ &context->bw_ctx.dml, pipes, pipe_cnt);
+ /* WM Set C */
+ table_entry = &bw_params->wm_table.entries[WM_C];
+ vlevel = MIN(MAX(vlevel_req, 3), vlevel_max);
+ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.c,
+ &context->bw_ctx.dml, pipes, pipe_cnt);
+ /* WM Set B */
+ table_entry = &bw_params->wm_table.entries[WM_B];
+ vlevel = MIN(MAX(vlevel_req, 2), vlevel_max);
+ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.b,
+ &context->bw_ctx.dml, pipes, pipe_cnt);
+
+ /* WM Set A */
+ table_entry = &bw_params->wm_table.entries[WM_A];
+ vlevel = MIN(vlevel_req, vlevel_max);
+ calculate_wm_set_for_vlevel(vlevel, table_entry, &context->bw_ctx.bw.dcn.watermarks.a,
+ &context->bw_ctx.dml, pipes, pipe_cnt);
+}
+
+bool dcn21_validate_bandwidth_fp(struct dc *dc,
+ struct dc_state *context,
+ bool fast_validate)
+{
+ bool out = false;
+
+ BW_VAL_TRACE_SETUP();
+
+ int vlevel = 0;
+ int pipe_split_from[MAX_PIPES];
+ int pipe_cnt = 0;
+ display_e2e_pipe_params_st *pipes = kzalloc(dc->res_pool->pipe_count * sizeof(display_e2e_pipe_params_st), GFP_ATOMIC);
+ DC_LOGGER_INIT(dc->ctx->logger);
+
+ BW_VAL_TRACE_COUNT();
+
+ dc_assert_fp_enabled();
+
+ /*Unsafe due to current pipe merge and split logic*/
+ ASSERT(context != dc->current_state);
+
+ out = dcn21_fast_validate_bw(dc, context, pipes, &pipe_cnt, pipe_split_from, &vlevel, fast_validate);
+
+ if (pipe_cnt == 0)
+ goto validate_out;
+
+ if (!out)
+ goto validate_fail;
+
+ BW_VAL_TRACE_END_VOLTAGE_LEVEL();
+
+ if (fast_validate) {
+ BW_VAL_TRACE_SKIP(fast);
+ goto validate_out;
+ }
+
+ dcn21_calculate_wm(dc, context, pipes, &pipe_cnt, pipe_split_from, vlevel, fast_validate);
+ dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
+
+ BW_VAL_TRACE_END_WATERMARKS();
+
+ goto validate_out;
+
+validate_fail:
+ DC_LOG_WARNING("Mode Validation Warning: %s failed validation.\n",
+ dml_get_status_message(context->bw_ctx.dml.vba.ValidationStatus[context->bw_ctx.dml.vba.soc.num_states]));
+
+ BW_VAL_TRACE_SKIP(fail);
+ out = false;
+
+validate_out:
+ kfree(pipes);
+
+ BW_VAL_TRACE_FINISH();
+
+ return out;
+}
+
+static struct _vcs_dpi_voltage_scaling_st construct_low_pstate_lvl(struct clk_limit_table *clk_table, unsigned int high_voltage_lvl)
+{
+ struct _vcs_dpi_voltage_scaling_st low_pstate_lvl;
+ int i;
+
+ low_pstate_lvl.state = 1;
+ low_pstate_lvl.dcfclk_mhz = clk_table->entries[0].dcfclk_mhz;
+ low_pstate_lvl.fabricclk_mhz = clk_table->entries[0].fclk_mhz;
+ low_pstate_lvl.socclk_mhz = clk_table->entries[0].socclk_mhz;
+ low_pstate_lvl.dram_speed_mts = clk_table->entries[0].memclk_mhz * 2;
+
+ low_pstate_lvl.dispclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dispclk_mhz;
+ low_pstate_lvl.dppclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dppclk_mhz;
+ low_pstate_lvl.dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[high_voltage_lvl].dram_bw_per_chan_gbps;
+ low_pstate_lvl.dscclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dscclk_mhz;
+ low_pstate_lvl.dtbclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].dtbclk_mhz;
+ low_pstate_lvl.phyclk_d18_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].phyclk_d18_mhz;
+ low_pstate_lvl.phyclk_mhz = dcn2_1_soc.clock_limits[high_voltage_lvl].phyclk_mhz;
+
+ for (i = clk_table->num_entries; i > 1; i--)
+ clk_table->entries[i] = clk_table->entries[i-1];
+ clk_table->entries[1] = clk_table->entries[0];
+ clk_table->num_entries++;
+
+ return low_pstate_lvl;
+}
+
+void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+ struct dcn21_resource_pool *pool = TO_DCN21_RES_POOL(dc->res_pool);
+ struct clk_limit_table *clk_table = &bw_params->clk_table;
+ struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES];
+ unsigned int i, closest_clk_lvl = 0, k = 0;
+ int j;
+
+ dc_assert_fp_enabled();
+
+ dcn2_1_ip.max_num_otg = pool->base.res_cap->num_timing_generator;
+ dcn2_1_ip.max_num_dpp = pool->base.pipe_count;
+ dcn2_1_soc.num_chans = bw_params->num_channels;
+
+ ASSERT(clk_table->num_entries);
+ /* Copy dcn2_1_soc.clock_limits to clock_limits to avoid copying over null states later */
+ for (i = 0; i < dcn2_1_soc.num_states + 1; i++) {
+ clock_limits[i] = dcn2_1_soc.clock_limits[i];
+ }
+
+ for (i = 0; i < clk_table->num_entries; i++) {
+ /* loop backwards*/
+ for (closest_clk_lvl = 0, j = dcn2_1_soc.num_states - 1; j >= 0; j--) {
+ if ((unsigned int) dcn2_1_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {
+ closest_clk_lvl = j;
+ break;
+ }
+ }
+
+ /* clk_table[1] is reserved for min DF PState. skip here to fill in later. */
+ if (i == 1)
+ k++;
+
+ clock_limits[k].state = k;
+ clock_limits[k].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz;
+ clock_limits[k].fabricclk_mhz = clk_table->entries[i].fclk_mhz;
+ clock_limits[k].socclk_mhz = clk_table->entries[i].socclk_mhz;
+ clock_limits[k].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2;
+
+ clock_limits[k].dispclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz;
+ clock_limits[k].dppclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz;
+ clock_limits[k].dram_bw_per_chan_gbps = dcn2_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps;
+ clock_limits[k].dscclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz;
+ clock_limits[k].dtbclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz;
+ clock_limits[k].phyclk_d18_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz;
+ clock_limits[k].phyclk_mhz = dcn2_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz;
+
+ k++;
+ }
+ for (i = 0; i < clk_table->num_entries + 1; i++)
+ dcn2_1_soc.clock_limits[i] = clock_limits[i];
+ if (clk_table->num_entries) {
+ dcn2_1_soc.num_states = clk_table->num_entries + 1;
+ /* fill in min DF PState */
+ dcn2_1_soc.clock_limits[1] = construct_low_pstate_lvl(clk_table, closest_clk_lvl);
+ /* duplicate last level */
+ dcn2_1_soc.clock_limits[dcn2_1_soc.num_states] = dcn2_1_soc.clock_limits[dcn2_1_soc.num_states - 1];
+ dcn2_1_soc.clock_limits[dcn2_1_soc.num_states].state = dcn2_1_soc.num_states;
+ }
+
+ dml_init_instance(&dc->dml, &dcn2_1_soc, &dcn2_1_ip, DML_PROJECT_DCN21);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
index 36f26126d574..aa892193e485 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.h
@@ -23,6 +23,7 @@
* Authors: AMD
*
*/
+#include "core_types.h"
#ifndef __DCN20_FPU_H__
#define __DCN20_FPU_H__
@@ -31,4 +32,54 @@ void dcn20_populate_dml_writeback_from_context(struct dc *dc,
struct resource_context *res_ctx,
display_e2e_pipe_params_st *pipes);
+void dcn20_fpu_set_wb_arb_params(struct mcif_arb_params *wb_arb_params,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt, int i);
+void dcn20_calculate_dlg_params(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt,
+ int vlevel);
+int dcn20_populate_dml_pipes_from_context(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate);
+void dcn20_calculate_wm(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int *out_pipe_cnt,
+ int *pipe_split_from,
+ int vlevel,
+ bool fast_validate);
+void dcn20_cap_soc_clocks(struct _vcs_dpi_soc_bounding_box_st *bb,
+ struct pp_smu_nv_clock_table max_clocks);
+void dcn20_update_bounding_box(struct dc *dc,
+ struct _vcs_dpi_soc_bounding_box_st *bb,
+ struct pp_smu_nv_clock_table *max_clocks,
+ unsigned int *uclk_states,
+ unsigned int num_states);
+void dcn20_patch_bounding_box(struct dc *dc,
+ struct _vcs_dpi_soc_bounding_box_st *bb);
+bool dcn20_validate_bandwidth_fp(struct dc *dc,
+ struct dc_state *context,
+ bool fast_validate);
+void dcn20_fpu_set_wm_ranges(int i,
+ struct pp_smu_wm_range_sets *ranges,
+ struct _vcs_dpi_soc_bounding_box_st *loaded_bb);
+void dcn20_fpu_adjust_dppclk(struct vba_vars_st *v,
+ int vlevel,
+ int max_mpc_comb,
+ int pipe_idx,
+ bool is_validating_bw);
+
+int dcn21_populate_dml_pipes_from_context(struct dc *dc,
+ struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ bool fast_validate);
+bool dcn21_validate_bandwidth_fp(struct dc *dc,
+ struct dc_state *context,
+ bool fast_validate);
+void dcn21_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+
#endif /* __DCN20_FPU_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
new file mode 100644
index 000000000000..574676a0711a
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.c
@@ -0,0 +1,617 @@
+/*
+ * Copyright 2020-2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "resource.h"
+#include "clk_mgr.h"
+#include "reg_helper.h"
+#include "dcn_calc_math.h"
+#include "dcn20/dcn20_resource.h"
+#include "dcn30/dcn30_resource.h"
+
+
+#include "display_mode_vba_30.h"
+#include "dcn30_fpu.h"
+
+#define REG(reg)\
+ optc1->tg_regs->reg
+
+#define CTX \
+ optc1->base.ctx
+
+#undef FN
+#define FN(reg_name, field_name) \
+ optc1->tg_shift->field_name, optc1->tg_mask->field_name
+
+
+struct _vcs_dpi_ip_params_st dcn3_0_ip = {
+ .use_min_dcfclk = 0,
+ .clamp_min_dcfclk = 0,
+ .odm_capable = 1,
+ .gpuvm_enable = 0,
+ .hostvm_enable = 0,
+ .gpuvm_max_page_table_levels = 4,
+ .hostvm_max_page_table_levels = 4,
+ .hostvm_cached_page_table_levels = 0,
+ .pte_group_size_bytes = 2048,
+ .num_dsc = 6,
+ .rob_buffer_size_kbytes = 184,
+ .det_buffer_size_kbytes = 184,
+ .dpte_buffer_size_in_pte_reqs_luma = 84,
+ .pde_proc_buffer_size_64k_reqs = 48,
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .pte_enable = 1,
+ .max_page_table_levels = 2,
+ .pte_chunk_size_kbytes = 2, // ?
+ .meta_chunk_size_kbytes = 2,
+ .writeback_chunk_size_kbytes = 8,
+ .line_buffer_size_bits = 789504,
+ .is_line_buffer_bpp_fixed = 0, // ?
+ .line_buffer_fixed_bpp = 0, // ?
+ .dcc_supported = true,
+ .writeback_interface_buffer_size_kbytes = 90,
+ .writeback_line_buffer_buffer_size = 0,
+ .max_line_buffer_lines = 12,
+ .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640
+ .writeback_chroma_buffer_size_kbytes = 8,
+ .writeback_chroma_line_buffer_width_pixels = 4,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 1,
+ .writeback_max_vscl_taps = 1,
+ .writeback_line_buffer_luma_buffer_size = 0,
+ .writeback_line_buffer_chroma_buffer_size = 14643,
+ .cursor_buffer_size = 8,
+ .cursor_chunk_size = 2,
+ .max_num_otg = 6,
+ .max_num_dpp = 6,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 6,
+ .max_vscl_ratio = 6,
+ .hscl_mults = 4,
+ .vscl_mults = 4,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dispclk_ramp_margin_percent = 1,
+ .underscan_factor = 1.11,
+ .min_vblank_lines = 32,
+ .dppclk_delay_subtotal = 46,
+ .dynamic_metadata_vm_enabled = true,
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_cnvc_formatter = 27,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 119,
+ .dcfclk_cstate_latency = 5.2, // SRExitTime
+ .max_inter_dcn_tile_repeaters = 8,
+ .max_num_hdmi_frl_outputs = 1,
+ .odm_combine_4to1_supported = true,
+
+ .xfc_supported = false,
+ .xfc_fill_bw_overhead_percent = 10.0,
+ .xfc_fill_constant_bytes = 0,
+ .gfx7_compat_tiling_supported = 0,
+ .number_of_cursors = 1,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_0_soc = {
+ .clock_limits = {
+ {
+ .state = 0,
+ .dispclk_mhz = 562.0,
+ .dppclk_mhz = 300.0,
+ .phyclk_mhz = 300.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 405.6,
+ },
+ },
+
+ .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */
+ .num_states = 1,
+ .sr_exit_time_us = 15.5,
+ .sr_enter_plus_exit_time_us = 20,
+ .urgent_latency_us = 4.0,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
+ .max_avg_sdp_bw_use_normal_percent = 60.0,
+ .max_avg_dram_bw_use_normal_percent = 40.0,
+ .writeback_latency_us = 12.0,
+ .max_request_size_bytes = 256,
+ .fabric_datapath_to_dcn_data_return_bytes = 64,
+ .dcn_downspread_percent = 0.5,
+ .downspread_percent = 0.38,
+ .dram_page_open_time_ns = 50.0,
+ .dram_rw_turnaround_time_ns = 17.5,
+ .dram_return_buffer_per_channel_bytes = 8192,
+ .round_trip_ping_latency_dcfclk_cycles = 191,
+ .urgent_out_of_order_return_per_channel_bytes = 4096,
+ .channel_interleave_bytes = 256,
+ .num_banks = 8,
+ .gpuvm_min_page_size_bytes = 4096,
+ .hostvm_min_page_size_bytes = 4096,
+ .dram_clock_change_latency_us = 404,
+ .dummy_pstate_latency_us = 5,
+ .writeback_dram_clock_change_latency_us = 23.0,
+ .return_bus_width_bytes = 64,
+ .dispclk_dppclk_vco_speed_mhz = 3650,
+ .xfc_bus_transport_time_us = 20, // ?
+ .xfc_xbuf_latency_tolerance_us = 4, // ?
+ .use_urgent_burst_bw = 1, // ?
+ .do_urgent_latency_adjustment = true,
+ .urgent_latency_adjustment_fabric_clock_component_us = 1.0,
+ .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
+};
+
+
+void optc3_fpu_set_vrr_m_const(struct timing_generator *optc,
+ double vtotal_avg)
+{
+struct optc *optc1 = DCN10TG_FROM_TG(optc);
+ double vtotal_min, vtotal_max;
+ double ratio, modulo, phase;
+ uint32_t vblank_start;
+ uint32_t v_total_mask_value = 0;
+
+ dc_assert_fp_enabled();
+
+ /* Compute VTOTAL_MIN and VTOTAL_MAX, so that
+ * VOTAL_MAX - VTOTAL_MIN = 1
+ */
+ v_total_mask_value = 16;
+ vtotal_min = dcn_bw_floor(vtotal_avg);
+ vtotal_max = dcn_bw_ceil(vtotal_avg);
+
+ /* Check that bottom VBLANK is at least 2 lines tall when running with
+ * VTOTAL_MIN. Note that VTOTAL registers are defined as 'total number
+ * of lines in a frame - 1'.
+ */
+ REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START,
+ &vblank_start);
+ ASSERT(vtotal_min >= vblank_start + 1);
+
+ /* Special case where the average frame rate can be achieved
+ * without using the DTO
+ */
+ if (vtotal_min == vtotal_max) {
+ REG_SET(OTG_V_TOTAL, 0, OTG_V_TOTAL, (uint32_t)vtotal_min);
+
+ optc->funcs->set_vtotal_min_max(optc, 0, 0);
+ REG_SET(OTG_M_CONST_DTO0, 0, OTG_M_CONST_DTO_PHASE, 0);
+ REG_SET(OTG_M_CONST_DTO1, 0, OTG_M_CONST_DTO_MODULO, 0);
+ REG_UPDATE_3(OTG_V_TOTAL_CONTROL,
+ OTG_V_TOTAL_MIN_SEL, 0,
+ OTG_V_TOTAL_MAX_SEL, 0,
+ OTG_SET_V_TOTAL_MIN_MASK_EN, 0);
+ return;
+ }
+
+ ratio = vtotal_max - vtotal_avg;
+ modulo = 65536.0 * 65536.0 - 1.0; /* 2^32 - 1 */
+ phase = ratio * modulo;
+
+ /* Special cases where the DTO phase gets rounded to 0 or
+ * to DTO modulo
+ */
+ if (phase <= 0 || phase >= modulo) {
+ REG_SET(OTG_V_TOTAL, 0, OTG_V_TOTAL,
+ phase <= 0 ?
+ (uint32_t)vtotal_max : (uint32_t)vtotal_min);
+ REG_SET(OTG_V_TOTAL_MIN, 0, OTG_V_TOTAL_MIN, 0);
+ REG_SET(OTG_V_TOTAL_MAX, 0, OTG_V_TOTAL_MAX, 0);
+ REG_SET(OTG_M_CONST_DTO0, 0, OTG_M_CONST_DTO_PHASE, 0);
+ REG_SET(OTG_M_CONST_DTO1, 0, OTG_M_CONST_DTO_MODULO, 0);
+ REG_UPDATE_3(OTG_V_TOTAL_CONTROL,
+ OTG_V_TOTAL_MIN_SEL, 0,
+ OTG_V_TOTAL_MAX_SEL, 0,
+ OTG_SET_V_TOTAL_MIN_MASK_EN, 0);
+ return;
+ }
+ REG_UPDATE_6(OTG_V_TOTAL_CONTROL,
+ OTG_V_TOTAL_MIN_SEL, 1,
+ OTG_V_TOTAL_MAX_SEL, 1,
+ OTG_SET_V_TOTAL_MIN_MASK_EN, 1,
+ OTG_SET_V_TOTAL_MIN_MASK, v_total_mask_value,
+ OTG_VTOTAL_MID_REPLACING_MIN_EN, 0,
+ OTG_VTOTAL_MID_REPLACING_MAX_EN, 0);
+ REG_SET(OTG_V_TOTAL, 0, OTG_V_TOTAL, (uint32_t)vtotal_min);
+ optc->funcs->set_vtotal_min_max(optc, vtotal_min, vtotal_max);
+ REG_SET(OTG_M_CONST_DTO0, 0, OTG_M_CONST_DTO_PHASE, (uint32_t)phase);
+ REG_SET(OTG_M_CONST_DTO1, 0, OTG_M_CONST_DTO_MODULO, (uint32_t)modulo);
+}
+
+void dcn30_fpu_populate_dml_writeback_from_context(
+ struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes)
+{
+ int pipe_cnt, i, j;
+ double max_calc_writeback_dispclk;
+ double writeback_dispclk;
+ struct writeback_st dout_wb;
+
+ dc_assert_fp_enabled();
+
+ for (i = 0, pipe_cnt = 0; i < dc->res_pool->pipe_count; i++) {
+ struct dc_stream_state *stream = res_ctx->pipe_ctx[i].stream;
+
+ if (!stream)
+ continue;
+ max_calc_writeback_dispclk = 0;
+
+ /* Set writeback information */
+ pipes[pipe_cnt].dout.wb_enable = 0;
+ pipes[pipe_cnt].dout.num_active_wb = 0;
+ for (j = 0; j < stream->num_wb_info; j++) {
+ struct dc_writeback_info *wb_info = &stream->writeback_info[j];
+
+ if (wb_info->wb_enabled && wb_info->writeback_source_plane &&
+ (wb_info->writeback_source_plane == res_ctx->pipe_ctx[i].plane_state)) {
+ pipes[pipe_cnt].dout.wb_enable = 1;
+ pipes[pipe_cnt].dout.num_active_wb++;
+ dout_wb.wb_src_height = wb_info->dwb_params.cnv_params.crop_en ?
+ wb_info->dwb_params.cnv_params.crop_height :
+ wb_info->dwb_params.cnv_params.src_height;
+ dout_wb.wb_src_width = wb_info->dwb_params.cnv_params.crop_en ?
+ wb_info->dwb_params.cnv_params.crop_width :
+ wb_info->dwb_params.cnv_params.src_width;
+ dout_wb.wb_dst_width = wb_info->dwb_params.dest_width;
+ dout_wb.wb_dst_height = wb_info->dwb_params.dest_height;
+
+ /* For IP that doesn't support WB scaling, set h/v taps to 1 to avoid DML validation failure */
+ if (dc->dml.ip.writeback_max_hscl_taps > 1) {
+ dout_wb.wb_htaps_luma = wb_info->dwb_params.scaler_taps.h_taps;
+ dout_wb.wb_vtaps_luma = wb_info->dwb_params.scaler_taps.v_taps;
+ } else {
+ dout_wb.wb_htaps_luma = 1;
+ dout_wb.wb_vtaps_luma = 1;
+ }
+ dout_wb.wb_htaps_chroma = 0;
+ dout_wb.wb_vtaps_chroma = 0;
+ dout_wb.wb_hratio = wb_info->dwb_params.cnv_params.crop_en ?
+ (double)wb_info->dwb_params.cnv_params.crop_width /
+ (double)wb_info->dwb_params.dest_width :
+ (double)wb_info->dwb_params.cnv_params.src_width /
+ (double)wb_info->dwb_params.dest_width;
+ dout_wb.wb_vratio = wb_info->dwb_params.cnv_params.crop_en ?
+ (double)wb_info->dwb_params.cnv_params.crop_height /
+ (double)wb_info->dwb_params.dest_height :
+ (double)wb_info->dwb_params.cnv_params.src_height /
+ (double)wb_info->dwb_params.dest_height;
+ if (wb_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_ARGB ||
+ wb_info->dwb_params.cnv_params.fc_out_format == DWB_OUT_FORMAT_64BPP_RGBA)
+ dout_wb.wb_pixel_format = dm_444_64;
+ else
+ dout_wb.wb_pixel_format = dm_444_32;
+
+ /* Workaround for cases where multiple writebacks are connected to same plane
+ * In which case, need to compute worst case and set the associated writeback parameters
+ * This workaround is necessary due to DML computation assuming only 1 set of writeback
+ * parameters per pipe
+ */
+ writeback_dispclk = dml30_CalculateWriteBackDISPCLK(
+ dout_wb.wb_pixel_format,
+ pipes[pipe_cnt].pipe.dest.pixel_rate_mhz,
+ dout_wb.wb_hratio,
+ dout_wb.wb_vratio,
+ dout_wb.wb_htaps_luma,
+ dout_wb.wb_vtaps_luma,
+ dout_wb.wb_src_width,
+ dout_wb.wb_dst_width,
+ pipes[pipe_cnt].pipe.dest.htotal,
+ dc->current_state->bw_ctx.dml.ip.writeback_line_buffer_buffer_size);
+
+ if (writeback_dispclk > max_calc_writeback_dispclk) {
+ max_calc_writeback_dispclk = writeback_dispclk;
+ pipes[pipe_cnt].dout.wb = dout_wb;
+ }
+ }
+ }
+
+ pipe_cnt++;
+ }
+}
+
+void dcn30_fpu_set_mcif_arb_params(struct mcif_arb_params *wb_arb_params,
+ struct display_mode_lib *dml,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt,
+ int cur_pipe)
+{
+ int i;
+
+ dc_assert_fp_enabled();
+
+ for (i = 0; i < sizeof(wb_arb_params->cli_watermark)/sizeof(wb_arb_params->cli_watermark[0]); i++) {
+ wb_arb_params->cli_watermark[i] = get_wm_writeback_urgent(dml, pipes, pipe_cnt) * 1000;
+ wb_arb_params->pstate_watermark[i] = get_wm_writeback_dram_clock_change(dml, pipes, pipe_cnt) * 1000;
+ }
+
+ wb_arb_params->dram_speed_change_duration = dml->vba.WritebackAllowDRAMClockChangeEndPosition[cur_pipe] * pipes[0].clks_cfg.refclk_mhz; /* num_clock_cycles = us * MHz */
+}
+
+void dcn30_fpu_update_soc_for_wm_a(struct dc *dc, struct dc_state *context)
+{
+
+dc_assert_fp_enabled();
+
+if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].valid) {
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
+ context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_enter_plus_exit_time_us;
+ context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.sr_exit_time_us;
+ }
+}
+
+void dcn30_fpu_calculate_wm_and_dlg(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt,
+ int vlevel)
+{
+int maxMpcComb = context->bw_ctx.dml.vba.maxMpcComb;
+ int i, pipe_idx;
+ double dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][maxMpcComb];
+ bool pstate_en = context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][maxMpcComb] != dm_dram_clock_change_unsupported;
+
+dc_assert_fp_enabled();
+
+ if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk)
+ dcfclk = context->bw_ctx.dml.soc.min_dcfclk;
+
+ pipes[0].clks_cfg.voltage = vlevel;
+ pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+ pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
+
+ /* Set B:
+ * DCFCLK: 1GHz or min required above 1GHz
+ * FCLK/UCLK: Max
+ */
+ if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid) {
+ if (vlevel == 0) {
+ pipes[0].clks_cfg.voltage = 1;
+ pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dcfclk_mhz;
+ }
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us;
+ context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us;
+ context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us;
+ }
+ context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+ pipes[0].clks_cfg.voltage = vlevel;
+ pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+
+ /* Set D:
+ * DCFCLK: Min Required
+ * FCLK(proportional to UCLK): 1GHz or Max
+ * MALL stutter, sr_enter_exit = 4, sr_exit = 2us
+ */
+ /*
+ if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].valid) {
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us;
+ context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us;
+ context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us;
+ }
+ context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ */
+
+ /* Set C:
+ * DCFCLK: Min Required
+ * FCLK(proportional to UCLK): 1GHz or Max
+ * pstate latency overridden to 5us
+ */
+ if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) {
+ unsigned int min_dram_speed_mts = context->bw_ctx.dml.vba.DRAMSpeed;
+ unsigned int min_dram_speed_mts_margin = 160;
+
+ if (context->bw_ctx.dml.vba.DRAMClockChangeSupport[vlevel][context->bw_ctx.dml.vba.maxMpcComb] == dm_dram_clock_change_unsupported)
+ min_dram_speed_mts = dc->clk_mgr->bw_params->clk_table.entries[dc->clk_mgr->bw_params->clk_table.num_entries - 1].memclk_mhz * 16;
+
+ /* find largest table entry that is lower than dram speed, but lower than DPM0 still uses DPM0 */
+ for (i = 3; i > 0; i--)
+ if (min_dram_speed_mts + min_dram_speed_mts_margin > dc->clk_mgr->bw_params->dummy_pstate_table[i].dram_speed_mts)
+ break;
+
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->dummy_pstate_table[i].dummy_pstate_latency_us;
+
+ context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us;
+ context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us;
+ }
+
+ context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+ if (!pstate_en) {
+ /* The only difference between A and C is p-state latency, if p-state is not supported we want to
+ * calculate DLG based on dummy p-state latency, and max out the set A p-state watermark
+ */
+ context->bw_ctx.bw.dcn.watermarks.a = context->bw_ctx.bw.dcn.watermarks.c;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = 0;
+ } else {
+ /* Set A:
+ * DCFCLK: Min Required
+ * FCLK(proportional to UCLK): 1GHz or Max
+ *
+ * Set A calculated last so that following calculations are based on Set A
+ */
+ dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
+ context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ }
+
+ context->perf_params.stutter_period_us = context->bw_ctx.dml.vba.StutterPeriod;
+
+ /* Make set D = set A until set D is enabled */
+ context->bw_ctx.bw.dcn.watermarks.d = context->bw_ctx.bw.dcn.watermarks.a;
+
+ for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+ if (!context->res_ctx.pipe_ctx[i].stream)
+ continue;
+
+ pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
+ pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+
+ if (dc->config.forced_clocks) {
+ pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
+ pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
+ }
+ if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000)
+ pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
+ if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
+ pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
+
+ pipe_idx++;
+ }
+
+ DC_FP_START();
+ dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
+ DC_FP_END();
+
+ if (!pstate_en)
+ /* Restore full p-state latency */
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us =
+ dc->clk_mgr->bw_params->wm_table.nv_entries[WM_A].dml_input.pstate_latency_us;
+
+}
+
+void dcn30_fpu_update_dram_channel_width_bytes(struct dc *dc)
+{
+ dc_assert_fp_enabled();
+
+ if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
+ dcn3_0_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
+}
+
+void dcn30_fpu_update_max_clk(struct dc_bounding_box_max_clk *dcn30_bb_max_clk)
+{
+ dc_assert_fp_enabled();
+
+ if (!dcn30_bb_max_clk->max_dcfclk_mhz)
+ dcn30_bb_max_clk->max_dcfclk_mhz = dcn3_0_soc.clock_limits[0].dcfclk_mhz;
+ if (!dcn30_bb_max_clk->max_dispclk_mhz)
+ dcn30_bb_max_clk->max_dispclk_mhz = dcn3_0_soc.clock_limits[0].dispclk_mhz;
+ if (!dcn30_bb_max_clk->max_dppclk_mhz)
+ dcn30_bb_max_clk->max_dppclk_mhz = dcn3_0_soc.clock_limits[0].dppclk_mhz;
+ if (!dcn30_bb_max_clk->max_phyclk_mhz)
+ dcn30_bb_max_clk->max_phyclk_mhz = dcn3_0_soc.clock_limits[0].phyclk_mhz;
+}
+
+void dcn30_fpu_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
+ unsigned int *optimal_dcfclk,
+ unsigned int *optimal_fclk)
+{
+ double bw_from_dram, bw_from_dram1, bw_from_dram2;
+
+ dc_assert_fp_enabled();
+
+ bw_from_dram1 = uclk_mts * dcn3_0_soc.num_chans *
+ dcn3_0_soc.dram_channel_width_bytes * (dcn3_0_soc.max_avg_dram_bw_use_normal_percent / 100);
+ bw_from_dram2 = uclk_mts * dcn3_0_soc.num_chans *
+ dcn3_0_soc.dram_channel_width_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100);
+
+ bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
+
+ if (optimal_fclk)
+ *optimal_fclk = bw_from_dram /
+ (dcn3_0_soc.fabric_datapath_to_dcn_data_return_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100));
+
+ if (optimal_dcfclk)
+ *optimal_dcfclk = bw_from_dram /
+ (dcn3_0_soc.return_bus_width_bytes * (dcn3_0_soc.max_avg_sdp_bw_use_normal_percent / 100));
+}
+
+void dcn30_fpu_update_bw_bounding_box(struct dc *dc,
+ struct clk_bw_params *bw_params,
+ struct dc_bounding_box_max_clk *dcn30_bb_max_clk,
+ unsigned int *dcfclk_mhz,
+ unsigned int *dram_speed_mts)
+{
+ unsigned int i;
+
+ dc_assert_fp_enabled();
+
+ dcn3_0_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+ dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+
+ for (i = 0; i < dcn3_0_soc.num_states; i++) {
+ dcn3_0_soc.clock_limits[i].state = i;
+ dcn3_0_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
+ dcn3_0_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
+ dcn3_0_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
+
+ /* Fill all states with max values of all other clocks */
+ dcn3_0_soc.clock_limits[i].dispclk_mhz = dcn30_bb_max_clk->max_dispclk_mhz;
+ dcn3_0_soc.clock_limits[i].dppclk_mhz = dcn30_bb_max_clk->max_dppclk_mhz;
+ dcn3_0_soc.clock_limits[i].phyclk_mhz = dcn30_bb_max_clk->max_phyclk_mhz;
+ dcn3_0_soc.clock_limits[i].dtbclk_mhz = dcn3_0_soc.clock_limits[0].dtbclk_mhz;
+ /* These clocks cannot come from bw_params, always fill from dcn3_0_soc[1] */
+ /* FCLK, PHYCLK_D18, SOCCLK, DSCCLK */
+ dcn3_0_soc.clock_limits[i].phyclk_d18_mhz = dcn3_0_soc.clock_limits[0].phyclk_d18_mhz;
+ dcn3_0_soc.clock_limits[i].socclk_mhz = dcn3_0_soc.clock_limits[0].socclk_mhz;
+ dcn3_0_soc.clock_limits[i].dscclk_mhz = dcn3_0_soc.clock_limits[0].dscclk_mhz;
+ }
+ /* re-init DML with updated bb */
+ dml_init_instance(&dc->dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30);
+ if (dc->current_state)
+ dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_0_soc, &dcn3_0_ip, DML_PROJECT_DCN30);
+
+}
+
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.h
new file mode 100644
index 000000000000..dedfe7b5f173
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn30/dcn30_fpu.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2020-2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN30_FPU_H__
+#define __DCN30_FPU_H__
+
+#include "core_types.h"
+#include "dcn20/dcn20_optc.h"
+
+void optc3_fpu_set_vrr_m_const(struct timing_generator *optc,
+ double vtotal_avg);
+
+void dcn30_fpu_populate_dml_writeback_from_context(
+ struct dc *dc, struct resource_context *res_ctx, display_e2e_pipe_params_st *pipes);
+
+void dcn30_fpu_set_mcif_arb_params(struct mcif_arb_params *wb_arb_params,
+ struct display_mode_lib *dml,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt,
+ int cur_pipe);
+
+void dcn30_fpu_update_soc_for_wm_a(struct dc *dc, struct dc_state *context);
+
+void dcn30_fpu_calculate_wm_and_dlg(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt,
+ int vlevel);
+
+void dcn30_fpu_update_dram_channel_width_bytes(struct dc *dc);
+
+void dcn30_fpu_update_max_clk(struct dc_bounding_box_max_clk *dcn30_bb_max_clk);
+
+void dcn30_fpu_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
+ unsigned int *optimal_dcfclk,
+ unsigned int *optimal_fclk);
+
+void dcn30_fpu_update_bw_bounding_box(struct dc *dc,
+ struct clk_bw_params *bw_params,
+ struct dc_bounding_box_max_clk *dcn30_bb_max_clk,
+ unsigned int *dcfclk_mhz,
+ unsigned int *dram_speed_mts);
+
+
+#endif /* __DCN30_FPU_H__*/
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c
new file mode 100644
index 000000000000..e2bcd205aa93
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.c
@@ -0,0 +1,357 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "resource.h"
+#include "clk_mgr.h"
+#include "dcn20/dcn20_resource.h"
+#include "dcn302/dcn302_resource.h"
+
+#include "dml/dcn20/dcn20_fpu.h"
+#include "dcn302_fpu.h"
+
+struct _vcs_dpi_ip_params_st dcn3_02_ip = {
+ .use_min_dcfclk = 0,
+ .clamp_min_dcfclk = 0,
+ .odm_capable = 1,
+ .gpuvm_enable = 1,
+ .hostvm_enable = 0,
+ .gpuvm_max_page_table_levels = 4,
+ .hostvm_max_page_table_levels = 4,
+ .hostvm_cached_page_table_levels = 0,
+ .pte_group_size_bytes = 2048,
+ .num_dsc = 5,
+ .rob_buffer_size_kbytes = 184,
+ .det_buffer_size_kbytes = 184,
+ .dpte_buffer_size_in_pte_reqs_luma = 64,
+ .dpte_buffer_size_in_pte_reqs_chroma = 34,
+ .pde_proc_buffer_size_64k_reqs = 48,
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .pte_enable = 1,
+ .max_page_table_levels = 2,
+ .pte_chunk_size_kbytes = 2, // ?
+ .meta_chunk_size_kbytes = 2,
+ .writeback_chunk_size_kbytes = 8,
+ .line_buffer_size_bits = 789504,
+ .is_line_buffer_bpp_fixed = 0, // ?
+ .line_buffer_fixed_bpp = 0, // ?
+ .dcc_supported = true,
+ .writeback_interface_buffer_size_kbytes = 90,
+ .writeback_line_buffer_buffer_size = 0,
+ .max_line_buffer_lines = 12,
+ .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640
+ .writeback_chroma_buffer_size_kbytes = 8,
+ .writeback_chroma_line_buffer_width_pixels = 4,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 1,
+ .writeback_max_vscl_taps = 1,
+ .writeback_line_buffer_luma_buffer_size = 0,
+ .writeback_line_buffer_chroma_buffer_size = 14643,
+ .cursor_buffer_size = 8,
+ .cursor_chunk_size = 2,
+ .max_num_otg = 5,
+ .max_num_dpp = 5,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 6,
+ .max_vscl_ratio = 6,
+ .hscl_mults = 4,
+ .vscl_mults = 4,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dispclk_ramp_margin_percent = 1,
+ .underscan_factor = 1.11,
+ .min_vblank_lines = 32,
+ .dppclk_delay_subtotal = 46,
+ .dynamic_metadata_vm_enabled = true,
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_cnvc_formatter = 27,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 119,
+ .dcfclk_cstate_latency = 5.2, // SRExitTime
+ .max_inter_dcn_tile_repeaters = 8,
+ .max_num_hdmi_frl_outputs = 1,
+ .odm_combine_4to1_supported = true,
+
+ .xfc_supported = false,
+ .xfc_fill_bw_overhead_percent = 10.0,
+ .xfc_fill_constant_bytes = 0,
+ .gfx7_compat_tiling_supported = 0,
+ .number_of_cursors = 1,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_02_soc = {
+ .clock_limits = {
+ {
+ .state = 0,
+ .dispclk_mhz = 562.0,
+ .dppclk_mhz = 300.0,
+ .phyclk_mhz = 300.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 405.6,
+ },
+ },
+
+ .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */
+ .num_states = 1,
+ .sr_exit_time_us = 26.5,
+ .sr_enter_plus_exit_time_us = 31,
+ .urgent_latency_us = 4.0,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
+ .max_avg_sdp_bw_use_normal_percent = 60.0,
+ .max_avg_dram_bw_use_normal_percent = 40.0,
+ .writeback_latency_us = 12.0,
+ .max_request_size_bytes = 256,
+ .fabric_datapath_to_dcn_data_return_bytes = 64,
+ .dcn_downspread_percent = 0.5,
+ .downspread_percent = 0.38,
+ .dram_page_open_time_ns = 50.0,
+ .dram_rw_turnaround_time_ns = 17.5,
+ .dram_return_buffer_per_channel_bytes = 8192,
+ .round_trip_ping_latency_dcfclk_cycles = 156,
+ .urgent_out_of_order_return_per_channel_bytes = 4096,
+ .channel_interleave_bytes = 256,
+ .num_banks = 8,
+ .gpuvm_min_page_size_bytes = 4096,
+ .hostvm_min_page_size_bytes = 4096,
+ .dram_clock_change_latency_us = 404,
+ .dummy_pstate_latency_us = 5,
+ .writeback_dram_clock_change_latency_us = 23.0,
+ .return_bus_width_bytes = 64,
+ .dispclk_dppclk_vco_speed_mhz = 3650,
+ .xfc_bus_transport_time_us = 20, // ?
+ .xfc_xbuf_latency_tolerance_us = 4, // ?
+ .use_urgent_burst_bw = 1, // ?
+ .do_urgent_latency_adjustment = true,
+ .urgent_latency_adjustment_fabric_clock_component_us = 1.0,
+ .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
+};
+
+static void dcn302_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
+ unsigned int *optimal_dcfclk,
+ unsigned int *optimal_fclk)
+{
+
+ double bw_from_dram, bw_from_dram1, bw_from_dram2;
+
+ bw_from_dram1 = uclk_mts * dcn3_02_soc.num_chans *
+ dcn3_02_soc.dram_channel_width_bytes *
+ (dcn3_02_soc.max_avg_dram_bw_use_normal_percent / 100);
+ bw_from_dram2 = uclk_mts * dcn3_02_soc.num_chans *
+ dcn3_02_soc.dram_channel_width_bytes *
+ (dcn3_02_soc.max_avg_sdp_bw_use_normal_percent / 100);
+
+ bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
+
+ if (optimal_fclk)
+ *optimal_fclk = bw_from_dram /
+ (dcn3_02_soc.fabric_datapath_to_dcn_data_return_bytes *
+ (dcn3_02_soc.max_avg_sdp_bw_use_normal_percent / 100));
+
+ if (optimal_dcfclk)
+ *optimal_dcfclk = bw_from_dram /
+ (dcn3_02_soc.return_bus_width_bytes *
+ (dcn3_02_soc.max_avg_sdp_bw_use_normal_percent / 100));
+}
+
+void dcn302_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+ unsigned int i, j;
+ unsigned int num_states = 0;
+
+ unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0};
+ unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0};
+ unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0};
+ unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0};
+
+ unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {694, 875, 1000, 1200};
+ unsigned int num_dcfclk_sta_targets = 4;
+ unsigned int num_uclk_states;
+
+ dc_assert_fp_enabled();
+
+ if (dc->ctx->dc_bios->vram_info.num_chans)
+ dcn3_02_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
+
+ if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
+ dcn3_02_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
+
+ dcn3_02_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+ dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+
+ if (bw_params->clk_table.entries[0].memclk_mhz) {
+ int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
+
+ for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
+ if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
+ max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
+ if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
+ max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
+ if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
+ max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
+ if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
+ max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
+ }
+ if (!max_dcfclk_mhz)
+ max_dcfclk_mhz = dcn3_02_soc.clock_limits[0].dcfclk_mhz;
+ if (!max_dispclk_mhz)
+ max_dispclk_mhz = dcn3_02_soc.clock_limits[0].dispclk_mhz;
+ if (!max_dppclk_mhz)
+ max_dppclk_mhz = dcn3_02_soc.clock_limits[0].dppclk_mhz;
+ if (!max_phyclk_mhz)
+ max_phyclk_mhz = dcn3_02_soc.clock_limits[0].phyclk_mhz;
+
+ if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+ /* If max DCFCLK is greater than the max DCFCLK STA target, insert into the DCFCLK STA target array */
+ dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
+ num_dcfclk_sta_targets++;
+ } else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+ /* If max DCFCLK is less than the max DCFCLK STA target, cap values and remove duplicates */
+ for (i = 0; i < num_dcfclk_sta_targets; i++) {
+ if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
+ dcfclk_sta_targets[i] = max_dcfclk_mhz;
+ break;
+ }
+ }
+ /* Update size of array since we "removed" duplicates */
+ num_dcfclk_sta_targets = i + 1;
+ }
+
+ num_uclk_states = bw_params->clk_table.num_entries;
+
+ /* Calculate optimal dcfclk for each uclk */
+ for (i = 0; i < num_uclk_states; i++) {
+ dcn302_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
+ &optimal_dcfclk_for_uclk[i], NULL);
+ if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz)
+ optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz;
+ }
+
+ /* Calculate optimal uclk for each dcfclk sta target */
+ for (i = 0; i < num_dcfclk_sta_targets; i++) {
+ for (j = 0; j < num_uclk_states; j++) {
+ if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) {
+ optimal_uclk_for_dcfclk_sta_targets[i] =
+ bw_params->clk_table.entries[j].memclk_mhz * 16;
+ break;
+ }
+ }
+ }
+
+ i = 0;
+ j = 0;
+ /* create the final dcfclk and uclk table */
+ while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) {
+ if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) {
+ dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
+ dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
+ } else {
+ if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+ dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
+ dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
+ } else {
+ j = num_uclk_states;
+ }
+ }
+ }
+
+ while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) {
+ dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
+ dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
+ }
+
+ while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
+ optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+ dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
+ dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
+ }
+
+ dcn3_02_soc.num_states = num_states;
+ for (i = 0; i < dcn3_02_soc.num_states; i++) {
+ dcn3_02_soc.clock_limits[i].state = i;
+ dcn3_02_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
+ dcn3_02_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
+ dcn3_02_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
+
+ /* Fill all states with max values of all other clocks */
+ dcn3_02_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
+ dcn3_02_soc.clock_limits[i].dppclk_mhz = max_dppclk_mhz;
+ dcn3_02_soc.clock_limits[i].phyclk_mhz = max_phyclk_mhz;
+ /* Populate from bw_params for DTBCLK, SOCCLK */
+ if (!bw_params->clk_table.entries[i].dtbclk_mhz && i > 0)
+ dcn3_02_soc.clock_limits[i].dtbclk_mhz = dcn3_02_soc.clock_limits[i-1].dtbclk_mhz;
+ else
+ dcn3_02_soc.clock_limits[i].dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
+ if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
+ dcn3_02_soc.clock_limits[i].socclk_mhz = dcn3_02_soc.clock_limits[i-1].socclk_mhz;
+ else
+ dcn3_02_soc.clock_limits[i].socclk_mhz = bw_params->clk_table.entries[i].socclk_mhz;
+ /* These clocks cannot come from bw_params, always fill from dcn3_02_soc[1] */
+ /* FCLK, PHYCLK_D18, DSCCLK */
+ dcn3_02_soc.clock_limits[i].phyclk_d18_mhz = dcn3_02_soc.clock_limits[0].phyclk_d18_mhz;
+ dcn3_02_soc.clock_limits[i].dscclk_mhz = dcn3_02_soc.clock_limits[0].dscclk_mhz;
+ }
+ /* re-init DML with updated bb */
+ dml_init_instance(&dc->dml, &dcn3_02_soc, &dcn3_02_ip, DML_PROJECT_DCN30);
+ if (dc->current_state)
+ dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_02_soc, &dcn3_02_ip, DML_PROJECT_DCN30);
+ }
+}
+
+void dcn302_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info)
+{
+
+ dc_assert_fp_enabled();
+
+ if (bb_info.dram_clock_change_latency_100ns > 0)
+ dcn3_02_soc.dram_clock_change_latency_us =
+ bb_info.dram_clock_change_latency_100ns * 10;
+
+ if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
+ dcn3_02_soc.sr_enter_plus_exit_time_us =
+ bb_info.dram_sr_enter_exit_latency_100ns * 10;
+
+ if (bb_info.dram_sr_exit_latency_100ns > 0)
+ dcn3_02_soc.sr_exit_time_us =
+ bb_info.dram_sr_exit_latency_100ns * 10;
+}
+
+
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.h
new file mode 100644
index 000000000000..548305d96cee
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn302/dcn302_fpu.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019-2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN302_FPU_H__
+#define __DCN302_FPU_H__
+
+void dcn302_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info);
+void dcn302_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+
+#endif /* __DCN302_FPU_H__*/
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c
new file mode 100644
index 000000000000..8fb14baed208
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2019-2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "resource.h"
+#include "clk_mgr.h"
+#include "dcn20/dcn20_resource.h"
+#include "dcn303/dcn303_resource.h"
+
+#include "dml/dcn20/dcn20_fpu.h"
+#include "dcn303_fpu.h"
+
+struct _vcs_dpi_ip_params_st dcn3_03_ip = {
+ .use_min_dcfclk = 0,
+ .clamp_min_dcfclk = 0,
+ .odm_capable = 1,
+ .gpuvm_enable = 1,
+ .hostvm_enable = 0,
+ .gpuvm_max_page_table_levels = 4,
+ .hostvm_max_page_table_levels = 4,
+ .hostvm_cached_page_table_levels = 0,
+ .pte_group_size_bytes = 2048,
+ .num_dsc = 2,
+ .rob_buffer_size_kbytes = 184,
+ .det_buffer_size_kbytes = 184,
+ .dpte_buffer_size_in_pte_reqs_luma = 64,
+ .dpte_buffer_size_in_pte_reqs_chroma = 34,
+ .pde_proc_buffer_size_64k_reqs = 48,
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .pte_enable = 1,
+ .max_page_table_levels = 2,
+ .pte_chunk_size_kbytes = 2, // ?
+ .meta_chunk_size_kbytes = 2,
+ .writeback_chunk_size_kbytes = 8,
+ .line_buffer_size_bits = 789504,
+ .is_line_buffer_bpp_fixed = 0, // ?
+ .line_buffer_fixed_bpp = 0, // ?
+ .dcc_supported = true,
+ .writeback_interface_buffer_size_kbytes = 90,
+ .writeback_line_buffer_buffer_size = 0,
+ .max_line_buffer_lines = 12,
+ .writeback_luma_buffer_size_kbytes = 12, // writeback_line_buffer_buffer_size = 656640
+ .writeback_chroma_buffer_size_kbytes = 8,
+ .writeback_chroma_line_buffer_width_pixels = 4,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 1,
+ .writeback_max_vscl_taps = 1,
+ .writeback_line_buffer_luma_buffer_size = 0,
+ .writeback_line_buffer_chroma_buffer_size = 14643,
+ .cursor_buffer_size = 8,
+ .cursor_chunk_size = 2,
+ .max_num_otg = 2,
+ .max_num_dpp = 2,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 6,
+ .max_vscl_ratio = 6,
+ .hscl_mults = 4,
+ .vscl_mults = 4,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dispclk_ramp_margin_percent = 1,
+ .underscan_factor = 1.11,
+ .min_vblank_lines = 32,
+ .dppclk_delay_subtotal = 46,
+ .dynamic_metadata_vm_enabled = true,
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_cnvc_formatter = 27,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 119,
+ .dcfclk_cstate_latency = 5.2, // SRExitTime
+ .max_inter_dcn_tile_repeaters = 8,
+ .max_num_hdmi_frl_outputs = 1,
+ .odm_combine_4to1_supported = false,
+
+ .xfc_supported = false,
+ .xfc_fill_bw_overhead_percent = 10.0,
+ .xfc_fill_constant_bytes = 0,
+ .gfx7_compat_tiling_supported = 0,
+ .number_of_cursors = 1,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_03_soc = {
+ .clock_limits = {
+ {
+ .state = 0,
+ .dispclk_mhz = 562.0,
+ .dppclk_mhz = 300.0,
+ .phyclk_mhz = 300.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 405.6,
+ },
+ },
+
+ .min_dcfclk = 500.0, /* TODO: set this to actual min DCFCLK */
+ .num_states = 1,
+ .sr_exit_time_us = 35.5,
+ .sr_enter_plus_exit_time_us = 40,
+ .urgent_latency_us = 4.0,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 80.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 40.0,
+ .max_avg_sdp_bw_use_normal_percent = 60.0,
+ .max_avg_dram_bw_use_normal_percent = 40.0,
+ .writeback_latency_us = 12.0,
+ .max_request_size_bytes = 256,
+ .fabric_datapath_to_dcn_data_return_bytes = 64,
+ .dcn_downspread_percent = 0.5,
+ .downspread_percent = 0.38,
+ .dram_page_open_time_ns = 50.0,
+ .dram_rw_turnaround_time_ns = 17.5,
+ .dram_return_buffer_per_channel_bytes = 8192,
+ .round_trip_ping_latency_dcfclk_cycles = 156,
+ .urgent_out_of_order_return_per_channel_bytes = 4096,
+ .channel_interleave_bytes = 256,
+ .num_banks = 8,
+ .gpuvm_min_page_size_bytes = 4096,
+ .hostvm_min_page_size_bytes = 4096,
+ .dram_clock_change_latency_us = 404,
+ .dummy_pstate_latency_us = 5,
+ .writeback_dram_clock_change_latency_us = 23.0,
+ .return_bus_width_bytes = 64,
+ .dispclk_dppclk_vco_speed_mhz = 3650,
+ .xfc_bus_transport_time_us = 20, // ?
+ .xfc_xbuf_latency_tolerance_us = 4, // ?
+ .use_urgent_burst_bw = 1, // ?
+ .do_urgent_latency_adjustment = true,
+ .urgent_latency_adjustment_fabric_clock_component_us = 1.0,
+ .urgent_latency_adjustment_fabric_clock_reference_mhz = 1000,
+};
+
+static void dcn303_get_optimal_dcfclk_fclk_for_uclk(unsigned int uclk_mts,
+ unsigned int *optimal_dcfclk,
+ unsigned int *optimal_fclk)
+{
+ double bw_from_dram, bw_from_dram1, bw_from_dram2;
+
+ bw_from_dram1 = uclk_mts * dcn3_03_soc.num_chans *
+ dcn3_03_soc.dram_channel_width_bytes * (dcn3_03_soc.max_avg_dram_bw_use_normal_percent / 100);
+ bw_from_dram2 = uclk_mts * dcn3_03_soc.num_chans *
+ dcn3_03_soc.dram_channel_width_bytes * (dcn3_03_soc.max_avg_sdp_bw_use_normal_percent / 100);
+
+ bw_from_dram = (bw_from_dram1 < bw_from_dram2) ? bw_from_dram1 : bw_from_dram2;
+
+ if (optimal_fclk)
+ *optimal_fclk = bw_from_dram /
+ (dcn3_03_soc.fabric_datapath_to_dcn_data_return_bytes *
+ (dcn3_03_soc.max_avg_sdp_bw_use_normal_percent / 100));
+
+ if (optimal_dcfclk)
+ *optimal_dcfclk = bw_from_dram /
+ (dcn3_03_soc.return_bus_width_bytes * (dcn3_03_soc.max_avg_sdp_bw_use_normal_percent / 100));
+}
+
+
+void dcn303_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+ unsigned int i, j;
+ unsigned int num_states = 0;
+
+ unsigned int dcfclk_mhz[DC__VOLTAGE_STATES] = {0};
+ unsigned int dram_speed_mts[DC__VOLTAGE_STATES] = {0};
+ unsigned int optimal_uclk_for_dcfclk_sta_targets[DC__VOLTAGE_STATES] = {0};
+ unsigned int optimal_dcfclk_for_uclk[DC__VOLTAGE_STATES] = {0};
+
+ unsigned int dcfclk_sta_targets[DC__VOLTAGE_STATES] = {694, 875, 1000, 1200};
+ unsigned int num_dcfclk_sta_targets = 4;
+ unsigned int num_uclk_states;
+
+ dc_assert_fp_enabled();
+
+ if (dc->ctx->dc_bios->vram_info.num_chans)
+ dcn3_03_soc.num_chans = dc->ctx->dc_bios->vram_info.num_chans;
+
+ if (dc->ctx->dc_bios->vram_info.dram_channel_width_bytes)
+ dcn3_03_soc.dram_channel_width_bytes = dc->ctx->dc_bios->vram_info.dram_channel_width_bytes;
+
+ dcn3_03_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+ dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+
+ if (bw_params->clk_table.entries[0].memclk_mhz) {
+ int max_dcfclk_mhz = 0, max_dispclk_mhz = 0, max_dppclk_mhz = 0, max_phyclk_mhz = 0;
+
+ for (i = 0; i < MAX_NUM_DPM_LVL; i++) {
+ if (bw_params->clk_table.entries[i].dcfclk_mhz > max_dcfclk_mhz)
+ max_dcfclk_mhz = bw_params->clk_table.entries[i].dcfclk_mhz;
+ if (bw_params->clk_table.entries[i].dispclk_mhz > max_dispclk_mhz)
+ max_dispclk_mhz = bw_params->clk_table.entries[i].dispclk_mhz;
+ if (bw_params->clk_table.entries[i].dppclk_mhz > max_dppclk_mhz)
+ max_dppclk_mhz = bw_params->clk_table.entries[i].dppclk_mhz;
+ if (bw_params->clk_table.entries[i].phyclk_mhz > max_phyclk_mhz)
+ max_phyclk_mhz = bw_params->clk_table.entries[i].phyclk_mhz;
+ }
+ if (!max_dcfclk_mhz)
+ max_dcfclk_mhz = dcn3_03_soc.clock_limits[0].dcfclk_mhz;
+ if (!max_dispclk_mhz)
+ max_dispclk_mhz = dcn3_03_soc.clock_limits[0].dispclk_mhz;
+ if (!max_dppclk_mhz)
+ max_dppclk_mhz = dcn3_03_soc.clock_limits[0].dppclk_mhz;
+ if (!max_phyclk_mhz)
+ max_phyclk_mhz = dcn3_03_soc.clock_limits[0].phyclk_mhz;
+
+ if (max_dcfclk_mhz > dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+ dcfclk_sta_targets[num_dcfclk_sta_targets] = max_dcfclk_mhz;
+ num_dcfclk_sta_targets++;
+ } else if (max_dcfclk_mhz < dcfclk_sta_targets[num_dcfclk_sta_targets-1]) {
+ for (i = 0; i < num_dcfclk_sta_targets; i++) {
+ if (dcfclk_sta_targets[i] > max_dcfclk_mhz) {
+ dcfclk_sta_targets[i] = max_dcfclk_mhz;
+ break;
+ }
+ }
+ /* Update size of array since we "removed" duplicates */
+ num_dcfclk_sta_targets = i + 1;
+ }
+
+ num_uclk_states = bw_params->clk_table.num_entries;
+
+ /* Calculate optimal dcfclk for each uclk */
+ for (i = 0; i < num_uclk_states; i++) {
+ dcn303_get_optimal_dcfclk_fclk_for_uclk(bw_params->clk_table.entries[i].memclk_mhz * 16,
+ &optimal_dcfclk_for_uclk[i], NULL);
+ if (optimal_dcfclk_for_uclk[i] < bw_params->clk_table.entries[0].dcfclk_mhz)
+ optimal_dcfclk_for_uclk[i] = bw_params->clk_table.entries[0].dcfclk_mhz;
+ }
+
+ /* Calculate optimal uclk for each dcfclk sta target */
+ for (i = 0; i < num_dcfclk_sta_targets; i++) {
+ for (j = 0; j < num_uclk_states; j++) {
+ if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j]) {
+ optimal_uclk_for_dcfclk_sta_targets[i] =
+ bw_params->clk_table.entries[j].memclk_mhz * 16;
+ break;
+ }
+ }
+ }
+
+ i = 0;
+ j = 0;
+ /* create the final dcfclk and uclk table */
+ while (i < num_dcfclk_sta_targets && j < num_uclk_states && num_states < DC__VOLTAGE_STATES) {
+ if (dcfclk_sta_targets[i] < optimal_dcfclk_for_uclk[j] && i < num_dcfclk_sta_targets) {
+ dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
+ dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
+ } else {
+ if (j < num_uclk_states && optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+ dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
+ dram_speed_mts[num_states++] =
+ bw_params->clk_table.entries[j++].memclk_mhz * 16;
+ } else {
+ j = num_uclk_states;
+ }
+ }
+ }
+
+ while (i < num_dcfclk_sta_targets && num_states < DC__VOLTAGE_STATES) {
+ dcfclk_mhz[num_states] = dcfclk_sta_targets[i];
+ dram_speed_mts[num_states++] = optimal_uclk_for_dcfclk_sta_targets[i++];
+ }
+
+ while (j < num_uclk_states && num_states < DC__VOLTAGE_STATES &&
+ optimal_dcfclk_for_uclk[j] <= max_dcfclk_mhz) {
+ dcfclk_mhz[num_states] = optimal_dcfclk_for_uclk[j];
+ dram_speed_mts[num_states++] = bw_params->clk_table.entries[j++].memclk_mhz * 16;
+ }
+
+ dcn3_03_soc.num_states = num_states;
+ for (i = 0; i < dcn3_03_soc.num_states; i++) {
+ dcn3_03_soc.clock_limits[i].state = i;
+ dcn3_03_soc.clock_limits[i].dcfclk_mhz = dcfclk_mhz[i];
+ dcn3_03_soc.clock_limits[i].fabricclk_mhz = dcfclk_mhz[i];
+ dcn3_03_soc.clock_limits[i].dram_speed_mts = dram_speed_mts[i];
+
+ /* Fill all states with max values of all other clocks */
+ dcn3_03_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
+ dcn3_03_soc.clock_limits[i].dppclk_mhz = max_dppclk_mhz;
+ dcn3_03_soc.clock_limits[i].phyclk_mhz = max_phyclk_mhz;
+ /* Populate from bw_params for DTBCLK, SOCCLK */
+ if (!bw_params->clk_table.entries[i].dtbclk_mhz && i > 0)
+ dcn3_03_soc.clock_limits[i].dtbclk_mhz = dcn3_03_soc.clock_limits[i-1].dtbclk_mhz;
+ else
+ dcn3_03_soc.clock_limits[i].dtbclk_mhz = bw_params->clk_table.entries[i].dtbclk_mhz;
+ if (!bw_params->clk_table.entries[i].socclk_mhz && i > 0)
+ dcn3_03_soc.clock_limits[i].socclk_mhz = dcn3_03_soc.clock_limits[i-1].socclk_mhz;
+ else
+ dcn3_03_soc.clock_limits[i].socclk_mhz = bw_params->clk_table.entries[i].socclk_mhz;
+ /* These clocks cannot come from bw_params, always fill from dcn3_03_soc[1] */
+ /* FCLK, PHYCLK_D18, DSCCLK */
+ dcn3_03_soc.clock_limits[i].phyclk_d18_mhz = dcn3_03_soc.clock_limits[0].phyclk_d18_mhz;
+ dcn3_03_soc.clock_limits[i].dscclk_mhz = dcn3_03_soc.clock_limits[0].dscclk_mhz;
+ }
+
+ if (dcn3_03_soc.num_chans <= 4) {
+ for (i = 0; i < dcn3_03_soc.num_states; i++) {
+ if (dcn3_03_soc.clock_limits[i].dram_speed_mts > 1700)
+ break;
+
+ if (dcn3_03_soc.clock_limits[i].dram_speed_mts >= 1500) {
+ dcn3_03_soc.clock_limits[i].dcfclk_mhz = 100;
+ dcn3_03_soc.clock_limits[i].fabricclk_mhz = 100;
+ }
+ }
+ }
+
+ /* re-init DML with updated bb */
+ dml_init_instance(&dc->dml, &dcn3_03_soc, &dcn3_03_ip, DML_PROJECT_DCN30);
+ if (dc->current_state)
+ dml_init_instance(&dc->current_state->bw_ctx.dml, &dcn3_03_soc, &dcn3_03_ip, DML_PROJECT_DCN30);
+ }
+}
+
+void dcn303_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info)
+{
+ dc_assert_fp_enabled();
+
+ if (bb_info.dram_clock_change_latency_100ns > 0)
+ dcn3_03_soc.dram_clock_change_latency_us =
+ bb_info.dram_clock_change_latency_100ns * 10;
+
+ if (bb_info.dram_sr_enter_exit_latency_100ns > 0)
+ dcn3_03_soc.sr_enter_plus_exit_time_us =
+ bb_info.dram_sr_enter_exit_latency_100ns * 10;
+
+ if (bb_info.dram_sr_exit_latency_100ns > 0)
+ dcn3_03_soc.sr_exit_time_us =
+ bb_info.dram_sr_exit_latency_100ns * 10;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.h
new file mode 100644
index 000000000000..92ec833fa528
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn303/dcn303_fpu.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019-2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN303_FPU_H__
+#define __DCN303_FPU_H__
+
+void dcn303_fpu_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+void dcn303_fpu_init_soc_bounding_box(struct bp_soc_bb_info bb_info);
+
+#endif /* __DCN303_FPU_H__*/
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
new file mode 100644
index 000000000000..54db2eca9e6b
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright 2019-2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "resource.h"
+#include "clk_mgr.h"
+
+#include "dml/dcn20/dcn20_fpu.h"
+#include "dcn31_fpu.h"
+
+/**
+ * DOC: DCN31x FPU manipulation Overview
+ *
+ * The DCN architecture relies on FPU operations, which require special
+ * compilation flags and the use of kernel_fpu_begin/end functions; ideally, we
+ * want to avoid spreading FPU access across multiple files. With this idea in
+ * mind, this file aims to centralize all DCN3.1.x functions that require FPU
+ * access in a single place. Code in this file follows the following code
+ * pattern:
+ *
+ * 1. Functions that use FPU operations should be isolated in static functions.
+ * 2. The FPU functions should have the noinline attribute to ensure anything
+ * that deals with FP register is contained within this call.
+ * 3. All function that needs to be accessed outside this file requires a
+ * public interface that not uses any FPU reference.
+ * 4. Developers **must not** use DC_FP_START/END in this file, but they need
+ * to ensure that the caller invokes it before access any function available
+ * in this file. For this reason, public functions in this file must invoke
+ * dc_assert_fp_enabled();
+ */
+
+struct _vcs_dpi_ip_params_st dcn3_1_ip = {
+ .gpuvm_enable = 1,
+ .gpuvm_max_page_table_levels = 1,
+ .hostvm_enable = 1,
+ .hostvm_max_page_table_levels = 2,
+ .rob_buffer_size_kbytes = 64,
+ .det_buffer_size_kbytes = DCN3_1_DEFAULT_DET_SIZE,
+ .config_return_buffer_size_in_kbytes = 1792,
+ .compressed_buffer_segment_size_in_kbytes = 64,
+ .meta_fifo_size_in_kentries = 32,
+ .zero_size_buffer_entries = 512,
+ .compbuf_reserved_space_64b = 256,
+ .compbuf_reserved_space_zs = 64,
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .meta_chunk_size_kbytes = 2,
+ .min_meta_chunk_size_bytes = 256,
+ .writeback_chunk_size_kbytes = 8,
+ .ptoi_supported = false,
+ .num_dsc = 3,
+ .maximum_dsc_bits_per_component = 10,
+ .dsc422_native_support = false,
+ .is_line_buffer_bpp_fixed = true,
+ .line_buffer_fixed_bpp = 48,
+ .line_buffer_size_bits = 789504,
+ .max_line_buffer_lines = 12,
+ .writeback_interface_buffer_size_kbytes = 90,
+ .max_num_dpp = 4,
+ .max_num_otg = 4,
+ .max_num_hdmi_frl_outputs = 1,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 6,
+ .max_vscl_ratio = 6,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dpte_buffer_size_in_pte_reqs_luma = 64,
+ .dpte_buffer_size_in_pte_reqs_chroma = 34,
+ .dispclk_ramp_margin_percent = 1,
+ .max_inter_dcn_tile_repeaters = 8,
+ .cursor_buffer_size = 16,
+ .cursor_chunk_size = 2,
+ .writeback_line_buffer_buffer_size = 0,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 1,
+ .writeback_max_vscl_taps = 1,
+ .dppclk_delay_subtotal = 46,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_cnvc_formatter = 27,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 119,
+ .dynamic_metadata_vm_enabled = false,
+ .odm_combine_4to1_supported = false,
+ .dcc_supported = true,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_1_soc = {
+ /*TODO: correct dispclk/dppclk voltage level determination*/
+ .clock_limits = {
+ {
+ .state = 0,
+ .dispclk_mhz = 1200.0,
+ .dppclk_mhz = 1200.0,
+ .phyclk_mhz = 600.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 186.0,
+ .dtbclk_mhz = 625.0,
+ },
+ {
+ .state = 1,
+ .dispclk_mhz = 1200.0,
+ .dppclk_mhz = 1200.0,
+ .phyclk_mhz = 810.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 209.0,
+ .dtbclk_mhz = 625.0,
+ },
+ {
+ .state = 2,
+ .dispclk_mhz = 1200.0,
+ .dppclk_mhz = 1200.0,
+ .phyclk_mhz = 810.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 209.0,
+ .dtbclk_mhz = 625.0,
+ },
+ {
+ .state = 3,
+ .dispclk_mhz = 1200.0,
+ .dppclk_mhz = 1200.0,
+ .phyclk_mhz = 810.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 371.0,
+ .dtbclk_mhz = 625.0,
+ },
+ {
+ .state = 4,
+ .dispclk_mhz = 1200.0,
+ .dppclk_mhz = 1200.0,
+ .phyclk_mhz = 810.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 417.0,
+ .dtbclk_mhz = 625.0,
+ },
+ },
+ .num_states = 5,
+ .sr_exit_time_us = 9.0,
+ .sr_enter_plus_exit_time_us = 11.0,
+ .sr_exit_z8_time_us = 442.0,
+ .sr_enter_plus_exit_z8_time_us = 560.0,
+ .writeback_latency_us = 12.0,
+ .dram_channel_width_bytes = 4,
+ .round_trip_ping_latency_dcfclk_cycles = 106,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_sdp_bw_after_urgent = 80.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 65.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0,
+ .max_avg_sdp_bw_use_normal_percent = 60.0,
+ .max_avg_dram_bw_use_normal_percent = 60.0,
+ .fabric_datapath_to_dcn_data_return_bytes = 32,
+ .return_bus_width_bytes = 64,
+ .downspread_percent = 0.38,
+ .dcn_downspread_percent = 0.5,
+ .gpuvm_min_page_size_bytes = 4096,
+ .hostvm_min_page_size_bytes = 4096,
+ .do_urgent_latency_adjustment = false,
+ .urgent_latency_adjustment_fabric_clock_component_us = 0,
+ .urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
+};
+
+struct _vcs_dpi_ip_params_st dcn3_15_ip = {
+ .gpuvm_enable = 1,
+ .gpuvm_max_page_table_levels = 1,
+ .hostvm_enable = 1,
+ .hostvm_max_page_table_levels = 2,
+ .rob_buffer_size_kbytes = 64,
+ .det_buffer_size_kbytes = DCN3_15_DEFAULT_DET_SIZE,
+ .min_comp_buffer_size_kbytes = DCN3_15_MIN_COMPBUF_SIZE_KB,
+ .config_return_buffer_size_in_kbytes = 1024,
+ .compressed_buffer_segment_size_in_kbytes = 64,
+ .meta_fifo_size_in_kentries = 32,
+ .zero_size_buffer_entries = 512,
+ .compbuf_reserved_space_64b = 256,
+ .compbuf_reserved_space_zs = 64,
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .meta_chunk_size_kbytes = 2,
+ .min_meta_chunk_size_bytes = 256,
+ .writeback_chunk_size_kbytes = 8,
+ .ptoi_supported = false,
+ .num_dsc = 3,
+ .maximum_dsc_bits_per_component = 10,
+ .dsc422_native_support = false,
+ .is_line_buffer_bpp_fixed = true,
+ .line_buffer_fixed_bpp = 49,
+ .line_buffer_size_bits = 789504,
+ .max_line_buffer_lines = 12,
+ .writeback_interface_buffer_size_kbytes = 90,
+ .max_num_dpp = 4,
+ .max_num_otg = 4,
+ .max_num_hdmi_frl_outputs = 1,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 6,
+ .max_vscl_ratio = 6,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dpte_buffer_size_in_pte_reqs_luma = 64,
+ .dpte_buffer_size_in_pte_reqs_chroma = 34,
+ .dispclk_ramp_margin_percent = 1,
+ .max_inter_dcn_tile_repeaters = 9,
+ .cursor_buffer_size = 16,
+ .cursor_chunk_size = 2,
+ .writeback_line_buffer_buffer_size = 0,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 1,
+ .writeback_max_vscl_taps = 1,
+ .dppclk_delay_subtotal = 46,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_cnvc_formatter = 27,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 119,
+ .dynamic_metadata_vm_enabled = false,
+ .odm_combine_4to1_supported = false,
+ .dcc_supported = true,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_15_soc = {
+ .sr_exit_time_us = 9.0,
+ .sr_enter_plus_exit_time_us = 11.0,
+ .sr_exit_z8_time_us = 50.0,
+ .sr_enter_plus_exit_z8_time_us = 50.0,
+ .writeback_latency_us = 12.0,
+ .dram_channel_width_bytes = 4,
+ .round_trip_ping_latency_dcfclk_cycles = 106,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_sdp_bw_after_urgent = 80.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 65.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0,
+ .max_avg_sdp_bw_use_normal_percent = 60.0,
+ .max_avg_dram_bw_use_normal_percent = 60.0,
+ .fabric_datapath_to_dcn_data_return_bytes = 32,
+ .return_bus_width_bytes = 64,
+ .downspread_percent = 0.38,
+ .dcn_downspread_percent = 0.38,
+ .gpuvm_min_page_size_bytes = 4096,
+ .hostvm_min_page_size_bytes = 4096,
+ .do_urgent_latency_adjustment = false,
+ .urgent_latency_adjustment_fabric_clock_component_us = 0,
+ .urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
+};
+
+struct _vcs_dpi_ip_params_st dcn3_16_ip = {
+ .gpuvm_enable = 1,
+ .gpuvm_max_page_table_levels = 1,
+ .hostvm_enable = 1,
+ .hostvm_max_page_table_levels = 2,
+ .rob_buffer_size_kbytes = 64,
+ .det_buffer_size_kbytes = DCN3_16_DEFAULT_DET_SIZE,
+ .config_return_buffer_size_in_kbytes = 1024,
+ .compressed_buffer_segment_size_in_kbytes = 64,
+ .meta_fifo_size_in_kentries = 32,
+ .zero_size_buffer_entries = 512,
+ .compbuf_reserved_space_64b = 256,
+ .compbuf_reserved_space_zs = 64,
+ .dpp_output_buffer_pixels = 2560,
+ .opp_output_buffer_lines = 1,
+ .pixel_chunk_size_kbytes = 8,
+ .meta_chunk_size_kbytes = 2,
+ .min_meta_chunk_size_bytes = 256,
+ .writeback_chunk_size_kbytes = 8,
+ .ptoi_supported = false,
+ .num_dsc = 3,
+ .maximum_dsc_bits_per_component = 10,
+ .dsc422_native_support = false,
+ .is_line_buffer_bpp_fixed = true,
+ .line_buffer_fixed_bpp = 48,
+ .line_buffer_size_bits = 789504,
+ .max_line_buffer_lines = 12,
+ .writeback_interface_buffer_size_kbytes = 90,
+ .max_num_dpp = 4,
+ .max_num_otg = 4,
+ .max_num_hdmi_frl_outputs = 1,
+ .max_num_wb = 1,
+ .max_dchub_pscl_bw_pix_per_clk = 4,
+ .max_pscl_lb_bw_pix_per_clk = 2,
+ .max_lb_vscl_bw_pix_per_clk = 4,
+ .max_vscl_hscl_bw_pix_per_clk = 4,
+ .max_hscl_ratio = 6,
+ .max_vscl_ratio = 6,
+ .max_hscl_taps = 8,
+ .max_vscl_taps = 8,
+ .dpte_buffer_size_in_pte_reqs_luma = 64,
+ .dpte_buffer_size_in_pte_reqs_chroma = 34,
+ .dispclk_ramp_margin_percent = 1,
+ .max_inter_dcn_tile_repeaters = 8,
+ .cursor_buffer_size = 16,
+ .cursor_chunk_size = 2,
+ .writeback_line_buffer_buffer_size = 0,
+ .writeback_min_hscl_ratio = 1,
+ .writeback_min_vscl_ratio = 1,
+ .writeback_max_hscl_ratio = 1,
+ .writeback_max_vscl_ratio = 1,
+ .writeback_max_hscl_taps = 1,
+ .writeback_max_vscl_taps = 1,
+ .dppclk_delay_subtotal = 46,
+ .dppclk_delay_scl = 50,
+ .dppclk_delay_scl_lb_only = 16,
+ .dppclk_delay_cnvc_formatter = 27,
+ .dppclk_delay_cnvc_cursor = 6,
+ .dispclk_delay_subtotal = 119,
+ .dynamic_metadata_vm_enabled = false,
+ .odm_combine_4to1_supported = false,
+ .dcc_supported = true,
+};
+
+struct _vcs_dpi_soc_bounding_box_st dcn3_16_soc = {
+ /*TODO: correct dispclk/dppclk voltage level determination*/
+ .clock_limits = {
+ {
+ .state = 0,
+ .dispclk_mhz = 556.0,
+ .dppclk_mhz = 556.0,
+ .phyclk_mhz = 600.0,
+ .phyclk_d18_mhz = 445.0,
+ .dscclk_mhz = 186.0,
+ .dtbclk_mhz = 625.0,
+ },
+ {
+ .state = 1,
+ .dispclk_mhz = 625.0,
+ .dppclk_mhz = 625.0,
+ .phyclk_mhz = 810.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 209.0,
+ .dtbclk_mhz = 625.0,
+ },
+ {
+ .state = 2,
+ .dispclk_mhz = 625.0,
+ .dppclk_mhz = 625.0,
+ .phyclk_mhz = 810.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 209.0,
+ .dtbclk_mhz = 625.0,
+ },
+ {
+ .state = 3,
+ .dispclk_mhz = 1112.0,
+ .dppclk_mhz = 1112.0,
+ .phyclk_mhz = 810.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 371.0,
+ .dtbclk_mhz = 625.0,
+ },
+ {
+ .state = 4,
+ .dispclk_mhz = 1250.0,
+ .dppclk_mhz = 1250.0,
+ .phyclk_mhz = 810.0,
+ .phyclk_d18_mhz = 667.0,
+ .dscclk_mhz = 417.0,
+ .dtbclk_mhz = 625.0,
+ },
+ },
+ .num_states = 5,
+ .sr_exit_time_us = 9.0,
+ .sr_enter_plus_exit_time_us = 11.0,
+ .sr_exit_z8_time_us = 442.0,
+ .sr_enter_plus_exit_z8_time_us = 560.0,
+ .writeback_latency_us = 12.0,
+ .dram_channel_width_bytes = 4,
+ .round_trip_ping_latency_dcfclk_cycles = 106,
+ .urgent_latency_pixel_data_only_us = 4.0,
+ .urgent_latency_pixel_mixed_with_vm_data_us = 4.0,
+ .urgent_latency_vm_data_only_us = 4.0,
+ .urgent_out_of_order_return_per_channel_pixel_only_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_pixel_and_vm_bytes = 4096,
+ .urgent_out_of_order_return_per_channel_vm_only_bytes = 4096,
+ .pct_ideal_sdp_bw_after_urgent = 80.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_only = 65.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_pixel_and_vm = 60.0,
+ .pct_ideal_dram_sdp_bw_after_urgent_vm_only = 30.0,
+ .max_avg_sdp_bw_use_normal_percent = 60.0,
+ .max_avg_dram_bw_use_normal_percent = 60.0,
+ .fabric_datapath_to_dcn_data_return_bytes = 32,
+ .return_bus_width_bytes = 64,
+ .downspread_percent = 0.38,
+ .dcn_downspread_percent = 0.5,
+ .gpuvm_min_page_size_bytes = 4096,
+ .hostvm_min_page_size_bytes = 4096,
+ .do_urgent_latency_adjustment = false,
+ .urgent_latency_adjustment_fabric_clock_component_us = 0,
+ .urgent_latency_adjustment_fabric_clock_reference_mhz = 0,
+};
+
+void dcn31_calculate_wm_and_dlg_fp(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt,
+ int vlevel)
+{
+ int i, pipe_idx;
+ double dcfclk = context->bw_ctx.dml.vba.DCFCLKState[vlevel][context->bw_ctx.dml.vba.maxMpcComb];
+
+ dc_assert_fp_enabled();
+
+ if (context->bw_ctx.dml.soc.min_dcfclk > dcfclk)
+ dcfclk = context->bw_ctx.dml.soc.min_dcfclk;
+
+ /* We don't recalculate clocks for 0 pipe configs, which can block
+ * S0i3 as high clocks will block low power states
+ * Override any clocks that can block S0i3 to min here
+ */
+ if (pipe_cnt == 0) {
+ context->bw_ctx.bw.dcn.clk.dcfclk_khz = dcfclk; // always should be vlevel 0
+ return;
+ }
+
+ pipes[0].clks_cfg.voltage = vlevel;
+ pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+ pipes[0].clks_cfg.socclk_mhz = context->bw_ctx.dml.soc.clock_limits[vlevel].socclk_mhz;
+
+#if 0 // TODO
+ /* Set B:
+ * TODO
+ */
+ if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].valid) {
+ if (vlevel == 0) {
+ pipes[0].clks_cfg.voltage = 1;
+ pipes[0].clks_cfg.dcfclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dcfclk_mhz;
+ }
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.pstate_latency_us;
+ context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_enter_plus_exit_time_us;
+ context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_B].dml_input.sr_exit_time_us;
+ }
+ context->bw_ctx.bw.dcn.watermarks.b.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.b.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+ pipes[0].clks_cfg.voltage = vlevel;
+ pipes[0].clks_cfg.dcfclk_mhz = dcfclk;
+
+ /* Set C:
+ * TODO
+ */
+ if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].valid) {
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.pstate_latency_us;
+ context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_enter_plus_exit_time_us;
+ context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_C].dml_input.sr_exit_time_us;
+ }
+ context->bw_ctx.bw.dcn.watermarks.c.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.c.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+
+ /* Set D:
+ * TODO
+ */
+ if (dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].valid) {
+ context->bw_ctx.dml.soc.dram_clock_change_latency_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.pstate_latency_us;
+ context->bw_ctx.dml.soc.sr_enter_plus_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_enter_plus_exit_time_us;
+ context->bw_ctx.dml.soc.sr_exit_time_us = dc->clk_mgr->bw_params->wm_table.nv_entries[WM_D].dml_input.sr_exit_time_us;
+ }
+ context->bw_ctx.bw.dcn.watermarks.d.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.d.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+#endif
+
+ /* Set A:
+ * All clocks min required
+ *
+ * Set A calculated last so that following calculations are based on Set A
+ */
+ dc->res_pool->funcs->update_soc_for_wm_a(dc, context);
+ context->bw_ctx.bw.dcn.watermarks.a.urgent_ns = get_wm_urgent(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_ns = get_wm_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_ns = get_wm_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.pstate_change_ns = get_wm_dram_clock_change(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_enter_plus_exit_z8_ns = get_wm_z8_stutter_enter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.cstate_pstate.cstate_exit_z8_ns = get_wm_z8_stutter_exit(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.pte_meta_urgent_ns = get_wm_memory_trip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_nom = get_fraction_of_urgent_bandwidth(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.frac_urg_bw_flip = get_fraction_of_urgent_bandwidth_imm_flip(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ context->bw_ctx.bw.dcn.watermarks.a.urgent_latency_ns = get_urgent_latency(&context->bw_ctx.dml, pipes, pipe_cnt) * 1000;
+ /* TODO: remove: */
+ context->bw_ctx.bw.dcn.watermarks.b = context->bw_ctx.bw.dcn.watermarks.a;
+ context->bw_ctx.bw.dcn.watermarks.c = context->bw_ctx.bw.dcn.watermarks.a;
+ context->bw_ctx.bw.dcn.watermarks.d = context->bw_ctx.bw.dcn.watermarks.a;
+ /* end remove*/
+
+ for (i = 0, pipe_idx = 0; i < dc->res_pool->pipe_count; i++) {
+ if (!context->res_ctx.pipe_ctx[i].stream)
+ continue;
+
+ pipes[pipe_idx].clks_cfg.dispclk_mhz = get_dispclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt);
+ pipes[pipe_idx].clks_cfg.dppclk_mhz = get_dppclk_calculated(&context->bw_ctx.dml, pipes, pipe_cnt, pipe_idx);
+
+ if (dc->config.forced_clocks || dc->debug.max_disp_clk) {
+ pipes[pipe_idx].clks_cfg.dispclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dispclk_mhz;
+ pipes[pipe_idx].clks_cfg.dppclk_mhz = context->bw_ctx.dml.soc.clock_limits[0].dppclk_mhz;
+ }
+ if (dc->debug.min_disp_clk_khz > pipes[pipe_idx].clks_cfg.dispclk_mhz * 1000)
+ pipes[pipe_idx].clks_cfg.dispclk_mhz = dc->debug.min_disp_clk_khz / 1000.0;
+ if (dc->debug.min_dpp_clk_khz > pipes[pipe_idx].clks_cfg.dppclk_mhz * 1000)
+ pipes[pipe_idx].clks_cfg.dppclk_mhz = dc->debug.min_dpp_clk_khz / 1000.0;
+
+ pipe_idx++;
+ }
+
+ dcn20_calculate_dlg_params(dc, context, pipes, pipe_cnt, vlevel);
+}
+
+void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+ struct clk_limit_table *clk_table = &bw_params->clk_table;
+ struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES];
+ unsigned int i, closest_clk_lvl;
+ int j;
+
+ dc_assert_fp_enabled();
+
+ // Default clock levels are used for diags, which may lead to overclocking.
+ if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
+ int max_dispclk_mhz = 0, max_dppclk_mhz = 0;
+
+ dcn3_1_ip.max_num_otg = dc->res_pool->res_cap->num_timing_generator;
+ dcn3_1_ip.max_num_dpp = dc->res_pool->pipe_count;
+ dcn3_1_soc.num_chans = bw_params->num_channels;
+
+ ASSERT(clk_table->num_entries);
+
+ /* Prepass to find max clocks independent of voltage level. */
+ for (i = 0; i < clk_table->num_entries; ++i) {
+ if (clk_table->entries[i].dispclk_mhz > max_dispclk_mhz)
+ max_dispclk_mhz = clk_table->entries[i].dispclk_mhz;
+ if (clk_table->entries[i].dppclk_mhz > max_dppclk_mhz)
+ max_dppclk_mhz = clk_table->entries[i].dppclk_mhz;
+ }
+
+ for (i = 0; i < clk_table->num_entries; i++) {
+ /* loop backwards*/
+ for (closest_clk_lvl = 0, j = dcn3_1_soc.num_states - 1; j >= 0; j--) {
+ if ((unsigned int) dcn3_1_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {
+ closest_clk_lvl = j;
+ break;
+ }
+ }
+
+ clock_limits[i].state = i;
+
+ /* Clocks dependent on voltage level. */
+ clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz;
+ clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz;
+ clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz;
+ clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2 * clk_table->entries[i].wck_ratio;
+
+ /* Clocks independent of voltage level. */
+ clock_limits[i].dispclk_mhz = max_dispclk_mhz ? max_dispclk_mhz :
+ dcn3_1_soc.clock_limits[closest_clk_lvl].dispclk_mhz;
+
+ clock_limits[i].dppclk_mhz = max_dppclk_mhz ? max_dppclk_mhz :
+ dcn3_1_soc.clock_limits[closest_clk_lvl].dppclk_mhz;
+
+ clock_limits[i].dram_bw_per_chan_gbps = dcn3_1_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps;
+ clock_limits[i].dscclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].dscclk_mhz;
+ clock_limits[i].dtbclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].dtbclk_mhz;
+ clock_limits[i].phyclk_d18_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz;
+ clock_limits[i].phyclk_mhz = dcn3_1_soc.clock_limits[closest_clk_lvl].phyclk_mhz;
+ }
+ for (i = 0; i < clk_table->num_entries; i++)
+ dcn3_1_soc.clock_limits[i] = clock_limits[i];
+ if (clk_table->num_entries) {
+ dcn3_1_soc.num_states = clk_table->num_entries;
+ }
+ }
+
+ dcn3_1_soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+ dc->dml.soc.dispclk_dppclk_vco_speed_mhz = dc->clk_mgr->dentist_vco_freq_khz / 1000.0;
+
+ if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31);
+ else
+ dml_init_instance(&dc->dml, &dcn3_1_soc, &dcn3_1_ip, DML_PROJECT_DCN31_FPGA);
+}
+
+void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+ struct clk_limit_table *clk_table = &bw_params->clk_table;
+ int i, max_dispclk_mhz = 0, max_dppclk_mhz = 0;
+
+ dc_assert_fp_enabled();
+
+ dcn3_15_ip.max_num_otg = dc->res_pool->res_cap->num_timing_generator;
+ dcn3_15_ip.max_num_dpp = dc->res_pool->pipe_count;
+ dcn3_15_soc.num_chans = bw_params->num_channels;
+
+ ASSERT(clk_table->num_entries);
+
+ /* Setup soc to always use max dispclk/dppclk to avoid odm-to-lower-voltage */
+ for (i = 0; i < clk_table->num_entries; ++i) {
+ if (clk_table->entries[i].dispclk_mhz > max_dispclk_mhz)
+ max_dispclk_mhz = clk_table->entries[i].dispclk_mhz;
+ if (clk_table->entries[i].dppclk_mhz > max_dppclk_mhz)
+ max_dppclk_mhz = clk_table->entries[i].dppclk_mhz;
+ }
+
+ for (i = 0; i < clk_table->num_entries; i++) {
+ dcn3_15_soc.clock_limits[i].state = i;
+
+ /* Clocks dependent on voltage level. */
+ dcn3_15_soc.clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz;
+ dcn3_15_soc.clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz;
+ dcn3_15_soc.clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz;
+ dcn3_15_soc.clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2 * clk_table->entries[i].wck_ratio;
+
+ /* These aren't actually read from smu, but rather set in clk_mgr defaults */
+ dcn3_15_soc.clock_limits[i].dtbclk_mhz = clk_table->entries[i].dtbclk_mhz;
+ dcn3_15_soc.clock_limits[i].phyclk_d18_mhz = clk_table->entries[i].phyclk_d18_mhz;
+ dcn3_15_soc.clock_limits[i].phyclk_mhz = clk_table->entries[i].phyclk_mhz;
+
+ /* Clocks independent of voltage level. */
+ dcn3_15_soc.clock_limits[i].dispclk_mhz = max_dispclk_mhz;
+ dcn3_15_soc.clock_limits[i].dppclk_mhz = max_dppclk_mhz;
+ dcn3_15_soc.clock_limits[i].dscclk_mhz = max_dispclk_mhz / 3.0;
+ }
+ dcn3_15_soc.num_states = clk_table->num_entries;
+
+
+ /* Set vco to max_dispclk * 2 to make sure the highest dispclk is always available for dml calcs,
+ * no impact outside of dml validation
+ */
+ dcn3_15_soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2;
+
+ if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ dml_init_instance(&dc->dml, &dcn3_15_soc, &dcn3_15_ip, DML_PROJECT_DCN31);
+ else
+ dml_init_instance(&dc->dml, &dcn3_15_soc, &dcn3_15_ip, DML_PROJECT_DCN31_FPGA);
+}
+
+void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params)
+{
+ struct clk_limit_table *clk_table = &bw_params->clk_table;
+ struct _vcs_dpi_voltage_scaling_st clock_limits[DC__VOLTAGE_STATES];
+ unsigned int i, closest_clk_lvl;
+ int max_dispclk_mhz = 0, max_dppclk_mhz = 0;
+ int j;
+
+ dc_assert_fp_enabled();
+
+ // Default clock levels are used for diags, which may lead to overclocking.
+ if (!IS_DIAG_DC(dc->ctx->dce_environment)) {
+
+ dcn3_16_ip.max_num_otg = dc->res_pool->res_cap->num_timing_generator;
+ dcn3_16_ip.max_num_dpp = dc->res_pool->pipe_count;
+ dcn3_16_soc.num_chans = bw_params->num_channels;
+
+ ASSERT(clk_table->num_entries);
+
+ /* Prepass to find max clocks independent of voltage level. */
+ for (i = 0; i < clk_table->num_entries; ++i) {
+ if (clk_table->entries[i].dispclk_mhz > max_dispclk_mhz)
+ max_dispclk_mhz = clk_table->entries[i].dispclk_mhz;
+ if (clk_table->entries[i].dppclk_mhz > max_dppclk_mhz)
+ max_dppclk_mhz = clk_table->entries[i].dppclk_mhz;
+ }
+
+ for (i = 0; i < clk_table->num_entries; i++) {
+ /* loop backwards*/
+ for (closest_clk_lvl = 0, j = dcn3_16_soc.num_states - 1; j >= 0; j--) {
+ if ((unsigned int) dcn3_16_soc.clock_limits[j].dcfclk_mhz <= clk_table->entries[i].dcfclk_mhz) {
+ closest_clk_lvl = j;
+ break;
+ }
+ }
+ // Ported from DCN315
+ if (clk_table->num_entries == 1) {
+ /*smu gives one DPM level, let's take the highest one*/
+ closest_clk_lvl = dcn3_16_soc.num_states - 1;
+ }
+
+ clock_limits[i].state = i;
+
+ /* Clocks dependent on voltage level. */
+ clock_limits[i].dcfclk_mhz = clk_table->entries[i].dcfclk_mhz;
+ if (clk_table->num_entries == 1 &&
+ clock_limits[i].dcfclk_mhz < dcn3_16_soc.clock_limits[closest_clk_lvl].dcfclk_mhz) {
+ /*SMU fix not released yet*/
+ clock_limits[i].dcfclk_mhz = dcn3_16_soc.clock_limits[closest_clk_lvl].dcfclk_mhz;
+ }
+ clock_limits[i].fabricclk_mhz = clk_table->entries[i].fclk_mhz;
+ clock_limits[i].socclk_mhz = clk_table->entries[i].socclk_mhz;
+ clock_limits[i].dram_speed_mts = clk_table->entries[i].memclk_mhz * 2 * clk_table->entries[i].wck_ratio;
+
+ /* Clocks independent of voltage level. */
+ clock_limits[i].dispclk_mhz = max_dispclk_mhz ? max_dispclk_mhz :
+ dcn3_16_soc.clock_limits[closest_clk_lvl].dispclk_mhz;
+
+ clock_limits[i].dppclk_mhz = max_dppclk_mhz ? max_dppclk_mhz :
+ dcn3_16_soc.clock_limits[closest_clk_lvl].dppclk_mhz;
+
+ clock_limits[i].dram_bw_per_chan_gbps = dcn3_16_soc.clock_limits[closest_clk_lvl].dram_bw_per_chan_gbps;
+ clock_limits[i].dscclk_mhz = dcn3_16_soc.clock_limits[closest_clk_lvl].dscclk_mhz;
+ clock_limits[i].dtbclk_mhz = dcn3_16_soc.clock_limits[closest_clk_lvl].dtbclk_mhz;
+ clock_limits[i].phyclk_d18_mhz = dcn3_16_soc.clock_limits[closest_clk_lvl].phyclk_d18_mhz;
+ clock_limits[i].phyclk_mhz = dcn3_16_soc.clock_limits[closest_clk_lvl].phyclk_mhz;
+ }
+ for (i = 0; i < clk_table->num_entries; i++)
+ dcn3_16_soc.clock_limits[i] = clock_limits[i];
+ if (clk_table->num_entries) {
+ dcn3_16_soc.num_states = clk_table->num_entries;
+ }
+ }
+
+ if (max_dispclk_mhz) {
+ dcn3_16_soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2;
+ dc->dml.soc.dispclk_dppclk_vco_speed_mhz = max_dispclk_mhz * 2;
+ }
+
+ if (!IS_FPGA_MAXIMUS_DC(dc->ctx->dce_environment))
+ dml_init_instance(&dc->dml, &dcn3_16_soc, &dcn3_16_ip, DML_PROJECT_DCN31);
+ else
+ dml_init_instance(&dc->dml, &dcn3_16_soc, &dcn3_16_ip, DML_PROJECT_DCN31_FPGA);
+}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
new file mode 100644
index 000000000000..24ac19c83687
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/dcn31_fpu.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019-2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DCN31_FPU_H__
+#define __DCN31_FPU_H__
+
+#define DCN3_1_DEFAULT_DET_SIZE 384
+#define DCN3_15_DEFAULT_DET_SIZE 192
+#define DCN3_15_MIN_COMPBUF_SIZE_KB 128
+#define DCN3_16_DEFAULT_DET_SIZE 192
+
+void dcn31_calculate_wm_and_dlg_fp(
+ struct dc *dc, struct dc_state *context,
+ display_e2e_pipe_params_st *pipes,
+ int pipe_cnt,
+ int vlevel);
+
+void dcn31_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+void dcn315_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+void dcn316_update_bw_bounding_box(struct dc *dc, struct clk_bw_params *bw_params);
+
+#endif /* __DCN31_FPU_H__*/
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
index 6feb23432f8d..e4b9fd31223c 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_mode_vba_31.c
@@ -64,6 +64,8 @@ typedef struct {
double DCFCLKDeepSleep;
unsigned int DPPPerPlane;
bool ScalerEnabled;
+ double VRatio;
+ double VRatioChroma;
enum scan_direction_class SourceScan;
unsigned int BlockWidth256BytesY;
unsigned int BlockHeight256BytesY;
@@ -942,6 +944,7 @@ static bool CalculatePrefetchSchedule(
double dst_y_prefetch_equ;
double Tsw_oto;
double prefetch_bw_oto;
+ double prefetch_bw_pr;
double Tvm_oto;
double Tr0_oto;
double Tvm_oto_lines;
@@ -971,6 +974,7 @@ static bool CalculatePrefetchSchedule(
double min_Lsw;
double Tsw_est1 = 0;
double Tsw_est3 = 0;
+ double max_Tsw = 0;
if (GPUVMEnable == true && HostVMEnable == true) {
HostVMDynamicLevelsTrips = HostVMMaxNonCachedPageTableLevels;
@@ -1111,11 +1115,14 @@ static bool CalculatePrefetchSchedule(
bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC / 4;
else
bytes_pp = myPipe->BytePerPixelY + myPipe->BytePerPixelC;
-
+ /*rev 99*/
+ prefetch_bw_pr = dml_min(1, bytes_pp * myPipe->PixelClock / (double) myPipe->DPPPerPlane);
+ max_Tsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime;
prefetch_sw_bytes = PrefetchSourceLinesY * swath_width_luma_ub * myPipe->BytePerPixelY + PrefetchSourceLinesC * swath_width_chroma_ub * myPipe->BytePerPixelC;
prefetch_bw_oto = dml_max(bytes_pp * myPipe->PixelClock / myPipe->DPPPerPlane, prefetch_sw_bytes / (dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) * LineTime));
+ prefetch_bw_oto = dml_max(prefetch_bw_pr, prefetch_sw_bytes / max_Tsw);
- min_Lsw = dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre;
+ min_Lsw = dml_max(1, dml_max(PrefetchSourceLinesY, PrefetchSourceLinesC) / max_vratio_pre);
Lsw_oto = dml_ceil(4 * dml_max(prefetch_sw_bytes / prefetch_bw_oto / LineTime, min_Lsw), 1) / 4;
Tsw_oto = Lsw_oto * LineTime;
@@ -1389,7 +1396,7 @@ static bool CalculatePrefetchSchedule(
dml_print("DML::%s: SwathHeightC = %d\n", __func__, SwathHeightC);
dml_print("DML::%s: VInitPreFillC = %f\n", __func__, VInitPreFillC);
#endif
- if ((SwathHeightC > 4)) {
+ if ((SwathHeightC > 4) || VInitPreFillC > 3) {
if (LinesToRequestPrefetchPixelData > (VInitPreFillC - 3.0) / 2.0) {
*VRatioPrefetchC = dml_max(
*VRatioPrefetchC,
@@ -2663,6 +2670,8 @@ static void DISPCLKDPPCLKDCFCLKDeepSleepPrefetchParametersWatermarksAndPerforman
myPipe.DCFCLKDeepSleep = v->DCFCLKDeepSleep;
myPipe.DPPPerPlane = v->DPPPerPlane[k];
myPipe.ScalerEnabled = v->ScalerEnabled[k];
+ myPipe.VRatio = v->VRatio[k];
+ myPipe.VRatioChroma = v->VRatioChroma[k];
myPipe.SourceScan = v->SourceScan[k];
myPipe.BlockWidth256BytesY = v->BlockWidth256BytesY[k];
myPipe.BlockHeight256BytesY = v->BlockHeight256BytesY[k];
@@ -3911,6 +3920,9 @@ static noinline void CalculatePrefetchSchedulePerPlane(
myPipe.DCFCLKDeepSleep = v->ProjectedDCFCLKDeepSleep[i][j];
myPipe.DPPPerPlane = v->NoOfDPP[i][j][k];
myPipe.ScalerEnabled = v->ScalerEnabled[k];
+ myPipe.VRatio = mode_lib->vba.VRatio[k];
+ myPipe.VRatioChroma = mode_lib->vba.VRatioChroma[k];
+
myPipe.SourceScan = v->SourceScan[k];
myPipe.BlockWidth256BytesY = v->Read256BlockWidthY[k];
myPipe.BlockHeight256BytesY = v->Read256BlockHeightY[k];
@@ -4987,6 +4999,17 @@ void dml31_ModeSupportAndSystemConfigurationFull(struct display_mode_lib *mode_l
&v->meta_row_bandwidth[i][j][k],
&v->dpte_row_bandwidth[i][j][k]);
}
+ /*DCCMetaBufferSizeSupport(i, j) = True
+ For k = 0 To NumberOfActivePlanes - 1
+ If MetaRowBytes(i, j, k) > 24064 Then
+ DCCMetaBufferSizeSupport(i, j) = False
+ End If
+ Next k*/
+ v->DCCMetaBufferSizeSupport[i][j] = true;
+ for (k = 0; k < v->NumberOfActivePlanes; ++k) {
+ if (v->MetaRowBytes[i][j][k] > 24064)
+ v->DCCMetaBufferSizeSupport[i][j] = false;
+ }
v->UrgLatency[i] = CalculateUrgentLatency(
v->UrgentLatencyPixelDataOnly,
v->UrgentLatencyPixelMixedWithVMData,
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
index e0fecf127bd5..53d760e169e6 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dcn31/display_rq_dlg_calc_31.c
@@ -1055,6 +1055,7 @@ static void dml_rq_dlg_get_dlg_params(
float vba__refcyc_per_req_delivery_pre_l = get_refcyc_per_req_delivery_pre_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA
float vba__refcyc_per_req_delivery_l = get_refcyc_per_req_delivery_l_in_us(mode_lib, e2e_pipe_param, num_pipes, pipe_idx) * refclk_freq_in_mhz; // From VBA
+ int blank_lines;
memset(disp_dlg_regs, 0, sizeof(*disp_dlg_regs));
memset(disp_ttu_regs, 0, sizeof(*disp_ttu_regs));
@@ -1080,6 +1081,18 @@ static void dml_rq_dlg_get_dlg_params(
dlg_vblank_start = interlaced ? (vblank_start / 2) : vblank_start;
disp_dlg_regs->min_dst_y_next_start = (unsigned int) (((double) dlg_vblank_start) * dml_pow(2, 2));
+ blank_lines = (dst->vblank_end + dst->vtotal_min - dst->vblank_start - dst->vstartup_start - 1);
+ if (blank_lines < 0)
+ blank_lines = 0;
+ if (blank_lines != 0) {
+ disp_dlg_regs->optimized_min_dst_y_next_start_us =
+ ((unsigned int) blank_lines * dst->hactive) / (unsigned int) dst->pixel_rate_mhz;
+ disp_dlg_regs->optimized_min_dst_y_next_start =
+ (unsigned int)(((double) (dlg_vblank_start + blank_lines)) * dml_pow(2, 2));
+ } else {
+ // use unoptimized value
+ disp_dlg_regs->optimized_min_dst_y_next_start = disp_dlg_regs->min_dst_y_next_start;
+ }
ASSERT(disp_dlg_regs->min_dst_y_next_start < (unsigned int)dml_pow(2, 18));
dml_print("DML_DLG: %s: min_ttu_vblank (us) = %3.2f\n", __func__, min_ttu_vblank);
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
index 8f9f1d607f7c..2df660cd8801 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_structs.h
@@ -141,6 +141,7 @@ struct _vcs_dpi_ip_params_st {
unsigned int odm_capable;
unsigned int rob_buffer_size_kbytes;
unsigned int det_buffer_size_kbytes;
+ unsigned int min_comp_buffer_size_kbytes;
unsigned int dpte_buffer_size_in_pte_reqs_luma;
unsigned int dpte_buffer_size_in_pte_reqs_chroma;
unsigned int pde_proc_buffer_size_64k_reqs;
@@ -445,6 +446,8 @@ struct _vcs_dpi_display_dlg_regs_st {
unsigned int refcyc_h_blank_end;
unsigned int dlg_vblank_end;
unsigned int min_dst_y_next_start;
+ unsigned int optimized_min_dst_y_next_start;
+ unsigned int optimized_min_dst_y_next_start_us;
unsigned int refcyc_per_htotal;
unsigned int refcyc_x_after_scaler;
unsigned int dst_y_after_scaler;
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
index 0fad15020c74..c0740dbdcc2e 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.c
@@ -47,6 +47,7 @@ static void recalculate_params(
unsigned int num_pipes);
static unsigned int CursorBppEnumToBits(enum cursor_bpp ebpp);
+static void cache_debug_params(struct display_mode_lib *mode_lib);
unsigned int dml_get_voltage_level(
struct display_mode_lib *mode_lib,
@@ -73,6 +74,7 @@ unsigned int dml_get_voltage_level(
PixelClockAdjustmentForProgressiveToInterlaceUnit(mode_lib);
}
mode_lib->funcs.validate(mode_lib);
+ cache_debug_params(mode_lib);
return mode_lib->vba.VoltageLevel;
}
@@ -745,6 +747,28 @@ static void fetch_pipe_params(struct display_mode_lib *mode_lib)
mode_lib->vba.HostVMEnable = mode_lib->vba.HostVMEnable && !!ip->hostvm_enable;
}
+/**
+ * ********************************************************************************************
+ * cache_debug_params: Cache any params that needed to be maintained from the initial validation
+ * for debug purposes.
+ *
+ * The DML getters can modify some of the VBA params that we are interested in (for example when
+ * calculating with dummy p-state latency), so cache any params here that we want for debugging
+ *
+ * @param [in] mode_lib: mode_lib input/output of validate call
+ *
+ * @return: void
+ *
+ * ********************************************************************************************
+ */
+static void cache_debug_params(struct display_mode_lib *mode_lib)
+{
+ int k = 0;
+
+ for (k = 0; k < mode_lib->vba.NumberOfActivePlanes; k++)
+ mode_lib->vba.CachedActiveDRAMClockChangeLatencyMargin[k] = mode_lib->vba.ActiveDRAMClockChangeLatencyMargin[k];
+}
+
// in wm mode we pull the parameters needed from the display_e2e_pipe_params_st structs
// rather than working them out as in recalculate_ms
static void recalculate_params(
diff --git a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
index 90e87961fe3e..0603b32971a6 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/display_mode_vba.h
@@ -195,6 +195,7 @@ struct vba_vars_st {
unsigned int LBLatencyHidingSourceLinesY;
unsigned int LBLatencyHidingSourceLinesC;
double ActiveDRAMClockChangeLatencyMargin[DC__NUM_DPP__MAX];
+ double CachedActiveDRAMClockChangeLatencyMargin[DC__NUM_DPP__MAX]; // Cache in dml_get_voltage_level for debug purposes only
double MinActiveDRAMClockChangeMargin;
double InitFillLevel;
double FinalFillMargin;
@@ -544,6 +545,8 @@ struct vba_vars_st {
bool DTBCLKRequiredMoreThanSupported[DC__VOLTAGE_STATES];
double UrgentRoundTripAndOutOfOrderLatencyPerState[DC__VOLTAGE_STATES];
bool ROBSupport[DC__VOLTAGE_STATES][2];
+ //based on rev 99: Dim DCCMetaBufferSizeSupport(NumberOfStates, 1) As Boolean
+ bool DCCMetaBufferSizeSupport[DC__VOLTAGE_STATES][2];
bool PTEBufferSizeNotExceeded[DC__VOLTAGE_STATES][2];
bool TotalVerticalActiveBandwidthSupport[DC__VOLTAGE_STATES][2];
double MaxTotalVerticalActiveAvailableBandwidth[DC__VOLTAGE_STATES][2];
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c b/drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c
index 789f7562cdc7..d2273674e872 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dml_wrapper.c
@@ -1284,10 +1284,8 @@ static bool is_dtbclk_required(struct dc *dc, struct dc_state *context)
for (i = 0; i < dc->res_pool->pipe_count; i++) {
if (!context->res_ctx.pipe_ctx[i].stream)
continue;
-#if defined (CONFIG_DRM_AMD_DC_DP2_0)
if (is_dp_128b_132b_signal(&context->res_ctx.pipe_ctx[i]))
return true;
-#endif
}
return false;
}
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c
index ec636d06e18c..ef75eb7d5adc 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c
+++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.c
@@ -68,7 +68,7 @@ static void get_qp_set(qp_set qps, enum colour_mode cm, enum bits_per_comp bpc,
int sel = table_hash(mode, bpc, max_min);
int table_size = 0;
int index;
- const struct qp_entry *table = 0L;
+ const struct qp_entry *table = NULL;
// alias enum
enum { min = DAL_MM_MIN, max = DAL_MM_MAX };
diff --git a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h
index cad244c023cd..d7cd8cc24758 100644
--- a/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h
+++ b/drivers/gpu/drm/amd/display/dc/dml/dsc/rc_calc_fpu.h
@@ -27,7 +27,7 @@
#define __RC_CALC_FPU_H__
#include "os_types.h"
-#include <drm/drm_dsc.h>
+#include <drm/display/drm_dsc.h>
#define QP_SET_SIZE 15
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
index 9c74564cbd8d..fa39a06eed1d 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
+++ b/drivers/gpu/drm/amd/display/dc/dsc/dc_dsc.c
@@ -22,10 +22,10 @@
* Author: AMD
*/
-#include <drm/drm_dsc.h>
+#include <drm/display/drm_dp_helper.h>
+#include <drm/display/drm_dsc_helper.h>
#include "dc_hw_types.h"
#include "dsc.h"
-#include <drm/drm_dp_helper.h>
#include "dc.h"
#include "rc_calc.h"
#include "fixed31_32.h"
@@ -864,11 +864,11 @@ static bool setup_dsc_config(
min_slices_h = inc_num_slices(dsc_common_caps.slice_caps, min_slices_h);
}
+ is_dsc_possible = (min_slices_h <= max_slices_h);
+
if (pic_width % min_slices_h != 0)
min_slices_h = 0; // DSC TODO: Maybe try increasing the number of slices first?
- is_dsc_possible = (min_slices_h <= max_slices_h);
-
if (min_slices_h == 0 && max_slices_h == 0)
is_dsc_possible = false;
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
index 9f70e87b3ecb..ad80bde9bc0f 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
+++ b/drivers/gpu/drm/amd/display/dc/dsc/dscc_types.h
@@ -26,7 +26,7 @@
#ifndef __DSCC_TYPES_H__
#define __DSCC_TYPES_H__
-#include <drm/drm_dsc.h>
+#include <drm/display/drm_dsc.h>
#ifndef NUM_BUF_RANGES
#define NUM_BUF_RANGES 15
diff --git a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
index 7e306aa3e2b9..f0aea988fef0 100644
--- a/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
+++ b/drivers/gpu/drm/amd/display/dc/dsc/rc_calc_dpi.c
@@ -22,7 +22,7 @@
* Authors: AMD
*
*/
-#include <drm/drm_dsc.h>
+#include <drm/display/drm_dsc_helper.h>
#include "dscc_types.h"
#include "rc_calc.h"
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/Makefile b/drivers/gpu/drm/amd/display/dc/gpio/Makefile
index c5ddade8b187..0f4a22be8c40 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/gpio/Makefile
@@ -73,7 +73,6 @@ AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCE120)
###############################################################################
# DCN 1x
###############################################################################
-ifdef CONFIG_DRM_AMD_DC_DCN
GPIO_DCN10 = hw_translate_dcn10.o hw_factory_dcn10.o
AMD_DAL_GPIO_DCN10 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn10/,$(GPIO_DCN10))
@@ -106,7 +105,15 @@ GPIO_DCN30 = hw_translate_dcn30.o hw_factory_dcn30.o
AMD_DAL_GPIO_DCN30 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn30/,$(GPIO_DCN30))
AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCN30)
-endif
+###############################################################################
+# DCN 3.15
+###############################################################################
+GPIO_DCN315 = hw_translate_dcn315.o hw_factory_dcn315.o
+
+AMD_DAL_GPIO_DCN315 = $(addprefix $(AMDDALPATH)/dc/gpio/dcn315/,$(GPIO_DCN315))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_GPIO_DCN315)
+
###############################################################################
# Diagnostics on FPGA
###############################################################################
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c
index 5f6ae3edb755..687d4f128480 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.c
@@ -22,7 +22,6 @@
* Authors: AMD
*
*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "dm_services.h"
#include "include/gpio_types.h"
#include "../hw_factory.h"
@@ -42,8 +41,8 @@
#include "nbio/nbio_7_4_offset.h"
-#include "dcn/dpcs_3_0_0_offset.h"
-#include "dcn/dpcs_3_0_0_sh_mask.h"
+#include "dpcs/dpcs_3_0_0_offset.h"
+#include "dpcs/dpcs_3_0_0_sh_mask.h"
#include "mmhub/mmhub_2_0_0_offset.h"
#include "mmhub/mmhub_2_0_0_sh_mask.h"
@@ -266,4 +265,3 @@ void dal_hw_factory_dcn30_init(struct hw_factory *factory)
factory->funcs = &funcs;
}
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.h
index 131e742b050a..e491af845b83 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.h
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_factory_dcn30.h
@@ -22,7 +22,6 @@
* Authors: AMD
*
*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#ifndef __DAL_HW_FACTORY_DCN30_H__
#define __DAL_HW_FACTORY_DCN30_H__
@@ -30,4 +29,3 @@
void dal_hw_factory_dcn30_init(struct hw_factory *factory);
#endif /* __DAL_HW_FACTORY_DCN30_H__ */
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c
index 0046219a1cc7..3169c567475f 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.c
@@ -26,7 +26,6 @@
/*
* Pre-requisites: headers required by header of this unit
*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "hw_translate_dcn30.h"
#include "dm_services.h"
@@ -40,8 +39,8 @@
#include "nbio/nbio_7_4_offset.h"
-#include "dcn/dpcs_3_0_0_offset.h"
-#include "dcn/dpcs_3_0_0_sh_mask.h"
+#include "dpcs/dpcs_3_0_0_offset.h"
+#include "dpcs/dpcs_3_0_0_sh_mask.h"
#include "mmhub/mmhub_2_0_0_offset.h"
#include "mmhub/mmhub_2_0_0_sh_mask.h"
@@ -384,4 +383,3 @@ void dal_hw_translate_dcn30_init(struct hw_translate *tr)
tr->funcs = &funcs;
}
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.h
index ed55410b7a4e..511a0dd49140 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.h
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn30/hw_translate_dcn30.h
@@ -22,7 +22,6 @@
* Authors: AMD
*
*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#ifndef __DAL_HW_TRANSLATE_DCN30_H__
#define __DAL_HW_TRANSLATE_DCN30_H__
@@ -32,4 +31,3 @@ struct hw_translate;
void dal_hw_translate_dcn30_init(struct hw_translate *tr);
#endif /* __DAL_HW_TRANSLATE_DCN30_H__ */
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_factory_dcn315.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_factory_dcn315.c
new file mode 100644
index 000000000000..5feebb3b95ca
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_factory_dcn315.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "dm_services.h"
+#include "include/gpio_types.h"
+#include "../hw_factory.h"
+
+
+#include "../hw_gpio.h"
+#include "../hw_ddc.h"
+#include "../hw_hpd.h"
+#include "../hw_generic.h"
+
+#include "hw_factory_dcn315.h"
+
+#include "dcn/dcn_3_1_5_offset.h"
+#include "dcn/dcn_3_1_5_sh_mask.h"
+
+#include "reg_helper.h"
+#include "../hpd_regs.h"
+/* begin *********************
+ * macros to expend register list macro defined in HW object header file */
+
+#define DCN_BASE__INST0_SEG0 0x00000012
+#define DCN_BASE__INST0_SEG1 0x000000C0
+#define DCN_BASE__INST0_SEG2 0x000034C0
+#define DCN_BASE__INST0_SEG3 0x00009000
+#define DCN_BASE__INST0_SEG4 0x02403C00
+#define DCN_BASE__INST0_SEG5 0
+
+/* DCN */
+#define block HPD
+#define reg_num 0
+
+#undef BASE_INNER
+#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
+
+#define BASE(seg) BASE_INNER(seg)
+
+
+
+#define REG(reg_name)\
+ BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name
+
+#define SF_HPD(reg_name, field_name, post_fix)\
+ .field_name = HPD0_ ## reg_name ## __ ## field_name ## post_fix
+
+#define REGI(reg_name, block, id)\
+ BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SF(reg_name, field_name, post_fix)\
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
+/* macros to expend register list macro defined in HW object header file
+ * end *********************/
+
+
+
+#define hpd_regs(id) \
+{\
+ HPD_REG_LIST(id)\
+}
+
+static const struct hpd_registers hpd_regs[] = {
+ hpd_regs(0),
+ hpd_regs(1),
+ hpd_regs(2),
+ hpd_regs(3),
+ hpd_regs(4),
+};
+
+static const struct hpd_sh_mask hpd_shift = {
+ HPD_MASK_SH_LIST(__SHIFT)
+};
+
+static const struct hpd_sh_mask hpd_mask = {
+ HPD_MASK_SH_LIST(_MASK)
+};
+
+#include "../ddc_regs.h"
+
+ /* set field name */
+#define SF_DDC(reg_name, field_name, post_fix)\
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
+static const struct ddc_registers ddc_data_regs_dcn[] = {
+ ddc_data_regs_dcn2(1),
+ ddc_data_regs_dcn2(2),
+ ddc_data_regs_dcn2(3),
+ ddc_data_regs_dcn2(4),
+ ddc_data_regs_dcn2(5),
+ {
+ DDC_GPIO_VGA_REG_LIST(DATA),
+ .ddc_setup = 0,
+ .phy_aux_cntl = 0,
+ .dc_gpio_aux_ctrl_5 = 0
+ }
+};
+
+static const struct ddc_registers ddc_clk_regs_dcn[] = {
+ ddc_clk_regs_dcn2(1),
+ ddc_clk_regs_dcn2(2),
+ ddc_clk_regs_dcn2(3),
+ ddc_clk_regs_dcn2(4),
+ ddc_clk_regs_dcn2(5),
+ {
+ DDC_GPIO_VGA_REG_LIST(CLK),
+ .ddc_setup = 0,
+ .phy_aux_cntl = 0,
+ .dc_gpio_aux_ctrl_5 = 0
+ }
+};
+
+static const struct ddc_sh_mask ddc_shift[] = {
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 1),
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 2),
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 3),
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 4),
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 5),
+ DDC_MASK_SH_LIST_DCN2(__SHIFT, 6)
+};
+
+static const struct ddc_sh_mask ddc_mask[] = {
+ DDC_MASK_SH_LIST_DCN2(_MASK, 1),
+ DDC_MASK_SH_LIST_DCN2(_MASK, 2),
+ DDC_MASK_SH_LIST_DCN2(_MASK, 3),
+ DDC_MASK_SH_LIST_DCN2(_MASK, 4),
+ DDC_MASK_SH_LIST_DCN2(_MASK, 5),
+ DDC_MASK_SH_LIST_DCN2(_MASK, 6)
+};
+
+#include "../generic_regs.h"
+
+/* set field name */
+#define SF_GENERIC(reg_name, field_name, post_fix)\
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
+#define generic_regs(id) \
+{\
+ GENERIC_REG_LIST(id)\
+}
+
+static const struct generic_registers generic_regs[] = {
+ generic_regs(A),
+ generic_regs(B),
+};
+
+static const struct generic_sh_mask generic_shift[] = {
+ GENERIC_MASK_SH_LIST(__SHIFT, A),
+ GENERIC_MASK_SH_LIST(__SHIFT, B),
+};
+
+static const struct generic_sh_mask generic_mask[] = {
+ GENERIC_MASK_SH_LIST(_MASK, A),
+ GENERIC_MASK_SH_LIST(_MASK, B),
+};
+
+static void define_generic_registers(struct hw_gpio_pin *pin, uint32_t en)
+{
+ struct hw_generic *generic = HW_GENERIC_FROM_BASE(pin);
+
+ generic->regs = &generic_regs[en];
+ generic->shifts = &generic_shift[en];
+ generic->masks = &generic_mask[en];
+ generic->base.regs = &generic_regs[en].gpio;
+}
+
+static void define_ddc_registers(
+ struct hw_gpio_pin *pin,
+ uint32_t en)
+{
+ struct hw_ddc *ddc = HW_DDC_FROM_BASE(pin);
+
+ switch (pin->id) {
+ case GPIO_ID_DDC_DATA:
+ ddc->regs = &ddc_data_regs_dcn[en];
+ ddc->base.regs = &ddc_data_regs_dcn[en].gpio;
+ break;
+ case GPIO_ID_DDC_CLOCK:
+ ddc->regs = &ddc_clk_regs_dcn[en];
+ ddc->base.regs = &ddc_clk_regs_dcn[en].gpio;
+ break;
+ default:
+ ASSERT_CRITICAL(false);
+ return;
+ }
+
+ ddc->shifts = &ddc_shift[en];
+ ddc->masks = &ddc_mask[en];
+
+}
+
+static void define_hpd_registers(struct hw_gpio_pin *pin, uint32_t en)
+{
+ struct hw_hpd *hpd = HW_HPD_FROM_BASE(pin);
+
+ hpd->regs = &hpd_regs[en];
+ hpd->shifts = &hpd_shift;
+ hpd->masks = &hpd_mask;
+ hpd->base.regs = &hpd_regs[en].gpio;
+}
+
+
+/* fucntion table */
+static const struct hw_factory_funcs funcs = {
+ .init_ddc_data = dal_hw_ddc_init,
+ .init_generic = dal_hw_generic_init,
+ .init_hpd = dal_hw_hpd_init,
+ .get_ddc_pin = dal_hw_ddc_get_pin,
+ .get_hpd_pin = dal_hw_hpd_get_pin,
+ .get_generic_pin = dal_hw_generic_get_pin,
+ .define_hpd_registers = define_hpd_registers,
+ .define_ddc_registers = define_ddc_registers,
+ .define_generic_registers = define_generic_registers
+};
+/*
+ * dal_hw_factory_dcn10_init
+ *
+ * @brief
+ * Initialize HW factory function pointers and pin info
+ *
+ * @param
+ * struct hw_factory *factory - [out] struct of function pointers
+ */
+void dal_hw_factory_dcn315_init(struct hw_factory *factory)
+{
+ /*TODO check ASIC CAPs*/
+ factory->number_of_pins[GPIO_ID_DDC_DATA] = 8;
+ factory->number_of_pins[GPIO_ID_DDC_CLOCK] = 8;
+ factory->number_of_pins[GPIO_ID_GENERIC] = 4;
+ factory->number_of_pins[GPIO_ID_HPD] = 6;
+ factory->number_of_pins[GPIO_ID_GPIO_PAD] = 28;
+ factory->number_of_pins[GPIO_ID_VIP_PAD] = 0;
+ factory->number_of_pins[GPIO_ID_SYNC] = 0;
+ factory->number_of_pins[GPIO_ID_GSL] = 0;/*add this*/
+
+ factory->funcs = &funcs;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_factory_dcn315.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_factory_dcn315.h
new file mode 100644
index 000000000000..ffa71fa41cd4
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_factory_dcn315.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __DAL_HW_FACTORY_DCN315_H__
+#define __DAL_HW_FACTORY_DCN315_H__
+
+/* Initialize HW factory function pointers and pin info */
+void dal_hw_factory_dcn315_init(struct hw_factory *factory);
+
+#endif /* __DAL_HW_FACTORY_DCN315_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.c b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.c
new file mode 100644
index 000000000000..fbdaba57f718
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.c
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "hw_translate_dcn315.h"
+
+#include "dm_services.h"
+#include "include/gpio_types.h"
+#include "../hw_translate.h"
+
+#include "dcn/dcn_3_1_5_offset.h"
+#include "dcn/dcn_3_1_5_sh_mask.h"
+
+/* begin *********************
+ * macros to expend register list macro defined in HW object header file */
+
+#define DCN_BASE__INST0_SEG0 0x00000012
+#define DCN_BASE__INST0_SEG1 0x000000C0
+#define DCN_BASE__INST0_SEG2 0x000034C0
+#define DCN_BASE__INST0_SEG3 0x00009000
+#define DCN_BASE__INST0_SEG4 0x02403C00
+#define DCN_BASE__INST0_SEG5 0
+
+/* DCN */
+#define block HPD
+#define reg_num 0
+
+#undef BASE_INNER
+#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
+
+#define BASE(seg) BASE_INNER(seg)
+
+#undef REG
+#define REG(reg_name)\
+ BASE(reg ## reg_name ## _BASE_IDX) + reg ## reg_name
+#define SF_HPD(reg_name, field_name, post_fix)\
+ .field_name = reg_name ## __ ## field_name ## post_fix
+
+
+/* macros to expend register list macro defined in HW object header file
+ * end *********************/
+
+
+static bool offset_to_id(
+ uint32_t offset,
+ uint32_t mask,
+ enum gpio_id *id,
+ uint32_t *en)
+{
+ switch (offset) {
+ /* GENERIC */
+ case REG(DC_GPIO_GENERIC_A):
+ *id = GPIO_ID_GENERIC;
+ switch (mask) {
+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK:
+ *en = GPIO_GENERIC_A;
+ return true;
+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK:
+ *en = GPIO_GENERIC_B;
+ return true;
+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK:
+ *en = GPIO_GENERIC_C;
+ return true;
+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK:
+ *en = GPIO_GENERIC_D;
+ return true;
+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK:
+ *en = GPIO_GENERIC_E;
+ return true;
+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK:
+ *en = GPIO_GENERIC_F;
+ return true;
+ case DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK:
+ *en = GPIO_GENERIC_G;
+ return true;
+ default:
+ ASSERT_CRITICAL(false);
+ return false;
+ }
+ break;
+ /* HPD */
+ case REG(DC_GPIO_HPD_A):
+ *id = GPIO_ID_HPD;
+ switch (mask) {
+ case DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK:
+ *en = GPIO_HPD_1;
+ return true;
+ case DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK:
+ *en = GPIO_HPD_2;
+ return true;
+ case DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK:
+ *en = GPIO_HPD_3;
+ return true;
+ case DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK:
+ *en = GPIO_HPD_4;
+ return true;
+ case DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK:
+ *en = GPIO_HPD_5;
+ return true;
+ case DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK:
+ *en = GPIO_HPD_6;
+ return true;
+ default:
+ ASSERT_CRITICAL(false);
+ return false;
+ }
+ break;
+ /* REG(DC_GPIO_GENLK_MASK */
+ case REG(DC_GPIO_GENLK_A):
+ *id = GPIO_ID_GSL;
+ switch (mask) {
+ case DC_GPIO_GENLK_A__DC_GPIO_GENLK_CLK_A_MASK:
+ *en = GPIO_GSL_GENLOCK_CLOCK;
+ return true;
+ case DC_GPIO_GENLK_A__DC_GPIO_GENLK_VSYNC_A_MASK:
+ *en = GPIO_GSL_GENLOCK_VSYNC;
+ return true;
+ case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_A_A_MASK:
+ *en = GPIO_GSL_SWAPLOCK_A;
+ return true;
+ case DC_GPIO_GENLK_A__DC_GPIO_SWAPLOCK_B_A_MASK:
+ *en = GPIO_GSL_SWAPLOCK_B;
+ return true;
+ default:
+ ASSERT_CRITICAL(false);
+ return false;
+ }
+ break;
+ /* DDC */
+ /* we don't care about the GPIO_ID for DDC
+ * in DdcHandle it will use GPIO_ID_DDC_DATA/GPIO_ID_DDC_CLOCK
+ * directly in the create method
+ */
+ case REG(DC_GPIO_DDC1_A):
+ *en = GPIO_DDC_LINE_DDC1;
+ return true;
+ case REG(DC_GPIO_DDC2_A):
+ *en = GPIO_DDC_LINE_DDC2;
+ return true;
+ case REG(DC_GPIO_DDC3_A):
+ *en = GPIO_DDC_LINE_DDC3;
+ return true;
+ case REG(DC_GPIO_DDC4_A):
+ *en = GPIO_DDC_LINE_DDC4;
+ return true;
+ case REG(DC_GPIO_DDC5_A):
+ *en = GPIO_DDC_LINE_DDC5;
+ return true;
+ case REG(DC_GPIO_DDCVGA_A):
+ *en = GPIO_DDC_LINE_DDC_VGA;
+ return true;
+
+/*
+ * case REG(DC_GPIO_I2CPAD_A): not exit
+ * case REG(DC_GPIO_PWRSEQ_A):
+ * case REG(DC_GPIO_PAD_STRENGTH_1):
+ * case REG(DC_GPIO_PAD_STRENGTH_2):
+ * case REG(DC_GPIO_DEBUG):
+ */
+ /* UNEXPECTED */
+ default:
+/* case REG(DC_GPIO_SYNCA_A): not exist */
+ ASSERT_CRITICAL(false);
+ return false;
+ }
+}
+
+static bool id_to_offset(
+ enum gpio_id id,
+ uint32_t en,
+ struct gpio_pin_info *info)
+{
+ bool result = true;
+
+ switch (id) {
+ case GPIO_ID_DDC_DATA:
+ info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1DATA_A_MASK;
+ switch (en) {
+ case GPIO_DDC_LINE_DDC1:
+ info->offset = REG(DC_GPIO_DDC1_A);
+ break;
+ case GPIO_DDC_LINE_DDC2:
+ info->offset = REG(DC_GPIO_DDC2_A);
+ break;
+ case GPIO_DDC_LINE_DDC3:
+ info->offset = REG(DC_GPIO_DDC3_A);
+ break;
+ case GPIO_DDC_LINE_DDC4:
+ info->offset = REG(DC_GPIO_DDC4_A);
+ break;
+ case GPIO_DDC_LINE_DDC5:
+ info->offset = REG(DC_GPIO_DDC5_A);
+ break;
+ case GPIO_DDC_LINE_DDC_VGA:
+ info->offset = REG(DC_GPIO_DDCVGA_A);
+ break;
+ case GPIO_DDC_LINE_I2C_PAD:
+ default:
+ ASSERT_CRITICAL(false);
+ result = false;
+ }
+ break;
+ case GPIO_ID_DDC_CLOCK:
+ info->mask = DC_GPIO_DDC1_A__DC_GPIO_DDC1CLK_A_MASK;
+ switch (en) {
+ case GPIO_DDC_LINE_DDC1:
+ info->offset = REG(DC_GPIO_DDC1_A);
+ break;
+ case GPIO_DDC_LINE_DDC2:
+ info->offset = REG(DC_GPIO_DDC2_A);
+ break;
+ case GPIO_DDC_LINE_DDC3:
+ info->offset = REG(DC_GPIO_DDC3_A);
+ break;
+ case GPIO_DDC_LINE_DDC4:
+ info->offset = REG(DC_GPIO_DDC4_A);
+ break;
+ case GPIO_DDC_LINE_DDC5:
+ info->offset = REG(DC_GPIO_DDC5_A);
+ break;
+ case GPIO_DDC_LINE_DDC_VGA:
+ info->offset = REG(DC_GPIO_DDCVGA_A);
+ break;
+ case GPIO_DDC_LINE_I2C_PAD:
+ default:
+ ASSERT_CRITICAL(false);
+ result = false;
+ }
+ break;
+ case GPIO_ID_GENERIC:
+ info->offset = REG(DC_GPIO_GENERIC_A);
+ switch (en) {
+ case GPIO_GENERIC_A:
+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICA_A_MASK;
+ break;
+ case GPIO_GENERIC_B:
+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICB_A_MASK;
+ break;
+ case GPIO_GENERIC_C:
+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICC_A_MASK;
+ break;
+ case GPIO_GENERIC_D:
+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICD_A_MASK;
+ break;
+ case GPIO_GENERIC_E:
+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICE_A_MASK;
+ break;
+ case GPIO_GENERIC_F:
+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICF_A_MASK;
+ break;
+ case GPIO_GENERIC_G:
+ info->mask = DC_GPIO_GENERIC_A__DC_GPIO_GENERICG_A_MASK;
+ break;
+ default:
+ ASSERT_CRITICAL(false);
+ result = false;
+ }
+ break;
+ case GPIO_ID_HPD:
+ info->offset = REG(DC_GPIO_HPD_A);
+ switch (en) {
+ case GPIO_HPD_1:
+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD1_A_MASK;
+ break;
+ case GPIO_HPD_2:
+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD2_A_MASK;
+ break;
+ case GPIO_HPD_3:
+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD3_A_MASK;
+ break;
+ case GPIO_HPD_4:
+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD4_A_MASK;
+ break;
+ case GPIO_HPD_5:
+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD5_A_MASK;
+ break;
+ case GPIO_HPD_6:
+ info->mask = DC_GPIO_HPD_A__DC_GPIO_HPD6_A_MASK;
+ break;
+ default:
+ ASSERT_CRITICAL(false);
+ result = false;
+ }
+ break;
+ case GPIO_ID_GSL:
+ switch (en) {
+ case GPIO_GSL_GENLOCK_CLOCK:
+ /*not implmented*/
+ ASSERT_CRITICAL(false);
+ result = false;
+ break;
+ case GPIO_GSL_GENLOCK_VSYNC:
+ /*not implmented*/
+ ASSERT_CRITICAL(false);
+ result = false;
+ break;
+ case GPIO_GSL_SWAPLOCK_A:
+ /*not implmented*/
+ ASSERT_CRITICAL(false);
+ result = false;
+ break;
+ case GPIO_GSL_SWAPLOCK_B:
+ /*not implmented*/
+ ASSERT_CRITICAL(false);
+ result = false;
+
+ break;
+ default:
+ ASSERT_CRITICAL(false);
+ result = false;
+ }
+ break;
+ case GPIO_ID_SYNC:
+ case GPIO_ID_VIP_PAD:
+ default:
+ ASSERT_CRITICAL(false);
+ result = false;
+ }
+
+ if (result) {
+ info->offset_y = info->offset + 2;
+ info->offset_en = info->offset + 1;
+ info->offset_mask = info->offset - 1;
+
+ info->mask_y = info->mask;
+ info->mask_en = info->mask;
+ info->mask_mask = info->mask;
+ }
+
+ return result;
+}
+
+/* function table */
+static const struct hw_translate_funcs funcs = {
+ .offset_to_id = offset_to_id,
+ .id_to_offset = id_to_offset,
+};
+
+/*
+ * dal_hw_translate_dcn30_init
+ *
+ * @brief
+ * Initialize Hw translate function pointers.
+ *
+ * @param
+ * struct hw_translate *tr - [out] struct of function pointers
+ *
+ */
+void dal_hw_translate_dcn315_init(struct hw_translate *tr)
+{
+ tr->funcs = &funcs;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.h b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.h
new file mode 100644
index 000000000000..d58def4884b2
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/gpio/dcn315/hw_translate_dcn315.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __DAL_HW_TRANSLATE_DCN315_H__
+#define __DAL_HW_TRANSLATE_DCN315_H__
+
+struct hw_translate;
+
+/* Initialize Hw translate function pointers */
+void dal_hw_translate_dcn315_init(struct hw_translate *tr);
+
+#endif /* __DAL_HW_TRANSLATE_DCN315_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
index dae8e489c8cf..778c206f754d 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/gpio_service.c
@@ -647,7 +647,9 @@ enum gpio_result dal_ddc_set_config(
void dal_ddc_close(
struct ddc *ddc)
{
- dal_gpio_close(ddc->pin_clock);
- dal_gpio_close(ddc->pin_data);
+ if (ddc != NULL) {
+ dal_gpio_close(ddc->pin_clock);
+ dal_gpio_close(ddc->pin_data);
+ }
}
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c
index 5029d4e42dbf..ef4f69612097 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_factory.c
@@ -48,12 +48,11 @@
#include "dce80/hw_factory_dce80.h"
#include "dce110/hw_factory_dce110.h"
#include "dce120/hw_factory_dce120.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "dcn10/hw_factory_dcn10.h"
#include "dcn20/hw_factory_dcn20.h"
#include "dcn21/hw_factory_dcn21.h"
#include "dcn30/hw_factory_dcn30.h"
-#endif
+#include "dcn315/hw_factory_dcn315.h"
#include "diagnostics/hw_factory_diag.h"
@@ -97,7 +96,6 @@ bool dal_hw_factory_init(
case DCE_VERSION_12_1:
dal_hw_factory_dce120_init(factory);
return true;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case DCN_VERSION_1_0:
case DCN_VERSION_1_01:
dal_hw_factory_dcn10_init(factory);
@@ -114,9 +112,12 @@ bool dal_hw_factory_init(
case DCN_VERSION_3_02:
case DCN_VERSION_3_03:
case DCN_VERSION_3_1:
+ case DCN_VERSION_3_16:
dal_hw_factory_dcn30_init(factory);
return true;
-#endif
+ case DCN_VERSION_3_15:
+ dal_hw_factory_dcn315_init(factory);
+ return true;
default:
ASSERT_CRITICAL(false);
return false;
diff --git a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c
index 904bd30bed68..1db4f1414d7e 100644
--- a/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c
+++ b/drivers/gpu/drm/amd/display/dc/gpio/hw_translate.c
@@ -46,12 +46,11 @@
#include "dce80/hw_translate_dce80.h"
#include "dce110/hw_translate_dce110.h"
#include "dce120/hw_translate_dce120.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "dcn10/hw_translate_dcn10.h"
#include "dcn20/hw_translate_dcn20.h"
#include "dcn21/hw_translate_dcn21.h"
#include "dcn30/hw_translate_dcn30.h"
-#endif
+#include "dcn315/hw_translate_dcn315.h"
#include "diagnostics/hw_translate_diag.h"
@@ -92,7 +91,6 @@ bool dal_hw_translate_init(
case DCE_VERSION_12_1:
dal_hw_translate_dce120_init(translate);
return true;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
case DCN_VERSION_1_0:
case DCN_VERSION_1_01:
dal_hw_translate_dcn10_init(translate);
@@ -109,9 +107,12 @@ bool dal_hw_translate_init(
case DCN_VERSION_3_02:
case DCN_VERSION_3_03:
case DCN_VERSION_3_1:
+ case DCN_VERSION_3_16:
dal_hw_translate_dcn30_init(translate);
return true;
-#endif
+ case DCN_VERSION_3_15:
+ dal_hw_translate_dcn315_init(translate);
+ return true;
default:
BREAK_TO_DEBUGGER();
diff --git a/drivers/gpu/drm/amd/display/dc/inc/core_types.h b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
index 943240e2809e..555d4d9e1454 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/core_types.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/core_types.h
@@ -33,9 +33,7 @@
#include "dc_bios_types.h"
#include "mem_input.h"
#include "hubp.h"
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "mpc.h"
-#endif
#include "dwb.h"
#include "mcif_wb.h"
#include "panel_cntl.h"
@@ -54,6 +52,7 @@ void enable_surface_flip_reporting(struct dc_plane_state *plane_state,
#ifdef CONFIG_DRM_AMD_DC_HDCP
#include "dm_cp_psp.h"
#endif
+#include "link_hwss.h"
/************ link *****************/
struct link_init_data {
@@ -180,7 +179,6 @@ struct resource_funcs {
void (*update_bw_bounding_box)(
struct dc *dc,
struct clk_bw_params *bw_params);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool (*acquire_post_bldn_3dlut)(
struct resource_context *res_ctx,
const struct resource_pool *pool,
@@ -193,7 +191,7 @@ struct resource_funcs {
const struct resource_pool *pool,
struct dc_3dlut **lut,
struct dc_transfer_func **shaper);
-#endif
+
enum dc_status (*add_dsc_to_stream_resource)(
struct dc *dc, struct dc_state *state,
struct dc_stream_state *stream);
@@ -249,16 +247,13 @@ struct resource_pool {
/* Number of USB4 DPIA (DisplayPort Input Adapter) link objects created.*/
unsigned int usb4_dpia_count;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
unsigned int hpo_dp_stream_enc_count;
struct hpo_dp_stream_encoder *hpo_dp_stream_enc[MAX_HPO_DP2_ENCODERS];
unsigned int hpo_dp_link_enc_count;
struct hpo_dp_link_encoder *hpo_dp_link_enc[MAX_HPO_DP2_LINK_ENCODERS];
-#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct dc_3dlut *mpc_lut[MAX_PIPES];
struct dc_transfer_func *mpc_shaper[MAX_PIPES];
-#endif
+
struct {
unsigned int xtalin_clock_inKhz;
unsigned int dccg_ref_clock_inKhz;
@@ -287,9 +282,7 @@ struct resource_pool {
struct dmcu *dmcu;
struct dmub_psr *psr;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct abm *multiple_abms[MAX_PIPES];
-#endif
const struct resource_funcs *funcs;
const struct resource_caps *res_cap;
@@ -307,9 +300,7 @@ struct stream_resource {
struct display_stream_compressor *dsc;
struct timing_generator *tg;
struct stream_encoder *stream_enc;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct hpo_dp_stream_encoder *hpo_dp_stream_enc;
-#endif
struct audio *audio;
struct pixel_clk_params pix_clk_params;
@@ -334,18 +325,12 @@ struct plane_resource {
struct dcn_fe_bandwidth bw;
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#define LINK_RES_HPO_DP_REC_MAP__MASK 0xFFFF
#define LINK_RES_HPO_DP_REC_MAP__SHIFT 0
-#endif
/* all mappable hardware resources used to enable a link */
struct link_resource {
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct hpo_dp_link_encoder *hpo_dp_link_enc;
-#else
- void *dummy;
-#endif
};
union pipe_update_flags {
@@ -389,7 +374,6 @@ struct pipe_ctx {
struct pipe_ctx *next_odm_pipe;
struct pipe_ctx *prev_odm_pipe;
-#ifdef CONFIG_DRM_AMD_DC_DCN
struct _vcs_dpi_display_dlg_regs_st dlg_regs;
struct _vcs_dpi_display_ttu_regs_st ttu_regs;
struct _vcs_dpi_display_rq_regs_st rq_regs;
@@ -399,7 +383,7 @@ struct pipe_ctx {
struct _vcs_dpi_display_e2e_pipe_params_st dml_input;
int det_buffer_size_kb;
bool unbounded_req;
-#endif
+
union pipe_update_flags update_flags;
struct dwbc *dwbc;
struct mcif_wb *mcif_wb;
@@ -425,14 +409,10 @@ struct resource_context {
uint8_t dp_clock_source_ref_count;
bool is_dsc_acquired[MAX_PIPES];
struct link_enc_cfg_context link_enc_cfg_ctx;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool is_hpo_dp_stream_enc_acquired[MAX_HPO_DP2_ENCODERS];
unsigned int hpo_dp_link_enc_to_link_idx[MAX_HPO_DP2_LINK_ENCODERS];
int hpo_dp_link_enc_ref_cnts[MAX_HPO_DP2_LINK_ENCODERS];
-#endif
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool is_mpc_3dlut_acquired[MAX_PIPES];
-#endif
};
struct dce_bw_output {
@@ -495,9 +475,7 @@ struct dc_state {
/* Note: these are big structures, do *not* put on stack! */
struct dm_pp_display_configuration pp_display_cfg;
-#ifdef CONFIG_DRM_AMD_DC_DCN
struct dcn_bw_internal_vars dcn_bw_vars;
-#endif
struct clk_mgr *clk_mgr;
@@ -508,4 +486,11 @@ struct dc_state {
} perf_params;
};
+struct dc_bounding_box_max_clk {
+ int max_dcfclk_mhz;
+ int max_dispclk_mhz;
+ int max_dppclk_mhz;
+ int max_phyclk_mhz;
+};
+
#endif /* _CORE_TYPES_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
index cd52813a8432..a3c1e9c56d8b 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dp.h
@@ -33,6 +33,7 @@
#define MAX_MTP_SLOT_COUNT 64
#define DP_REPEATER_CONFIGURATION_AND_STATUS_SIZE 0x50
#define TRAINING_AUX_RD_INTERVAL 100 //us
+#define LINK_AUX_WAKE_TIMEOUT_MS 1500 // Timeout when trying to wake unresponsive DPRX.
struct dc_link;
struct dc_stream_state;
@@ -54,22 +55,13 @@ enum {
PEAK_FACTOR_X1000 = 1006,
};
-bool dp_verify_link_cap(
- struct dc_link *link,
- const struct link_resource *link_res,
- struct dc_link_settings *known_limit_link_setting,
- int *fail_count);
+struct dc_link_settings dp_get_max_link_cap(struct dc_link *link);
bool dp_verify_link_cap_with_retries(
struct dc_link *link,
- const struct link_resource *link_res,
struct dc_link_settings *known_limit_link_setting,
int attempts);
-bool dp_verify_mst_link_cap(
- struct dc_link *link,
- const struct link_resource *link_res);
-
bool dp_validate_mode_timing(
struct dc_link *link,
const struct dc_crtc_timing *timing);
@@ -114,6 +106,9 @@ void dp_set_panel_mode(struct dc_link *link, enum dp_panel_mode panel_mode);
bool dp_overwrite_extended_receiver_cap(struct dc_link *link);
void dpcd_set_source_specific_data(struct dc_link *link);
+
+void dpcd_write_cable_id_to_dprx(struct dc_link *link);
+
/* Write DPCD link configuration data. */
enum dc_status dpcd_set_link_settings(
struct dc_link *link,
@@ -153,12 +148,12 @@ bool dp_is_max_vs_reached(
void dp_hw_to_dpcd_lane_settings(
const struct link_training_settings *lt_settings,
const struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
- union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
+ union dpcd_training_lane dpcd_lane_settings[]);
void dp_decide_lane_settings(
const struct link_training_settings *lt_settings,
const union lane_adjust ln_adjust[LANE_COUNT_DP_MAX],
struct dc_lane_settings hw_lane_settings[LANE_COUNT_DP_MAX],
- union dpcd_training_lane dpcd_lane_settings[LANE_COUNT_DP_MAX]);
+ union dpcd_training_lane dpcd_lane_settings[]);
uint32_t dp_translate_training_aux_read_interval(uint32_t dpcd_aux_read_interval);
@@ -173,7 +168,6 @@ uint8_t dc_dp_initialize_scrambling_data_symbols(
enum dc_status dp_set_fec_ready(struct dc_link *link, const struct link_resource *link_res, bool ready);
void dp_set_fec_enable(struct dc_link *link, bool enable);
-struct link_encoder *dp_get_link_enc(struct dc_link *link);
bool dp_set_dsc_enable(struct pipe_ctx *pipe_ctx, bool enable);
bool dp_set_dsc_pps_sdp(struct pipe_ctx *pipe_ctx, bool enable, bool immediate_update);
void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable);
@@ -222,8 +216,47 @@ void disable_dp_hpo_output(struct dc_link *link,
enum signal_type signal);
void setup_dp_hpo_stream(struct pipe_ctx *pipe_ctx, bool enable);
bool is_dp_128b_132b_signal(struct pipe_ctx *pipe_ctx);
-void reset_dp_hpo_stream_encoders_for_link(struct dc_link *link);
bool dp_retrieve_lttpr_cap(struct dc_link *link);
void edp_panel_backlight_power_on(struct dc_link *link);
+void dp_receiver_power_ctrl(struct dc_link *link, bool on);
+void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode);
+void dp_enable_link_phy(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings);
+void edp_add_delay_for_T9(struct dc_link *link);
+bool edp_receiver_ready_T9(struct dc_link *link);
+bool edp_receiver_ready_T7(struct dc_link *link);
+
+void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res,
+ enum signal_type signal);
+
+void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res,
+ enum signal_type signal);
+
+bool dp_set_hw_training_pattern(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum dc_dp_training_pattern pattern,
+ uint32_t offset);
+
+void dp_set_hw_lane_settings(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct link_training_settings *link_settings,
+ uint32_t offset);
+
+void dp_set_hw_test_pattern(
+ struct dc_link *link,
+ const struct link_resource *link_res,
+ enum dp_test_pattern test_pattern,
+ uint8_t *custom_pattern,
+ uint32_t custom_pattern_size);
+
+void dp_retrain_link_dp_test(struct dc_link *link,
+ struct dc_link_settings *link_setting,
+ bool skip_video_pattern);
#endif /* __DC_LINK_DP_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h
index 74dafd0f9d3d..39c1d1d07357 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dc_link_dpia.h
@@ -87,6 +87,11 @@ union dpia_set_config_data {
*/
enum dc_status dpcd_get_tunneling_device_data(struct dc_link *link);
+/* Query hot plug status of USB4 DP tunnel.
+ * Returns true if HPD high.
+ */
+bool dc_link_dpia_query_hpd_status(struct dc_link *link);
+
/* Train DP tunneling link for USB4 DPIA display endpoint.
* DPIA equivalent of dc_link_dp_perfrorm_link_training.
* Aborts link training upon detection of sink unplug.
diff --git a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h
index 337c0161e72d..806f3041db14 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/dcn_calcs.h
@@ -619,7 +619,7 @@ struct dcn_ip_params {
};
extern const struct dcn_ip_params dcn10_ip_defaults;
-bool dcn10_validate_bandwidth(
+bool dcn_validate_bandwidth(
struct dc *dc,
struct dc_state *context,
bool fast_validate);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
index c920c4b6077d..b5570aa8e39d 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/clk_mgr.h
@@ -91,6 +91,7 @@ struct clk_limit_table_entry {
unsigned int dispclk_mhz;
unsigned int dppclk_mhz;
unsigned int phyclk_mhz;
+ unsigned int phyclk_d18_mhz;
unsigned int wck_ratio;
};
@@ -236,6 +237,7 @@ struct clk_mgr_funcs {
bool safe_to_lower);
int (*get_dp_ref_clk_frequency)(struct clk_mgr *clk_mgr);
+ int (*get_dtb_ref_clk_frequency)(struct clk_mgr *clk_mgr);
void (*set_low_power_state)(struct clk_mgr *clk_mgr);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
index c940fdfda144..c7021915bac8 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
@@ -60,8 +60,17 @@ struct dccg {
const struct dccg_funcs *funcs;
int pipe_dppclk_khz[MAX_PIPES];
int ref_dppclk;
- int dtbclk_khz[MAX_PIPES];
- int audio_dtbclk_khz;
+ //int dtbclk_khz[MAX_PIPES];/* TODO needs to be removed */
+ //int audio_dtbclk_khz;/* TODO needs to be removed */
+ int ref_dtbclk_khz;/* TODO needs to be removed */
+};
+
+struct dtbclk_dto_params {
+ const struct dc_crtc_timing *timing;
+ int otg_inst;
+ int pixclk_khz;
+ int req_audio_dtbclk_khz;
+ int num_odm_segments;
int ref_dtbclk_khz;
};
@@ -79,7 +88,7 @@ struct dccg_funcs {
void (*otg_drop_pixel)(struct dccg *dccg,
uint32_t otg_inst);
void (*dccg_init)(struct dccg *dccg);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
+
void (*set_dpstreamclk)(
struct dccg *dccg,
enum hdmistreamclk_source src,
@@ -102,7 +111,7 @@ struct dccg_funcs {
void (*disable_symclk32_le)(
struct dccg *dccg,
int hpo_le_inst);
-#endif
+
void (*set_physymclk)(
struct dccg *dccg,
int phy_inst,
@@ -111,10 +120,7 @@ struct dccg_funcs {
void (*set_dtbclk_dto)(
struct dccg *dccg,
- int dtbclk_inst,
- int req_dtbclk_khz,
- int num_odm_segments,
- const struct dc_crtc_timing *timing);
+ struct dtbclk_dto_params *dto_params);
void (*set_audio_dtbclk_dto)(
struct dccg *dccg,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
index 713f5558f5e1..9195dec294c2 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
@@ -154,6 +154,8 @@ struct hubbub_funcs {
bool (*is_allow_self_refresh_enabled)(struct hubbub *hubbub);
void (*allow_self_refresh_control)(struct hubbub *hubbub, bool allow);
+ bool (*verify_allow_pstate_change_high)(struct hubbub *hubbub);
+
void (*apply_DEDCN21_147_wa)(struct hubbub *hubbub);
void (*force_wm_propagate_to_pipes)(struct hubbub *hubbub);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
index 346f0ba73e86..d7b8d586b523 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
@@ -104,6 +104,7 @@ struct dsc_funcs {
uint8_t *dsc_packed_pps);
void (*dsc_enable)(struct display_stream_compressor *dsc, int opp_pipe);
void (*dsc_disable)(struct display_stream_compressor *dsc);
+ void (*dsc_disconnect)(struct display_stream_compressor *dsc);
};
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
index 2c031586f4e6..ad69d78c4ac3 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hubp.h
@@ -195,6 +195,10 @@ struct hubp_funcs {
void (*hubp_set_flip_int)(struct hubp *hubp);
+ void (*program_extended_blank)(struct hubp *hubp,
+ unsigned int min_dst_y_next_start_optimized);
+
+ void (*hubp_wait_pipe_read_start)(struct hubp *hubp);
};
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
index 10ecbc667ffa..d89bd55f110f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/hw_shared.h
@@ -38,10 +38,8 @@
#define MAX_PIPES 6
#define MAX_DIG_LINK_ENCODERS 7
#define MAX_DWB_PIPES 1
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#define MAX_HPO_DP2_ENCODERS 4
#define MAX_HPO_DP2_LINK_ENCODERS 2
-#endif
struct gamma_curve {
uint32_t offset;
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
index 2ce15cd10d80..2013a70603ae 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h
@@ -162,7 +162,8 @@ struct link_encoder_funcs {
void (*disable_output)(struct link_encoder *link_enc,
enum signal_type signal);
void (*dp_set_lane_settings)(struct link_encoder *enc,
- const struct link_training_settings *link_settings);
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
void (*dp_set_phy_pattern)(struct link_encoder *enc,
const struct encoder_set_dp_phy_pattern_param *para);
void (*update_mst_stream_allocation_table)(
@@ -220,7 +221,6 @@ enum link_enc_cfg_mode {
LINK_ENC_CFG_TRANSIENT /* During commit state - use state to be committed. */
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dp2_link_mode {
DP2_LINK_TRAINING_TPS1,
DP2_LINK_TRAINING_TPS2,
@@ -306,6 +306,5 @@ struct hpo_dp_link_encoder_funcs {
const struct dc_link_settings *link_settings,
uint8_t ffe_preset);
};
-#endif
#endif /* LINK_ENCODER_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h
index 48eac622c6a0..24af9d80b937 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/panel_cntl.h
@@ -39,6 +39,7 @@ struct panel_cntl_backlight_registers {
unsigned int BL_PWM_CNTL2;
unsigned int BL_PWM_PERIOD_CNTL;
unsigned int LVTMA_PWRSEQ_REF_DIV_BL_PWM_REF_DIV;
+ unsigned int PANEL_PWRSEQ_REF_DIV2;
};
struct panel_cntl_funcs {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
index c88e113b94d1..678c2065e5e8 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/stream_encoder.h
@@ -245,7 +245,6 @@ struct stream_encoder_funcs {
struct stream_encoder *enc);
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct hpo_dp_stream_encoder_state {
uint32_t stream_enc_enabled;
uint32_t vid_stream_enabled;
@@ -324,7 +323,10 @@ struct hpo_dp_stream_encoder_funcs {
void (*read_state)(
struct hpo_dp_stream_encoder *enc,
struct hpo_dp_stream_encoder_state *state);
+
+ void (*set_hblank_min_symbol_width)(
+ struct hpo_dp_stream_encoder *enc,
+ uint16_t width);
};
-#endif
#endif /* STREAM_ENCODER_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
index c29320b3855d..554d2e33bd7f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
@@ -100,9 +100,7 @@ enum crc_selection {
enum otg_out_mux_dest {
OUT_MUX_DIO = 0,
-#if defined(CONFIG_DRM_AMD_DC_DCN)
OUT_MUX_HPO_DP = 2,
-#endif
};
enum h_timing_div_mode {
@@ -312,6 +310,8 @@ struct timing_generator_funcs {
uint32_t slave_pixel_clock_100Hz,
uint8_t master_clock_divider,
uint8_t slave_clock_divider);
+
+ void (*init_odm)(struct timing_generator *tg);
};
#endif
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
index c2008258c50a..8c2f190c4712 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h
@@ -41,9 +41,8 @@ struct dce_hwseq_wa {
bool DEGVIDCN10_254;
bool DEGVIDCN21;
bool disallow_self_refresh_during_multi_plane_transition;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
bool dp_hpo_and_otg_sequence;
-#endif
+ bool wait_hubpret_read_start_during_mpo_transition;
};
struct hwseq_wa_state {
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h b/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h
index 3f12b1600d2a..d561f86d503c 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_dpcd.h
@@ -27,7 +27,7 @@
#define __LINK_DPCD_H__
#include <inc/core_status.h>
#include <dc_link.h>
-#include <inc/link_hwss.h>
+#include <dc_link_dp.h>
enum dc_status core_link_read_dpcd(
struct dc_link *link,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h b/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h
index a4e43b4826e0..c6f6baa6e677 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_enc_cfg.h
@@ -40,6 +40,11 @@ void link_enc_cfg_init(
struct dc_state *state);
/*
+ * Copies a link encoder assignment from another state.
+ */
+void link_enc_cfg_copy(const struct dc_state *src_ctx, struct dc_state *dst_ctx);
+
+/*
* Algorithm for assigning available DIG link encoders to streams.
*
* Update link_enc_assignments table and link_enc_avail list accordingly in
@@ -96,6 +101,9 @@ struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream(
struct dc *dc,
const struct dc_stream_state *stream);
+/* Return DIG link encoder. NULL if unused. */
+struct link_encoder *link_enc_cfg_get_link_enc(const struct dc_link *link);
+
/* Return true if encoder available to use. */
bool link_enc_cfg_is_link_enc_avail(struct dc *dc, enum engine_id eng_id, struct dc_link *link);
diff --git a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
index 69d63763a10e..e6c49ef8b584 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/link_hwss.h
@@ -26,50 +26,59 @@
#ifndef __DC_LINK_HWSS_H__
#define __DC_LINK_HWSS_H__
-struct gpio *get_hpd_gpio(struct dc_bios *dcb,
- struct graphics_object_id link_id,
- struct gpio_service *gpio_service);
+/* include basic type headers only */
+#include "dc_dp_types.h"
+#include "signal_types.h"
+#include "grph_object_id.h"
+#include "fixed31_32.h"
-void dp_enable_link_phy(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum signal_type signal,
- enum clock_source_id clock_source,
- const struct dc_link_settings *link_settings);
+/* forward declare dc core types */
+struct dc_link;
+struct link_resource;
+struct pipe_ctx;
+struct encoder_set_dp_phy_pattern_param;
+struct link_mst_stream_allocation_table;
-void dp_receiver_power_ctrl(struct dc_link *link, bool on);
-void dp_source_sequence_trace(struct dc_link *link, uint8_t dp_test_mode);
-void edp_add_delay_for_T9(struct dc_link *link);
-bool edp_receiver_ready_T9(struct dc_link *link);
-bool edp_receiver_ready_T7(struct dc_link *link);
+struct link_hwss_ext {
+ /* function pointers below may require to check for NULL if caller
+ * considers missing implementation as expected in some cases or none
+ * critical to be investigated immediately
+ * *********************************************************************
+ */
+ void (*set_hblank_min_symbol_width)(struct pipe_ctx *pipe_ctx,
+ const struct dc_link_settings *link_settings,
+ struct fixed31_32 throttled_vcp_size);
+ void (*set_throttled_vcp_size)(struct pipe_ctx *pipe_ctx,
+ struct fixed31_32 throttled_vcp_size);
+ void (*enable_dp_link_output)(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings);
+ void (*disable_dp_link_output)(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal);
+ void (*set_dp_link_test_pattern)(struct dc_link *link,
+ const struct link_resource *link_res,
+ struct encoder_set_dp_phy_pattern_param *tp_params);
+ void (*set_dp_lane_settings)(struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
+ void (*update_stream_allocation_table)(struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct link_mst_stream_allocation_table *table);
+};
-void dp_disable_link_phy(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal);
-
-void dp_disable_link_phy_mst(struct dc_link *link, const struct link_resource *link_res,
- enum signal_type signal);
-
-bool dp_set_hw_training_pattern(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum dc_dp_training_pattern pattern,
- uint32_t offset);
-
-void dp_set_hw_lane_settings(
- struct dc_link *link,
- const struct link_resource *link_res,
- const struct link_training_settings *link_settings,
- uint32_t offset);
-
-void dp_set_hw_test_pattern(
- struct dc_link *link,
- const struct link_resource *link_res,
- enum dp_test_pattern test_pattern,
- uint8_t *custom_pattern,
- uint32_t custom_pattern_size);
-
-void dp_retrain_link_dp_test(struct dc_link *link,
- struct dc_link_settings *link_setting,
- bool skip_video_pattern);
+struct link_hwss {
+ struct link_hwss_ext ext;
+ /* function pointers below MUST be assigned to all types of link_hwss
+ * *********************************************************************
+ */
+ void (*setup_stream_encoder)(struct pipe_ctx *pipe_ctx);
+ void (*reset_stream_encoder)(struct pipe_ctx *pipe_ctx);
+ void (*setup_stream_attribute)(struct pipe_ctx *pipe_ctx);
+};
#endif /* __DC_LINK_HWSS_H__ */
+
diff --git a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h
index 2470405e996b..a402df225a76 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/reg_helper.h
@@ -498,6 +498,40 @@ uint32_t generic_indirect_reg_update_ex(const struct dc_context *ctx,
uint8_t shift1, uint32_t mask1, uint32_t field_value1,
...);
+/* indirect register access
+ * underlying implementation determines which index/data pair to be used
+ * in a synchronous way
+ */
+#define IX_REG_SET_N_SYNC(index, n, initial_val, ...) \
+ generic_indirect_reg_update_ex_sync(CTX, \
+ IND_REG(index), \
+ initial_val, \
+ n, __VA_ARGS__)
+
+#define IX_REG_SET_2_SYNC(index, init_value, f1, v1, f2, v2) \
+ IX_REG_SET_N_SYNC(index, 2, init_value, \
+ FN(reg, f1), v1,\
+ FN(reg, f2), v2)
+
+#define IX_REG_GET_N_SYNC(index, n, ...) \
+ generic_indirect_reg_get_sync(CTX, \
+ IND_REG(index), \
+ n, __VA_ARGS__)
+
+#define IX_REG_GET_SYNC(index, field, val) \
+ IX_REG_GET_N_SYNC(index, 1, \
+ FN(data_reg_name, field), val)
+
+uint32_t generic_indirect_reg_get_sync(const struct dc_context *ctx,
+ uint32_t index, int n,
+ uint8_t shift1, uint32_t mask1, uint32_t *field_value1,
+ ...);
+
+uint32_t generic_indirect_reg_update_ex_sync(const struct dc_context *ctx,
+ uint32_t index, uint32_t reg_val, int n,
+ uint8_t shift1, uint32_t mask1, uint32_t field_value1,
+ ...);
+
/* register offload macros
*
* instead of MMIO to register directly, in some cases we want
diff --git a/drivers/gpu/drm/amd/display/dc/inc/resource.h b/drivers/gpu/drm/amd/display/dc/inc/resource.h
index dbfe6690ded8..2369f38ed06f 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/resource.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/resource.h
@@ -54,10 +54,8 @@ struct resource_caps {
int num_dsc;
unsigned int num_dig_link_enc; // Total number of DIGs (digital encoders) in DIO (Display Input/Output).
unsigned int num_usb4_dpia; // Total number of USB4 DPIA (DisplayPort Input Adapters).
-#if defined(CONFIG_DRM_AMD_DC_DCN)
int num_hpo_dp_stream_encoder;
int num_hpo_dp_link_encoder;
-#endif
int num_mpc_3dlut;
};
@@ -77,14 +75,12 @@ struct resource_create_funcs {
struct stream_encoder *(*create_stream_encoder)(
enum engine_id eng_id, struct dc_context *ctx);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
struct hpo_dp_stream_encoder *(*create_hpo_dp_stream_encoder)(
enum engine_id eng_id, struct dc_context *ctx);
struct hpo_dp_link_encoder *(*create_hpo_dp_link_encoder)(
uint8_t inst,
struct dc_context *ctx);
-#endif
struct dce_hwseq *(*create_hwseq)(
struct dc_context *ctx);
@@ -205,12 +201,9 @@ int get_num_mpc_splits(struct pipe_ctx *pipe);
int get_num_odm_splits(struct pipe_ctx *pipe);
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-struct hpo_dp_link_encoder *resource_get_hpo_dp_link_enc_for_det_lt(
- const struct resource_context *res_ctx,
- const struct resource_pool *pool,
- const struct dc_link *link);
-#endif
+bool get_temp_dp_link_res(struct dc_link *link,
+ struct link_resource *link_res,
+ struct dc_link_settings *link_settings);
void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
struct dc_state *context);
@@ -221,4 +214,7 @@ void check_syncd_pipes_for_disabled_master_pipe(struct dc *dc,
uint8_t resource_transmitter_to_phy_idx(const struct dc *dc, enum transmitter transmitter);
+const struct link_hwss *get_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res);
+
#endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */
diff --git a/drivers/gpu/drm/amd/display/dc/irq/Makefile b/drivers/gpu/drm/amd/display/dc/irq/Makefile
index fd739aecf104..5f49048dde47 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/irq/Makefile
@@ -71,7 +71,6 @@ AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCE12)
###############################################################################
# DCN 1x
###############################################################################
-ifdef CONFIG_DRM_AMD_DC_DCN
IRQ_DCN1 = irq_service_dcn10.o
AMD_DAL_IRQ_DCN1 = $(addprefix $(AMDDALPATH)/dc/irq/dcn10/,$(IRQ_DCN1))
@@ -136,4 +135,12 @@ IRQ_DCN31 = irq_service_dcn31.o
AMD_DAL_IRQ_DCN31= $(addprefix $(AMDDALPATH)/dc/irq/dcn31/,$(IRQ_DCN31))
AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN31)
-endif
+
+###############################################################################
+# DCN 315
+###############################################################################
+IRQ_DCN315 = irq_service_dcn315.o
+
+AMD_DAL_IRQ_DCN315= $(addprefix $(AMDDALPATH)/dc/irq/dcn315/,$(IRQ_DCN315))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_IRQ_DCN315)
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
index c4b067d01895..93c31111500b 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn20/irq_service_dcn20.c
@@ -40,7 +40,7 @@
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
-enum dc_irq_source to_dal_irq_source_dcn20(
+static enum dc_irq_source to_dal_irq_source_dcn20(
struct irq_service *irq_service,
uint32_t src_id,
uint32_t ext_id)
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
index aa708b61142f..45f99351a0ab 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn201/irq_service_dcn201.c
@@ -138,11 +138,6 @@ static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
.ack = NULL
};
-static const struct irq_source_info_funcs dmub_outbox_irq_info_funcs = {
- .set = NULL,
- .ack = NULL
-};
-
#undef BASE_INNER
#define BASE_INNER(seg) DMU_BASE__INST0_SEG ## seg
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
index 0f15bcada4e9..717977aec6d0 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn21/irq_service_dcn21.c
@@ -265,14 +265,6 @@ static const struct irq_source_info_funcs vline0_irq_info_funcs = {
.funcs = &pflip_irq_info_funcs\
}
-#define vupdate_int_entry(reg_num)\
- [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
- IRQ_REG_ENTRY(OTG, reg_num,\
- OTG_GLOBAL_SYNC_STATUS, VUPDATE_INT_EN,\
- OTG_GLOBAL_SYNC_STATUS, VUPDATE_EVENT_CLEAR),\
- .funcs = &vblank_irq_info_funcs\
- }
-
/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic
* of DCE's DC_IRQ_SOURCE_VUPDATEx.
*/
@@ -401,12 +393,6 @@ irq_source_info_dcn21[DAL_IRQ_SOURCES_NUMBER] = {
dc_underflow_int_entry(6),
[DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
[DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
- vupdate_int_entry(0),
- vupdate_int_entry(1),
- vupdate_int_entry(2),
- vupdate_int_entry(3),
- vupdate_int_entry(4),
- vupdate_int_entry(5),
vupdate_no_lock_int_entry(0),
vupdate_no_lock_int_entry(1),
vupdate_no_lock_int_entry(2),
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
index 914ce2ce1c2f..146cd1819912 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.c
@@ -22,8 +22,6 @@
*
*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-
#include "dm_services.h"
#include "include/logger_interface.h"
@@ -37,8 +35,8 @@
#include "nbio/nbio_7_4_offset.h"
-#include "dcn/dpcs_3_0_0_offset.h"
-#include "dcn/dpcs_3_0_0_sh_mask.h"
+#include "dpcs/dpcs_3_0_0_offset.h"
+#include "dpcs/dpcs_3_0_0_sh_mask.h"
#include "mmhub/mmhub_2_0_0_offset.h"
#include "mmhub/mmhub_2_0_0_sh_mask.h"
@@ -47,7 +45,7 @@
#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
-enum dc_irq_source to_dal_irq_source_dcn30(
+static enum dc_irq_source to_dal_irq_source_dcn30(
struct irq_service *irq_service,
uint32_t src_id,
uint32_t ext_id)
@@ -450,4 +448,3 @@ struct irq_service *dal_irq_service_dcn30_create(
return irq_service;
}
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.h b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.h
index 080e21239688..c6c7b184d3c1 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.h
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn30/irq_service_dcn30.h
@@ -23,8 +23,6 @@
*
*/
-#if defined(CONFIG_DRM_AMD_DC_DCN)
-
#ifndef __DAL_IRQ_SERVICE_DCN30_H__
#define __DAL_IRQ_SERVICE_DCN30_H__
@@ -34,4 +32,3 @@ struct irq_service *dal_irq_service_dcn30_create(
struct irq_service_init_data *init_data);
#endif /* __DAL_IRQ_SERVICE_DCN30_H__ */
-#endif
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
new file mode 100644
index 000000000000..e722171f0d2d
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.c
@@ -0,0 +1,438 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#include "dm_services.h"
+#include "include/logger_interface.h"
+#include "../dce110/irq_service_dce110.h"
+
+
+#include "dcn/dcn_3_1_5_offset.h"
+#include "dcn/dcn_3_1_5_sh_mask.h"
+
+#include "irq_service_dcn315.h"
+
+#include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
+
+#define DCN_BASE__INST0_SEG0 0x00000012
+#define DCN_BASE__INST0_SEG1 0x000000C0
+#define DCN_BASE__INST0_SEG2 0x000034C0
+#define DCN_BASE__INST0_SEG3 0x00009000
+#define DCN_BASE__INST0_SEG4 0x02403C00
+#define DCN_BASE__INST0_SEG5 0
+
+static enum dc_irq_source to_dal_irq_source_dcn315(
+ struct irq_service *irq_service,
+ uint32_t src_id,
+ uint32_t ext_id)
+{
+ switch (src_id) {
+ case DCN_1_0__SRCID__DC_D1_OTG_VSTARTUP:
+ return DC_IRQ_SOURCE_VBLANK1;
+ case DCN_1_0__SRCID__DC_D2_OTG_VSTARTUP:
+ return DC_IRQ_SOURCE_VBLANK2;
+ case DCN_1_0__SRCID__DC_D3_OTG_VSTARTUP:
+ return DC_IRQ_SOURCE_VBLANK3;
+ case DCN_1_0__SRCID__DC_D4_OTG_VSTARTUP:
+ return DC_IRQ_SOURCE_VBLANK4;
+ case DCN_1_0__SRCID__DC_D5_OTG_VSTARTUP:
+ return DC_IRQ_SOURCE_VBLANK5;
+ case DCN_1_0__SRCID__DC_D6_OTG_VSTARTUP:
+ return DC_IRQ_SOURCE_VBLANK6;
+ case DCN_1_0__SRCID__OTG1_VERTICAL_INTERRUPT0_CONTROL:
+ return DC_IRQ_SOURCE_DC1_VLINE0;
+ case DCN_1_0__SRCID__OTG2_VERTICAL_INTERRUPT0_CONTROL:
+ return DC_IRQ_SOURCE_DC2_VLINE0;
+ case DCN_1_0__SRCID__OTG3_VERTICAL_INTERRUPT0_CONTROL:
+ return DC_IRQ_SOURCE_DC3_VLINE0;
+ case DCN_1_0__SRCID__OTG4_VERTICAL_INTERRUPT0_CONTROL:
+ return DC_IRQ_SOURCE_DC4_VLINE0;
+ case DCN_1_0__SRCID__OTG5_VERTICAL_INTERRUPT0_CONTROL:
+ return DC_IRQ_SOURCE_DC5_VLINE0;
+ case DCN_1_0__SRCID__OTG6_VERTICAL_INTERRUPT0_CONTROL:
+ return DC_IRQ_SOURCE_DC6_VLINE0;
+ case DCN_1_0__SRCID__HUBP0_FLIP_INTERRUPT:
+ return DC_IRQ_SOURCE_PFLIP1;
+ case DCN_1_0__SRCID__HUBP1_FLIP_INTERRUPT:
+ return DC_IRQ_SOURCE_PFLIP2;
+ case DCN_1_0__SRCID__HUBP2_FLIP_INTERRUPT:
+ return DC_IRQ_SOURCE_PFLIP3;
+ case DCN_1_0__SRCID__HUBP3_FLIP_INTERRUPT:
+ return DC_IRQ_SOURCE_PFLIP4;
+ case DCN_1_0__SRCID__HUBP4_FLIP_INTERRUPT:
+ return DC_IRQ_SOURCE_PFLIP5;
+ case DCN_1_0__SRCID__HUBP5_FLIP_INTERRUPT:
+ return DC_IRQ_SOURCE_PFLIP6;
+ case DCN_1_0__SRCID__OTG0_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
+ return DC_IRQ_SOURCE_VUPDATE1;
+ case DCN_1_0__SRCID__OTG1_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
+ return DC_IRQ_SOURCE_VUPDATE2;
+ case DCN_1_0__SRCID__OTG2_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
+ return DC_IRQ_SOURCE_VUPDATE3;
+ case DCN_1_0__SRCID__OTG3_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
+ return DC_IRQ_SOURCE_VUPDATE4;
+ case DCN_1_0__SRCID__OTG4_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
+ return DC_IRQ_SOURCE_VUPDATE5;
+ case DCN_1_0__SRCID__OTG5_IHC_V_UPDATE_NO_LOCK_INTERRUPT:
+ return DC_IRQ_SOURCE_VUPDATE6;
+ case DCN_1_0__SRCID__DMCUB_OUTBOX_LOW_PRIORITY_READY_INT:
+ return DC_IRQ_SOURCE_DMCUB_OUTBOX;
+ case DCN_1_0__SRCID__DC_HPD1_INT:
+ /* generic src_id for all HPD and HPDRX interrupts */
+ switch (ext_id) {
+ case DCN_1_0__CTXID__DC_HPD1_INT:
+ return DC_IRQ_SOURCE_HPD1;
+ case DCN_1_0__CTXID__DC_HPD2_INT:
+ return DC_IRQ_SOURCE_HPD2;
+ case DCN_1_0__CTXID__DC_HPD3_INT:
+ return DC_IRQ_SOURCE_HPD3;
+ case DCN_1_0__CTXID__DC_HPD4_INT:
+ return DC_IRQ_SOURCE_HPD4;
+ case DCN_1_0__CTXID__DC_HPD5_INT:
+ return DC_IRQ_SOURCE_HPD5;
+ case DCN_1_0__CTXID__DC_HPD6_INT:
+ return DC_IRQ_SOURCE_HPD6;
+ case DCN_1_0__CTXID__DC_HPD1_RX_INT:
+ return DC_IRQ_SOURCE_HPD1RX;
+ case DCN_1_0__CTXID__DC_HPD2_RX_INT:
+ return DC_IRQ_SOURCE_HPD2RX;
+ case DCN_1_0__CTXID__DC_HPD3_RX_INT:
+ return DC_IRQ_SOURCE_HPD3RX;
+ case DCN_1_0__CTXID__DC_HPD4_RX_INT:
+ return DC_IRQ_SOURCE_HPD4RX;
+ case DCN_1_0__CTXID__DC_HPD5_RX_INT:
+ return DC_IRQ_SOURCE_HPD5RX;
+ case DCN_1_0__CTXID__DC_HPD6_RX_INT:
+ return DC_IRQ_SOURCE_HPD6RX;
+ default:
+ return DC_IRQ_SOURCE_INVALID;
+ }
+ break;
+
+ default:
+ return DC_IRQ_SOURCE_INVALID;
+ }
+}
+
+static bool hpd_ack(
+ struct irq_service *irq_service,
+ const struct irq_source_info *info)
+{
+ uint32_t addr = info->status_reg;
+ uint32_t value = dm_read_reg(irq_service->ctx, addr);
+ uint32_t current_status =
+ get_reg_field_value(
+ value,
+ HPD0_DC_HPD_INT_STATUS,
+ DC_HPD_SENSE_DELAYED);
+
+ dal_irq_service_ack_generic(irq_service, info);
+
+ value = dm_read_reg(irq_service->ctx, info->enable_reg);
+
+ set_reg_field_value(
+ value,
+ current_status ? 0 : 1,
+ HPD0_DC_HPD_INT_CONTROL,
+ DC_HPD_INT_POLARITY);
+
+ dm_write_reg(irq_service->ctx, info->enable_reg, value);
+
+ return true;
+}
+
+static const struct irq_source_info_funcs hpd_irq_info_funcs = {
+ .set = NULL,
+ .ack = hpd_ack
+};
+
+static const struct irq_source_info_funcs hpd_rx_irq_info_funcs = {
+ .set = NULL,
+ .ack = NULL
+};
+
+static const struct irq_source_info_funcs pflip_irq_info_funcs = {
+ .set = NULL,
+ .ack = NULL
+};
+
+static const struct irq_source_info_funcs vupdate_no_lock_irq_info_funcs = {
+ .set = NULL,
+ .ack = NULL
+};
+
+static const struct irq_source_info_funcs vblank_irq_info_funcs = {
+ .set = NULL,
+ .ack = NULL
+};
+
+static const struct irq_source_info_funcs outbox_irq_info_funcs = {
+ .set = NULL,
+ .ack = NULL
+};
+
+static const struct irq_source_info_funcs vline0_irq_info_funcs = {
+ .set = NULL,
+ .ack = NULL
+};
+
+#undef BASE_INNER
+#define BASE_INNER(seg) DCN_BASE__INST0_SEG ## seg
+
+/* compile time expand base address. */
+#define BASE(seg) \
+ BASE_INNER(seg)
+
+#define SRI(reg_name, block, id)\
+ BASE(reg ## block ## id ## _ ## reg_name ## _BASE_IDX) + \
+ reg ## block ## id ## _ ## reg_name
+
+#define SRI_DMUB(reg_name)\
+ BASE(reg ## reg_name ## _BASE_IDX) + \
+ reg ## reg_name
+
+#define IRQ_REG_ENTRY(block, reg_num, reg1, mask1, reg2, mask2)\
+ .enable_reg = SRI(reg1, block, reg_num),\
+ .enable_mask = \
+ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
+ .enable_value = {\
+ block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK,\
+ ~block ## reg_num ## _ ## reg1 ## __ ## mask1 ## _MASK \
+ },\
+ .ack_reg = SRI(reg2, block, reg_num),\
+ .ack_mask = \
+ block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK,\
+ .ack_value = \
+ block ## reg_num ## _ ## reg2 ## __ ## mask2 ## _MASK \
+
+#define IRQ_REG_ENTRY_DMUB(reg1, mask1, reg2, mask2)\
+ .enable_reg = SRI_DMUB(reg1),\
+ .enable_mask = \
+ reg1 ## __ ## mask1 ## _MASK,\
+ .enable_value = {\
+ reg1 ## __ ## mask1 ## _MASK,\
+ ~reg1 ## __ ## mask1 ## _MASK \
+ },\
+ .ack_reg = SRI_DMUB(reg2),\
+ .ack_mask = \
+ reg2 ## __ ## mask2 ## _MASK,\
+ .ack_value = \
+ reg2 ## __ ## mask2 ## _MASK \
+
+#define hpd_int_entry(reg_num)\
+ [DC_IRQ_SOURCE_HPD1 + reg_num] = {\
+ IRQ_REG_ENTRY(HPD, reg_num,\
+ DC_HPD_INT_CONTROL, DC_HPD_INT_EN,\
+ DC_HPD_INT_CONTROL, DC_HPD_INT_ACK),\
+ .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\
+ .funcs = &hpd_irq_info_funcs\
+ }
+
+#define hpd_rx_int_entry(reg_num)\
+ [DC_IRQ_SOURCE_HPD1RX + reg_num] = {\
+ IRQ_REG_ENTRY(HPD, reg_num,\
+ DC_HPD_INT_CONTROL, DC_HPD_RX_INT_EN,\
+ DC_HPD_INT_CONTROL, DC_HPD_RX_INT_ACK),\
+ .status_reg = SRI(DC_HPD_INT_STATUS, HPD, reg_num),\
+ .funcs = &hpd_rx_irq_info_funcs\
+ }
+#define pflip_int_entry(reg_num)\
+ [DC_IRQ_SOURCE_PFLIP1 + reg_num] = {\
+ IRQ_REG_ENTRY(HUBPREQ, reg_num,\
+ DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_INT_MASK,\
+ DCSURF_SURFACE_FLIP_INTERRUPT, SURFACE_FLIP_CLEAR),\
+ .funcs = &pflip_irq_info_funcs\
+ }
+
+/* vupdate_no_lock_int_entry maps to DC_IRQ_SOURCE_VUPDATEx, to match semantic
+ * of DCE's DC_IRQ_SOURCE_VUPDATEx.
+ */
+#define vupdate_no_lock_int_entry(reg_num)\
+ [DC_IRQ_SOURCE_VUPDATE1 + reg_num] = {\
+ IRQ_REG_ENTRY(OTG, reg_num,\
+ OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_INT_EN,\
+ OTG_GLOBAL_SYNC_STATUS, VUPDATE_NO_LOCK_EVENT_CLEAR),\
+ .funcs = &vupdate_no_lock_irq_info_funcs\
+ }
+
+#define vblank_int_entry(reg_num)\
+ [DC_IRQ_SOURCE_VBLANK1 + reg_num] = {\
+ IRQ_REG_ENTRY(OTG, reg_num,\
+ OTG_GLOBAL_SYNC_STATUS, VSTARTUP_INT_EN,\
+ OTG_GLOBAL_SYNC_STATUS, VSTARTUP_EVENT_CLEAR),\
+ .funcs = &vblank_irq_info_funcs\
+ }
+
+#define vline0_int_entry(reg_num)\
+ [DC_IRQ_SOURCE_DC1_VLINE0 + reg_num] = {\
+ IRQ_REG_ENTRY(OTG, reg_num,\
+ OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_INT_ENABLE,\
+ OTG_VERTICAL_INTERRUPT0_CONTROL, OTG_VERTICAL_INTERRUPT0_CLEAR),\
+ .funcs = &vline0_irq_info_funcs\
+ }
+#define dmub_outbox_int_entry()\
+ [DC_IRQ_SOURCE_DMCUB_OUTBOX] = {\
+ IRQ_REG_ENTRY_DMUB(\
+ DMCUB_INTERRUPT_ENABLE, DMCUB_OUTBOX1_READY_INT_EN,\
+ DMCUB_INTERRUPT_ACK, DMCUB_OUTBOX1_READY_INT_ACK),\
+ .funcs = &outbox_irq_info_funcs\
+ }
+
+#define dummy_irq_entry() \
+ {\
+ .funcs = &dummy_irq_info_funcs\
+ }
+
+#define i2c_int_entry(reg_num) \
+ [DC_IRQ_SOURCE_I2C_DDC ## reg_num] = dummy_irq_entry()
+
+#define dp_sink_int_entry(reg_num) \
+ [DC_IRQ_SOURCE_DPSINK ## reg_num] = dummy_irq_entry()
+
+#define gpio_pad_int_entry(reg_num) \
+ [DC_IRQ_SOURCE_GPIOPAD ## reg_num] = dummy_irq_entry()
+
+#define dc_underflow_int_entry(reg_num) \
+ [DC_IRQ_SOURCE_DC ## reg_num ## UNDERFLOW] = dummy_irq_entry()
+
+static const struct irq_source_info_funcs dummy_irq_info_funcs = {
+ .set = dal_irq_service_dummy_set,
+ .ack = dal_irq_service_dummy_ack
+};
+
+static const struct irq_source_info
+irq_source_info_dcn315[DAL_IRQ_SOURCES_NUMBER] = {
+ [DC_IRQ_SOURCE_INVALID] = dummy_irq_entry(),
+ hpd_int_entry(0),
+ hpd_int_entry(1),
+ hpd_int_entry(2),
+ hpd_int_entry(3),
+ hpd_int_entry(4),
+ hpd_rx_int_entry(0),
+ hpd_rx_int_entry(1),
+ hpd_rx_int_entry(2),
+ hpd_rx_int_entry(3),
+ hpd_rx_int_entry(4),
+ i2c_int_entry(1),
+ i2c_int_entry(2),
+ i2c_int_entry(3),
+ i2c_int_entry(4),
+ i2c_int_entry(5),
+ i2c_int_entry(6),
+ dp_sink_int_entry(1),
+ dp_sink_int_entry(2),
+ dp_sink_int_entry(3),
+ dp_sink_int_entry(4),
+ dp_sink_int_entry(5),
+ dp_sink_int_entry(6),
+ [DC_IRQ_SOURCE_TIMER] = dummy_irq_entry(),
+ pflip_int_entry(0),
+ pflip_int_entry(1),
+ pflip_int_entry(2),
+ pflip_int_entry(3),
+ [DC_IRQ_SOURCE_PFLIP5] = dummy_irq_entry(),
+ [DC_IRQ_SOURCE_PFLIP6] = dummy_irq_entry(),
+ [DC_IRQ_SOURCE_PFLIP_UNDERLAY0] = dummy_irq_entry(),
+ gpio_pad_int_entry(0),
+ gpio_pad_int_entry(1),
+ gpio_pad_int_entry(2),
+ gpio_pad_int_entry(3),
+ gpio_pad_int_entry(4),
+ gpio_pad_int_entry(5),
+ gpio_pad_int_entry(6),
+ gpio_pad_int_entry(7),
+ gpio_pad_int_entry(8),
+ gpio_pad_int_entry(9),
+ gpio_pad_int_entry(10),
+ gpio_pad_int_entry(11),
+ gpio_pad_int_entry(12),
+ gpio_pad_int_entry(13),
+ gpio_pad_int_entry(14),
+ gpio_pad_int_entry(15),
+ gpio_pad_int_entry(16),
+ gpio_pad_int_entry(17),
+ gpio_pad_int_entry(18),
+ gpio_pad_int_entry(19),
+ gpio_pad_int_entry(20),
+ gpio_pad_int_entry(21),
+ gpio_pad_int_entry(22),
+ gpio_pad_int_entry(23),
+ gpio_pad_int_entry(24),
+ gpio_pad_int_entry(25),
+ gpio_pad_int_entry(26),
+ gpio_pad_int_entry(27),
+ gpio_pad_int_entry(28),
+ gpio_pad_int_entry(29),
+ gpio_pad_int_entry(30),
+ dc_underflow_int_entry(1),
+ dc_underflow_int_entry(2),
+ dc_underflow_int_entry(3),
+ dc_underflow_int_entry(4),
+ dc_underflow_int_entry(5),
+ dc_underflow_int_entry(6),
+ [DC_IRQ_SOURCE_DMCU_SCP] = dummy_irq_entry(),
+ [DC_IRQ_SOURCE_VBIOS_SW] = dummy_irq_entry(),
+ vupdate_no_lock_int_entry(0),
+ vupdate_no_lock_int_entry(1),
+ vupdate_no_lock_int_entry(2),
+ vupdate_no_lock_int_entry(3),
+ vblank_int_entry(0),
+ vblank_int_entry(1),
+ vblank_int_entry(2),
+ vblank_int_entry(3),
+ vline0_int_entry(0),
+ vline0_int_entry(1),
+ vline0_int_entry(2),
+ vline0_int_entry(3),
+ [DC_IRQ_SOURCE_DC5_VLINE1] = dummy_irq_entry(),
+ [DC_IRQ_SOURCE_DC6_VLINE1] = dummy_irq_entry(),
+ dmub_outbox_int_entry(),
+};
+
+static const struct irq_service_funcs irq_service_funcs_dcn315 = {
+ .to_dal_irq_source = to_dal_irq_source_dcn315
+};
+
+static void dcn315_irq_construct(
+ struct irq_service *irq_service,
+ struct irq_service_init_data *init_data)
+{
+ dal_irq_service_construct(irq_service, init_data);
+
+ irq_service->info = irq_source_info_dcn315;
+ irq_service->funcs = &irq_service_funcs_dcn315;
+}
+
+struct irq_service *dal_irq_service_dcn315_create(
+ struct irq_service_init_data *init_data)
+{
+ struct irq_service *irq_service = kzalloc(sizeof(*irq_service),
+ GFP_KERNEL);
+
+ if (!irq_service)
+ return NULL;
+
+ dcn315_irq_construct(irq_service, init_data);
+ return irq_service;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.h b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.h
new file mode 100644
index 000000000000..a5a80486a8d6
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/irq/dcn315/irq_service_dcn315.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef __DAL_IRQ_SERVICE_DCN315_H__
+#define __DAL_IRQ_SERVICE_DCN315_H__
+
+#include "../irq_service.h"
+
+struct irq_service *dal_irq_service_dcn315_create(
+ struct irq_service_init_data *init_data);
+
+#endif /* __DAL_IRQ_SERVICE_DCN315_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
index a2a4fbeb83f8..cb38d4c527d4 100644
--- a/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
+++ b/drivers/gpu/drm/amd/display/dc/irq/irq_service.c
@@ -37,13 +37,8 @@
#endif
#include "dce80/irq_service_dce80.h"
-
#include "dce120/irq_service_dce120.h"
-
-
-#if defined(CONFIG_DRM_AMD_DC_DCN)
#include "dcn10/irq_service_dcn10.h"
-#endif
#include "reg_helper.h"
#include "irq_service.h"
diff --git a/drivers/gpu/drm/amd/display/dc/link/Makefile b/drivers/gpu/drm/amd/display/dc/link/Makefile
new file mode 100644
index 000000000000..054c2a727eb2
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright 2022 Advanced Micro Devices, Inc.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+# OTHER DEALINGS IN THE SOFTWARE.
+#
+# Makefile for the link sub-component of DAL.
+# It abstracts the control and status of back end pipe such as DIO, HPO, DPIA,
+# PHY, HPD, DDC and etc).
+
+LINK = link_hwss_dio.o link_hwss_dpia.o link_hwss_hpo_dp.o link_dp_trace.o
+
+AMD_DAL_LINK = $(addprefix $(AMDDALPATH)/dc/link/,$(LINK))
+
+AMD_DISPLAY_FILES += $(AMD_DAL_LINK)
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c b/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c
new file mode 100644
index 000000000000..2c1a3bfcdb50
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#include "dc_link.h"
+#include "link_dp_trace.h"
+
+void dp_trace_init(struct dc_link *link)
+{
+ memset(&link->dp_trace, 0, sizeof(link->dp_trace));
+ link->dp_trace.is_initialized = true;
+}
+
+void dp_trace_reset(struct dc_link *link)
+{
+ memset(&link->dp_trace, 0, sizeof(link->dp_trace));
+}
+
+bool dc_dp_trace_is_initialized(struct dc_link *link)
+{
+ return link->dp_trace.is_initialized;
+}
+
+void dp_trace_detect_lt_init(struct dc_link *link)
+{
+ memset(&link->dp_trace.detect_lt_trace, 0, sizeof(link->dp_trace.detect_lt_trace));
+}
+
+void dp_trace_commit_lt_init(struct dc_link *link)
+{
+ memset(&link->dp_trace.commit_lt_trace, 0, sizeof(link->dp_trace.commit_lt_trace));
+}
+
+void dp_trace_link_loss_increment(struct dc_link *link)
+{
+ link->dp_trace.link_loss_count++;
+}
+
+void dp_trace_lt_fail_count_update(struct dc_link *link,
+ unsigned int fail_count,
+ bool in_detection)
+{
+ if (in_detection)
+ link->dp_trace.detect_lt_trace.counts.fail = fail_count;
+ else
+ link->dp_trace.commit_lt_trace.counts.fail = fail_count;
+}
+
+void dp_trace_lt_total_count_increment(struct dc_link *link,
+ bool in_detection)
+{
+ if (in_detection)
+ link->dp_trace.detect_lt_trace.counts.total++;
+ else
+ link->dp_trace.commit_lt_trace.counts.total++;
+}
+
+void dc_dp_trace_set_is_logged_flag(struct dc_link *link,
+ bool in_detection,
+ bool is_logged)
+{
+ if (in_detection)
+ link->dp_trace.detect_lt_trace.is_logged = is_logged;
+ else
+ link->dp_trace.commit_lt_trace.is_logged = is_logged;
+}
+
+bool dc_dp_trace_is_logged(struct dc_link *link,
+ bool in_detection)
+{
+ if (in_detection)
+ return link->dp_trace.detect_lt_trace.is_logged;
+ else
+ return link->dp_trace.commit_lt_trace.is_logged;
+}
+
+void dp_trace_lt_result_update(struct dc_link *link,
+ enum link_training_result result,
+ bool in_detection)
+{
+ if (in_detection)
+ link->dp_trace.detect_lt_trace.result = result;
+ else
+ link->dp_trace.commit_lt_trace.result = result;
+}
+
+void dp_trace_set_lt_start_timestamp(struct dc_link *link,
+ bool in_detection)
+{
+ if (in_detection)
+ link->dp_trace.detect_lt_trace.timestamps.start = dm_get_timestamp(link->dc->ctx);
+ else
+ link->dp_trace.commit_lt_trace.timestamps.start = dm_get_timestamp(link->dc->ctx);
+}
+
+void dp_trace_set_lt_end_timestamp(struct dc_link *link,
+ bool in_detection)
+{
+ if (in_detection)
+ link->dp_trace.detect_lt_trace.timestamps.end = dm_get_timestamp(link->dc->ctx);
+ else
+ link->dp_trace.commit_lt_trace.timestamps.end = dm_get_timestamp(link->dc->ctx);
+}
+
+unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
+ bool in_detection)
+{
+ if (in_detection)
+ return link->dp_trace.detect_lt_trace.timestamps.end;
+ else
+ return link->dp_trace.commit_lt_trace.timestamps.end;
+}
+
+struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
+ bool in_detection)
+{
+ if (in_detection)
+ return &link->dp_trace.detect_lt_trace.counts;
+ else
+ return &link->dp_trace.commit_lt_trace.counts;
+}
+
+unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link)
+{
+ return link->dp_trace.link_loss_count;
+}
+
+void dp_trace_set_edp_power_timestamp(struct dc_link *link,
+ bool power_up)
+{
+ if (!power_up)
+ /*save driver power off time stamp*/
+ link->dp_trace.edp_trace_power_timestamps.poweroff = dm_get_timestamp(link->dc->ctx);
+ else
+ link->dp_trace.edp_trace_power_timestamps.poweron = dm_get_timestamp(link->dc->ctx);
+}
+
+uint64_t dp_trace_get_edp_poweron_timestamp(struct dc_link *link)
+{
+ return link->dp_trace.edp_trace_power_timestamps.poweron;
+}
+
+uint64_t dp_trace_get_edp_poweroff_timestamp(struct dc_link *link)
+{
+ return link->dp_trace.edp_trace_power_timestamps.poweroff;
+} \ No newline at end of file
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h b/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h
new file mode 100644
index 000000000000..26700e3cd65e
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dp_trace.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_DP_TRACE_H__
+#define __LINK_DP_TRACE_H__
+
+void dp_trace_init(struct dc_link *link);
+void dp_trace_reset(struct dc_link *link);
+bool dc_dp_trace_is_initialized(struct dc_link *link);
+void dp_trace_detect_lt_init(struct dc_link *link);
+void dp_trace_commit_lt_init(struct dc_link *link);
+void dp_trace_link_loss_increment(struct dc_link *link);
+void dp_trace_lt_fail_count_update(struct dc_link *link,
+ unsigned int fail_count,
+ bool in_detection);
+void dp_trace_lt_total_count_increment(struct dc_link *link,
+ bool in_detection);
+void dc_dp_trace_set_is_logged_flag(struct dc_link *link,
+ bool in_detection,
+ bool is_logged);
+bool dc_dp_trace_is_logged(struct dc_link *link,
+ bool in_detection);
+void dp_trace_lt_result_update(struct dc_link *link,
+ enum link_training_result result,
+ bool in_detection);
+void dp_trace_set_lt_start_timestamp(struct dc_link *link,
+ bool in_detection);
+void dp_trace_set_lt_end_timestamp(struct dc_link *link,
+ bool in_detection);
+unsigned long long dc_dp_trace_get_lt_end_timestamp(struct dc_link *link,
+ bool in_detection);
+struct dp_trace_lt_counts *dc_dp_trace_get_lt_counts(struct dc_link *link,
+ bool in_detection);
+unsigned int dc_dp_trace_get_link_loss_count(struct dc_link *link);
+
+void dp_trace_set_edp_power_timestamp(struct dc_link *link,
+ bool power_up);
+uint64_t dp_trace_get_edp_poweron_timestamp(struct dc_link *link);
+uint64_t dp_trace_get_edp_poweroff_timestamp(struct dc_link *link);
+
+#endif /* __LINK_DP_TRACE_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c
new file mode 100644
index 000000000000..776e822abcbb
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "link_hwss_dio.h"
+#include "core_types.h"
+#include "dc_link_dp.h"
+#include "link_enc_cfg.h"
+
+void set_dio_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
+ struct fixed31_32 throttled_vcp_size)
+{
+ struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
+
+ stream_encoder->funcs->set_throttled_vcp_size(
+ stream_encoder,
+ throttled_vcp_size);
+}
+
+void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
+
+ link_enc->funcs->connect_dig_be_to_fe(link_enc,
+ pipe_ctx->stream_res.stream_enc->id, true);
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ dp_source_sequence_trace(pipe_ctx->stream->link,
+ DPCD_SOURCE_SEQ_AFTER_CONNECT_DIG_FE_BE);
+}
+
+void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(pipe_ctx->stream->link);
+
+ link_enc->funcs->connect_dig_be_to_fe(
+ link_enc,
+ pipe_ctx->stream_res.stream_enc->id,
+ false);
+ if (dc_is_dp_signal(pipe_ctx->stream->signal))
+ dp_source_sequence_trace(pipe_ctx->stream->link,
+ DPCD_SOURCE_SEQ_AFTER_DISCONNECT_DIG_FE_BE);
+
+}
+
+void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx)
+{
+ struct stream_encoder *stream_encoder = pipe_ctx->stream_res.stream_enc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+
+ if (!dc_is_virtual_signal(stream->signal))
+ stream_encoder->funcs->setup_stereo_sync(
+ stream_encoder,
+ pipe_ctx->stream_res.tg->inst,
+ stream->timing.timing_3d_format != TIMING_3D_FORMAT_NONE);
+
+ if (dc_is_dp_signal(stream->signal))
+ stream_encoder->funcs->dp_set_stream_attribute(
+ stream_encoder,
+ &stream->timing,
+ stream->output_color_space,
+ stream->use_vsc_sdp_for_colorimetry,
+ link->dpcd_caps.dprx_feature.bits.SST_SPLIT_SDP_CAP);
+ else if (dc_is_hdmi_tmds_signal(stream->signal))
+ stream_encoder->funcs->hdmi_set_stream_attribute(
+ stream_encoder,
+ &stream->timing,
+ stream->phy_pix_clk,
+ pipe_ctx->stream_res.audio != NULL);
+ else if (dc_is_dvi_signal(stream->signal))
+ stream_encoder->funcs->dvi_set_stream_attribute(
+ stream_encoder,
+ &stream->timing,
+ (stream->signal == SIGNAL_TYPE_DVI_DUAL_LINK) ?
+ true : false);
+ else if (dc_is_lvds_signal(stream->signal))
+ stream_encoder->funcs->lvds_set_stream_attribute(
+ stream_encoder,
+ &stream->timing);
+
+ if (dc_is_dp_signal(stream->signal))
+ dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
+}
+
+void enable_dio_dp_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings)
+{
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+
+ if (dc_is_dp_sst_signal(signal))
+ link_enc->funcs->enable_dp_output(
+ link_enc,
+ link_settings,
+ clock_source);
+ else
+ link_enc->funcs->enable_dp_mst_output(
+ link_enc,
+ link_settings,
+ clock_source);
+ dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_ENABLE_LINK_PHY);
+}
+
+void disable_dio_dp_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+
+ link_enc->funcs->disable_output(link_enc, signal);
+ dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DISABLE_LINK_PHY);
+}
+
+void set_dio_dp_link_test_pattern(struct dc_link *link,
+ const struct link_resource *link_res,
+ struct encoder_set_dp_phy_pattern_param *tp_params)
+{
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+
+ link_enc->funcs->dp_set_phy_pattern(link_enc, tp_params);
+ dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
+}
+
+void set_dio_dp_lane_settings(struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
+{
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+
+ link_enc->funcs->dp_set_lane_settings(link_enc, link_settings, lane_settings);
+}
+
+static void update_dio_stream_allocation_table(struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct link_mst_stream_allocation_table *table)
+{
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+
+ ASSERT(link_enc);
+ link_enc->funcs->update_mst_stream_allocation_table(link_enc, table);
+}
+
+static const struct link_hwss dio_link_hwss = {
+ .setup_stream_encoder = setup_dio_stream_encoder,
+ .reset_stream_encoder = reset_dio_stream_encoder,
+ .setup_stream_attribute = setup_dio_stream_attribute,
+ .ext = {
+ .set_throttled_vcp_size = set_dio_throttled_vcp_size,
+ .enable_dp_link_output = enable_dio_dp_link_output,
+ .disable_dp_link_output = disable_dio_dp_link_output,
+ .set_dp_link_test_pattern = set_dio_dp_link_test_pattern,
+ .set_dp_lane_settings = set_dio_dp_lane_settings,
+ .update_stream_allocation_table = update_dio_stream_allocation_table,
+ },
+};
+
+bool can_use_dio_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res)
+{
+ return link->link_enc != NULL;
+}
+
+const struct link_hwss *get_dio_link_hwss(void)
+{
+ return &dio_link_hwss;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h
new file mode 100644
index 000000000000..08f22b32df48
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dio.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_HWSS_DIO_H__
+#define __LINK_HWSS_DIO_H__
+
+#include "link_hwss.h"
+
+const struct link_hwss *get_dio_link_hwss(void);
+bool can_use_dio_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res);
+void set_dio_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
+ struct fixed31_32 throttled_vcp_size);
+void setup_dio_stream_encoder(struct pipe_ctx *pipe_ctx);
+void reset_dio_stream_encoder(struct pipe_ctx *pipe_ctx);
+void setup_dio_stream_attribute(struct pipe_ctx *pipe_ctx);
+void enable_dio_dp_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings);
+void disable_dio_dp_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal);
+void set_dio_dp_link_test_pattern(struct dc_link *link,
+ const struct link_resource *link_res,
+ struct encoder_set_dp_phy_pattern_param *tp_params);
+void set_dio_dp_lane_settings(struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]);
+
+#endif /* __LINK_HWSS_DIO_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c
new file mode 100644
index 000000000000..89d4e8159138
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "link_hwss_dpia.h"
+#include "core_types.h"
+#include "link_hwss_dio.h"
+#include "link_enc_cfg.h"
+
+#define DC_LOGGER_INIT(logger)
+
+static void update_dpia_stream_allocation_table(struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct link_mst_stream_allocation_table *table)
+{
+ struct link_encoder *link_enc = link_enc_cfg_get_link_enc(link);
+ static enum dc_status status;
+ uint8_t mst_alloc_slots = 0, prev_mst_slots_in_use = 0xFF;
+ int i;
+ DC_LOGGER_INIT(link->ctx->logger);
+
+ for (i = 0; i < table->stream_count; i++)
+ mst_alloc_slots += table->stream_allocations[i].slot_count;
+
+ status = dc_process_dmub_set_mst_slots(link->dc, link->link_index,
+ mst_alloc_slots, &prev_mst_slots_in_use);
+ ASSERT(status == DC_OK);
+ DC_LOG_MST("dpia : status[%d]: alloc_slots[%d]: used_slots[%d]\n",
+ status, mst_alloc_slots, prev_mst_slots_in_use);
+
+ ASSERT(link_enc);
+ link_enc->funcs->update_mst_stream_allocation_table(link_enc, table);
+}
+
+static const struct link_hwss dpia_link_hwss = {
+ .setup_stream_encoder = setup_dio_stream_encoder,
+ .reset_stream_encoder = reset_dio_stream_encoder,
+ .setup_stream_attribute = setup_dio_stream_attribute,
+ .ext = {
+ .set_throttled_vcp_size = set_dio_throttled_vcp_size,
+ .enable_dp_link_output = enable_dio_dp_link_output,
+ .disable_dp_link_output = disable_dio_dp_link_output,
+ .set_dp_link_test_pattern = set_dio_dp_link_test_pattern,
+ .set_dp_lane_settings = set_dio_dp_lane_settings,
+ .update_stream_allocation_table = update_dpia_stream_allocation_table,
+ },
+};
+
+bool can_use_dpia_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res)
+{
+ return link->is_dig_mapping_flexible &&
+ link->dc->res_pool->funcs->link_encs_assign;
+}
+
+const struct link_hwss *get_dpia_link_hwss(void)
+{
+ return &dpia_link_hwss;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h
new file mode 100644
index 000000000000..ad16ec5d9bb7
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_dpia.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_HWSS_DPIA_H__
+#define __LINK_HWSS_DPIA_H__
+
+#include "link_hwss.h"
+
+const struct link_hwss *get_dpia_link_hwss(void);
+bool can_use_dpia_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res);
+
+#endif /* __LINK_HWSS_DPIA_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c
new file mode 100644
index 000000000000..ea6cf8bfce30
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.c
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "link_hwss_hpo_dp.h"
+#include "dm_helpers.h"
+#include "core_types.h"
+#include "dccg.h"
+#include "dc_link_dp.h"
+#include "clk_mgr.h"
+
+static enum phyd32clk_clock_source get_phyd32clk_src(struct dc_link *link)
+{
+ switch (link->link_enc->transmitter) {
+ case TRANSMITTER_UNIPHY_A:
+ return PHYD32CLKA;
+ case TRANSMITTER_UNIPHY_B:
+ return PHYD32CLKB;
+ case TRANSMITTER_UNIPHY_C:
+ return PHYD32CLKC;
+ case TRANSMITTER_UNIPHY_D:
+ return PHYD32CLKD;
+ case TRANSMITTER_UNIPHY_E:
+ return PHYD32CLKE;
+ default:
+ return PHYD32CLKA;
+ }
+}
+
+static void set_hpo_dp_throttled_vcp_size(struct pipe_ctx *pipe_ctx,
+ struct fixed31_32 throttled_vcp_size)
+{
+ struct hpo_dp_stream_encoder *hpo_dp_stream_encoder =
+ pipe_ctx->stream_res.hpo_dp_stream_enc;
+ struct hpo_dp_link_encoder *hpo_dp_link_encoder =
+ pipe_ctx->link_res.hpo_dp_link_enc;
+
+ hpo_dp_link_encoder->funcs->set_throttled_vcp_size(hpo_dp_link_encoder,
+ hpo_dp_stream_encoder->inst,
+ throttled_vcp_size);
+}
+
+static void set_hpo_dp_hblank_min_symbol_width(struct pipe_ctx *pipe_ctx,
+ const struct dc_link_settings *link_settings,
+ struct fixed31_32 throttled_vcp_size)
+{
+ struct hpo_dp_stream_encoder *hpo_dp_stream_encoder =
+ pipe_ctx->stream_res.hpo_dp_stream_enc;
+ struct dc_crtc_timing *timing = &pipe_ctx->stream->timing;
+ struct fixed31_32 h_blank_in_ms, time_slot_in_ms, mtp_cnt_per_h_blank;
+ uint32_t link_bw_in_kbps =
+ dc_link_bandwidth_kbps(pipe_ctx->stream->link, link_settings);
+ uint16_t hblank_min_symbol_width = 0;
+
+ if (link_bw_in_kbps > 0) {
+ h_blank_in_ms = dc_fixpt_div(dc_fixpt_from_int(
+ timing->h_total - timing->h_addressable),
+ dc_fixpt_from_fraction(timing->pix_clk_100hz, 10));
+ time_slot_in_ms = dc_fixpt_from_fraction(32 * 4, link_bw_in_kbps);
+ mtp_cnt_per_h_blank = dc_fixpt_div(h_blank_in_ms,
+ dc_fixpt_mul_int(time_slot_in_ms, 64));
+ hblank_min_symbol_width = dc_fixpt_floor(
+ dc_fixpt_mul(mtp_cnt_per_h_blank, throttled_vcp_size));
+ }
+
+ hpo_dp_stream_encoder->funcs->set_hblank_min_symbol_width(hpo_dp_stream_encoder,
+ hblank_min_symbol_width);
+}
+
+static int get_odm_segment_count(struct pipe_ctx *pipe_ctx)
+{
+ struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
+ int count = 1;
+
+ while (odm_pipe != NULL) {
+ count++;
+ odm_pipe = odm_pipe->next_odm_pipe;
+ }
+
+ return count;
+}
+
+static void setup_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+ struct hpo_dp_link_encoder *link_enc = pipe_ctx->link_res.hpo_dp_link_enc;
+ struct dccg *dccg = dc->res_pool->dccg;
+ struct timing_generator *tg = pipe_ctx->stream_res.tg;
+ struct dtbclk_dto_params dto_params = {0};
+ enum phyd32clk_clock_source phyd32clk = get_phyd32clk_src(pipe_ctx->stream->link);
+
+ dto_params.otg_inst = tg->inst;
+ dto_params.pixclk_khz = pipe_ctx->stream->phy_pix_clk;
+ dto_params.num_odm_segments = get_odm_segment_count(pipe_ctx);
+ dto_params.timing = &pipe_ctx->stream->timing;
+ dto_params.ref_dtbclk_khz = dc->clk_mgr->funcs->get_dtb_ref_clk_frequency(dc->clk_mgr);
+
+ dccg->funcs->set_dpstreamclk(dccg, DTBCLK0, tg->inst);
+ dccg->funcs->enable_symclk32_se(dccg, stream_enc->inst, phyd32clk);
+ dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
+ stream_enc->funcs->enable_stream(stream_enc);
+ stream_enc->funcs->map_stream_to_link(stream_enc, stream_enc->inst, link_enc->inst);
+}
+
+static void reset_hpo_dp_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+ struct dc *dc = pipe_ctx->stream->ctx->dc;
+ struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+ struct dccg *dccg = dc->res_pool->dccg;
+ struct timing_generator *tg = pipe_ctx->stream_res.tg;
+ struct dtbclk_dto_params dto_params = {0};
+
+ dto_params.otg_inst = tg->inst;
+ dto_params.timing = &pipe_ctx->stream->timing;
+
+ stream_enc->funcs->disable(stream_enc);
+ dccg->funcs->set_dtbclk_dto(dccg, &dto_params);
+ dccg->funcs->disable_symclk32_se(dccg, stream_enc->inst);
+ dccg->funcs->set_dpstreamclk(dccg, REFCLK, tg->inst);
+}
+
+static void setup_hpo_dp_stream_attribute(struct pipe_ctx *pipe_ctx)
+{
+ struct hpo_dp_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_dp_stream_enc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct dc_link *link = stream->link;
+
+ stream_enc->funcs->set_stream_attribute(
+ stream_enc,
+ &stream->timing,
+ stream->output_color_space,
+ stream->use_vsc_sdp_for_colorimetry,
+ stream->timing.flags.DSC,
+ false);
+ dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_DP_STREAM_ATTR);
+}
+
+static void enable_hpo_dp_fpga_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings)
+{
+ const struct dc *dc = link->dc;
+ enum phyd32clk_clock_source phyd32clk = get_phyd32clk_src(link);
+ int phyd32clk_freq_khz = link_settings->link_rate == LINK_RATE_UHBR10 ? 312500 :
+ link_settings->link_rate == LINK_RATE_UHBR13_5 ? 412875 :
+ link_settings->link_rate == LINK_RATE_UHBR20 ? 625000 : 0;
+
+ dm_set_phyd32clk(dc->ctx, phyd32clk_freq_khz);
+ dc->res_pool->dccg->funcs->set_physymclk(
+ dc->res_pool->dccg,
+ link->link_enc_hw_inst,
+ PHYSYMCLK_FORCE_SRC_PHYD32CLK,
+ true);
+ dc->res_pool->dccg->funcs->enable_symclk32_le(
+ dc->res_pool->dccg,
+ link_res->hpo_dp_link_enc->inst,
+ phyd32clk);
+ link_res->hpo_dp_link_enc->funcs->link_enable(
+ link_res->hpo_dp_link_enc,
+ link_settings->lane_count);
+
+}
+
+static void enable_hpo_dp_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal,
+ enum clock_source_id clock_source,
+ const struct dc_link_settings *link_settings)
+{
+ if (IS_FPGA_MAXIMUS_DC(link->dc->ctx->dce_environment))
+ enable_hpo_dp_fpga_link_output(link, link_res, signal,
+ clock_source, link_settings);
+ else
+ link_res->hpo_dp_link_enc->funcs->enable_link_phy(
+ link_res->hpo_dp_link_enc,
+ link_settings,
+ link->link_enc->transmitter,
+ link->link_enc->hpd_source);
+}
+
+
+static void disable_hpo_dp_fpga_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ const struct dc *dc = link->dc;
+
+ link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
+ dc->res_pool->dccg->funcs->disable_symclk32_le(
+ dc->res_pool->dccg,
+ link_res->hpo_dp_link_enc->inst);
+ dc->res_pool->dccg->funcs->set_physymclk(
+ dc->res_pool->dccg,
+ link->link_enc_hw_inst,
+ PHYSYMCLK_FORCE_SRC_SYMCLK,
+ false);
+ dm_set_phyd32clk(dc->ctx, 0);
+}
+
+static void disable_hpo_dp_link_output(struct dc_link *link,
+ const struct link_resource *link_res,
+ enum signal_type signal)
+{
+ if (IS_FPGA_MAXIMUS_DC(link->dc->ctx->dce_environment)) {
+ disable_hpo_dp_fpga_link_output(link, link_res, signal);
+ } else {
+ link_res->hpo_dp_link_enc->funcs->link_disable(link_res->hpo_dp_link_enc);
+ link_res->hpo_dp_link_enc->funcs->disable_link_phy(
+ link_res->hpo_dp_link_enc, signal);
+ }
+}
+
+static void set_hpo_dp_link_test_pattern(struct dc_link *link,
+ const struct link_resource *link_res,
+ struct encoder_set_dp_phy_pattern_param *tp_params)
+{
+ link_res->hpo_dp_link_enc->funcs->set_link_test_pattern(
+ link_res->hpo_dp_link_enc, tp_params);
+ dp_source_sequence_trace(link, DPCD_SOURCE_SEQ_AFTER_SET_SOURCE_PATTERN);
+}
+
+static void set_hpo_dp_lane_settings(struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX])
+{
+ link_res->hpo_dp_link_enc->funcs->set_ffe(
+ link_res->hpo_dp_link_enc,
+ link_settings,
+ lane_settings[0].FFE_PRESET.raw);
+}
+
+static void update_hpo_dp_stream_allocation_table(struct dc_link *link,
+ const struct link_resource *link_res,
+ const struct link_mst_stream_allocation_table *table)
+{
+ link_res->hpo_dp_link_enc->funcs->update_stream_allocation_table(
+ link_res->hpo_dp_link_enc,
+ table);
+}
+
+static const struct link_hwss hpo_dp_link_hwss = {
+ .setup_stream_encoder = setup_hpo_dp_stream_encoder,
+ .reset_stream_encoder = reset_hpo_dp_stream_encoder,
+ .setup_stream_attribute = setup_hpo_dp_stream_attribute,
+ .ext = {
+ .set_throttled_vcp_size = set_hpo_dp_throttled_vcp_size,
+ .set_hblank_min_symbol_width = set_hpo_dp_hblank_min_symbol_width,
+ .enable_dp_link_output = enable_hpo_dp_link_output,
+ .disable_dp_link_output = disable_hpo_dp_link_output,
+ .set_dp_link_test_pattern = set_hpo_dp_link_test_pattern,
+ .set_dp_lane_settings = set_hpo_dp_lane_settings,
+ .update_stream_allocation_table = update_hpo_dp_stream_allocation_table,
+ },
+};
+
+bool can_use_hpo_dp_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res)
+{
+ return link_res->hpo_dp_link_enc != NULL;
+}
+
+const struct link_hwss *get_hpo_dp_link_hwss(void)
+{
+ return &hpo_dp_link_hwss;
+}
+
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h
new file mode 100644
index 000000000000..57d447ec27b8
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_dp.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_HWSS_HPO_DP_H__
+#define __LINK_HWSS_HPO_DP_H__
+
+#include "link_hwss.h"
+
+bool can_use_hpo_dp_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res);
+const struct link_hwss *get_hpo_dp_link_hwss(void);
+
+
+#endif /* __LINK_HWSS_HPO_DP_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.c b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.c
new file mode 100644
index 000000000000..4b5eccd994c4
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "link_hwss_hpo_frl.h"
+#include "core_types.h"
+#include "virtual/virtual_link_hwss.h"
+
+static void setup_hpo_frl_stream_attribute(struct pipe_ctx *pipe_ctx)
+{
+ struct hpo_frl_stream_encoder *stream_enc = pipe_ctx->stream_res.hpo_frl_stream_enc;
+ struct dc_stream_state *stream = pipe_ctx->stream;
+ struct pipe_ctx *odm_pipe;
+ int odm_combine_num_segments = 1;
+
+ /* get number of ODM combine input segments */
+ for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
+ odm_combine_num_segments++;
+
+ stream_enc->funcs->hdmi_frl_set_stream_attribute(
+ stream_enc,
+ &stream->timing,
+ &stream->link->frl_link_settings.borrow_params,
+ odm_combine_num_segments);
+}
+
+static const struct link_hwss hpo_frl_link_hwss = {
+ .setup_stream_encoder = virtual_setup_stream_encoder,
+ .reset_stream_encoder = virtual_reset_stream_encoder,
+ .setup_stream_attribute = setup_hpo_frl_stream_attribute,
+};
+
+bool can_use_hpo_frl_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res)
+{
+ return link_res->hpo_frl_link_enc != NULL;
+}
+
+const struct link_hwss *get_hpo_frl_link_hwss(void)
+{
+ return &hpo_frl_link_hwss;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h
new file mode 100644
index 000000000000..ea8d9760132f
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/link/link_hwss_hpo_frl.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __LINK_HWSS_HPO_FRL_H__
+#define __LINK_HWSS_HPO_FRL_H__
+
+#include "link_hwss.h"
+
+bool can_use_hpo_frl_link_hwss(const struct dc_link *link,
+ const struct link_resource *link_res);
+const struct link_hwss *get_hpo_frl_link_hwss(void);
+
+#endif /* __LINK_HWSS_HPO_FRL_H__ */
diff --git a/drivers/gpu/drm/amd/display/dc/os_types.h b/drivers/gpu/drm/amd/display/dc/os_types.h
index 5df1d80c8341..981a9ed6fb61 100644
--- a/drivers/gpu/drm/amd/display/dc/os_types.h
+++ b/drivers/gpu/drm/amd/display/dc/os_types.h
@@ -35,8 +35,8 @@
#include <asm/byteorder.h>
+#include <drm/display/drm_dp_helper.h>
#include <drm/drm_print.h>
-#include <drm/drm_dp_helper.h>
#include "cgs_common.h"
diff --git a/drivers/gpu/drm/amd/display/dc/virtual/Makefile b/drivers/gpu/drm/amd/display/dc/virtual/Makefile
index 07326d244d50..931facd4dab5 100644
--- a/drivers/gpu/drm/amd/display/dc/virtual/Makefile
+++ b/drivers/gpu/drm/amd/display/dc/virtual/Makefile
@@ -23,7 +23,7 @@
# Makefile for the virtual sub-component of DAL.
# It provides the control and status of HW CRTC block.
-VIRTUAL = virtual_link_encoder.o virtual_stream_encoder.o
+VIRTUAL = virtual_link_encoder.o virtual_stream_encoder.o virtual_link_hwss.o
AMD_DAL_VIRTUAL = $(addprefix $(AMDDALPATH)/dc/virtual/,$(VIRTUAL))
diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c
index 348e9a600a72..df8bc44bc4be 100644
--- a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c
+++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_encoder.c
@@ -63,7 +63,8 @@ static void virtual_link_encoder_disable_output(
static void virtual_link_encoder_dp_set_lane_settings(
struct link_encoder *enc,
- const struct link_training_settings *link_settings) {}
+ const struct dc_link_settings *link_settings,
+ const struct dc_lane_settings lane_settings[LANE_COUNT_DP_MAX]) {}
static void virtual_link_encoder_dp_set_phy_pattern(
struct link_encoder *enc,
diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.c b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.c
new file mode 100644
index 000000000000..501173ce270e
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "virtual_link_hwss.h"
+
+void virtual_setup_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+}
+
+void virtual_setup_stream_attribute(struct pipe_ctx *pipe_ctx)
+{
+}
+
+void virtual_reset_stream_encoder(struct pipe_ctx *pipe_ctx)
+{
+}
+static const struct link_hwss virtual_link_hwss = {
+ .setup_stream_encoder = virtual_setup_stream_encoder,
+ .reset_stream_encoder = virtual_reset_stream_encoder,
+ .setup_stream_attribute = virtual_setup_stream_attribute,
+};
+
+const struct link_hwss *get_virtual_link_hwss(void)
+{
+ return &virtual_link_hwss;
+}
diff --git a/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.h b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.h
new file mode 100644
index 000000000000..fbcbc5afb47d
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dc/virtual/virtual_link_hwss.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2022 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+#ifndef __DC_VIRTUAL_LINK_HWSS_H__
+#define __DC_VIRTUAL_LINK_HWSS_H__
+
+#include "core_types.h"
+
+void virtual_setup_stream_encoder(struct pipe_ctx *pipe_ctx);
+void virtual_setup_stream_attribute(struct pipe_ctx *pipe_ctx);
+void virtual_reset_stream_encoder(struct pipe_ctx *pipe_ctx);
+const struct link_hwss *get_virtual_link_hwss(void);
+
+#endif /* __DC_VIRTUAL_LINK_HWSS_H__ */
diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
index 83855b8a32e9..f5cb8932bd5c 100644
--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
@@ -98,6 +98,8 @@ enum dmub_asic {
DMUB_ASIC_DCN303,
DMUB_ASIC_DCN31,
DMUB_ASIC_DCN31B,
+ DMUB_ASIC_DCN315,
+ DMUB_ASIC_DCN316,
DMUB_ASIC_MAX,
};
@@ -241,6 +243,7 @@ struct dmub_srv_hw_params {
bool power_optimization;
bool dpia_supported;
bool disable_dpia;
+ bool usb4_cm_version;
};
/**
diff --git a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
index 873ecd04e01d..385c28238beb 100644
--- a/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
+++ b/drivers/gpu/drm/amd/display/dmub/inc/dmub_cmd.h
@@ -44,24 +44,6 @@
#endif // defined(_TEST_HARNESS) || defined(FPGA_USB4)
-/* Firmware versioning. */
-#ifdef DMUB_EXPOSE_VERSION
-#define DMUB_FW_VERSION_GIT_HASH 0xbaf06b95
-#define DMUB_FW_VERSION_MAJOR 0
-#define DMUB_FW_VERSION_MINOR 0
-#define DMUB_FW_VERSION_REVISION 98
-#define DMUB_FW_VERSION_TEST 0
-#define DMUB_FW_VERSION_VBIOS 0
-#define DMUB_FW_VERSION_HOTFIX 0
-#define DMUB_FW_VERSION_UCODE (((DMUB_FW_VERSION_MAJOR & 0xFF) << 24) | \
- ((DMUB_FW_VERSION_MINOR & 0xFF) << 16) | \
- ((DMUB_FW_VERSION_REVISION & 0xFF) << 8) | \
- ((DMUB_FW_VERSION_TEST & 0x1) << 7) | \
- ((DMUB_FW_VERSION_VBIOS & 0x1) << 6) | \
- (DMUB_FW_VERSION_HOTFIX & 0x3F))
-
-#endif
-
//<DMUB_TYPES>==================================================================
/* Basic type definitions. */
@@ -367,8 +349,10 @@ union dmub_fw_boot_options {
/**< 1 if all root clock gating is enabled and low power memory is enabled*/
uint32_t power_optimization: 1;
uint32_t diag_env: 1; /* 1 if diagnostic environment */
+ uint32_t gpint_scratch8: 1; /* 1 if GPINT is in scratch8*/
+ uint32_t usb4_cm_version: 1; /**< 1 CM support */
- uint32_t reserved : 19; /**< reserved */
+ uint32_t reserved : 17; /**< reserved */
} bits; /**< boot bits */
uint32_t all; /**< 32-bit access to bits */
};
@@ -523,7 +507,7 @@ union dmub_inbox0_cmd_lock_hw {
uint32_t command_code: 8;
/* NOTE: Must be have enough bits to match: enum hw_lock_client */
- uint32_t hw_lock_client: 1;
+ uint32_t hw_lock_client: 2;
/* NOTE: Below fields must match with: struct dmub_hw_lock_inst_flags */
uint32_t otg_inst: 3;
@@ -538,7 +522,7 @@ union dmub_inbox0_cmd_lock_hw {
uint32_t lock: 1; /**< Lock */
uint32_t should_release: 1; /**< Release */
- uint32_t reserved: 8; /**< Reserved for extending more clients, HW, etc. */
+ uint32_t reserved: 7; /**< Reserved for extending more clients, HW, etc. */
} bits;
uint32_t all;
};
@@ -644,6 +628,7 @@ enum dmub_cmd_type {
* Command type used for OUTBOX1 notification enable
*/
DMUB_CMD__OUTBOX1_ENABLE = 71,
+
/**
* Command type used for all idle optimization commands.
*/
@@ -656,6 +641,7 @@ enum dmub_cmd_type {
* Command type used for all panel control commands.
*/
DMUB_CMD__PANEL_CNTL = 74,
+
/**
* Command type used for interfacing with DPIA.
*/
@@ -665,6 +651,14 @@ enum dmub_cmd_type {
*/
DMUB_CMD__EDID_CEA = 79,
/**
+ * Command type used for getting usbc cable ID
+ */
+ DMUB_CMD_GET_USBC_CABLE_ID = 81,
+ /**
+ * Command type used to query HPD state.
+ */
+ DMUB_CMD__QUERY_HPD_STATE = 82,
+ /**
* Command type used for all VBIOS interface commands.
*/
DMUB_CMD__VBIOS = 128,
@@ -1363,6 +1357,30 @@ struct dmub_rb_cmd_dp_set_config_reply {
struct set_config_reply_control_data set_config_reply_control;
};
+/**
+ * Data passed from driver to FW in a DMUB_CMD__QUERY_HPD_STATE command.
+ */
+struct dmub_cmd_hpd_state_query_data {
+ uint8_t instance; /**< HPD instance or DPIA instance */
+ uint8_t result; /**< For returning HPD state */
+ enum aux_channel_type ch_type; /**< enum aux_channel_type */
+ enum aux_return_code_type status; /**< for returning the status of command */
+};
+
+/**
+ * Definition of a DMUB_CMD__QUERY_HPD_STATE command.
+ */
+struct dmub_rb_cmd_query_hpd_state {
+ /**
+ * Command header.
+ */
+ struct dmub_cmd_header header;
+ /**
+ * Data passed from driver to FW in a DMUB_CMD__QUERY_HPD_STATE command.
+ */
+ struct dmub_cmd_hpd_state_query_data data;
+};
+
/*
* Command IDs should be treated as stable ABI.
* Do not reuse or modify IDs.
@@ -1443,6 +1461,78 @@ enum dmub_cmd_mall_type {
DMUB_CMD__MALL_ACTION_NO_DF_REQ = 3,
};
+/**
+ * PHY Link rate for DP.
+ */
+enum phy_link_rate {
+ /**
+ * not supported.
+ */
+ PHY_RATE_UNKNOWN = 0,
+ /**
+ * Rate_1 (RBR) - 1.62 Gbps/Lane
+ */
+ PHY_RATE_162 = 1,
+ /**
+ * Rate_2 - 2.16 Gbps/Lane
+ */
+ PHY_RATE_216 = 2,
+ /**
+ * Rate_3 - 2.43 Gbps/Lane
+ */
+ PHY_RATE_243 = 3,
+ /**
+ * Rate_4 (HBR) - 2.70 Gbps/Lane
+ */
+ PHY_RATE_270 = 4,
+ /**
+ * Rate_5 (RBR2)- 3.24 Gbps/Lane
+ */
+ PHY_RATE_324 = 5,
+ /**
+ * Rate_6 - 4.32 Gbps/Lane
+ */
+ PHY_RATE_432 = 6,
+ /**
+ * Rate_7 (HBR2)- 5.40 Gbps/Lane
+ */
+ PHY_RATE_540 = 7,
+ /**
+ * Rate_8 (HBR3)- 8.10 Gbps/Lane
+ */
+ PHY_RATE_810 = 8,
+ /**
+ * UHBR10 - 10.0 Gbps/Lane
+ */
+ PHY_RATE_1000 = 9,
+ /**
+ * UHBR13.5 - 13.5 Gbps/Lane
+ */
+ PHY_RATE_1350 = 10,
+ /**
+ * UHBR10 - 20.0 Gbps/Lane
+ */
+ PHY_RATE_2000 = 11,
+};
+
+/**
+ * enum dmub_phy_fsm_state - PHY FSM states.
+ * PHY FSM state to transit to during PSR enable/disable.
+ */
+enum dmub_phy_fsm_state {
+ DMUB_PHY_FSM_POWER_UP_DEFAULT = 0,
+ DMUB_PHY_FSM_RESET,
+ DMUB_PHY_FSM_RESET_RELEASED,
+ DMUB_PHY_FSM_SRAM_LOAD_DONE,
+ DMUB_PHY_FSM_INITIALIZED,
+ DMUB_PHY_FSM_CALIBRATED,
+ DMUB_PHY_FSM_CALIBRATED_LP,
+ DMUB_PHY_FSM_CALIBRATED_PG,
+ DMUB_PHY_FSM_POWER_DOWN,
+ DMUB_PHY_FSM_PLL_EN,
+ DMUB_PHY_FSM_TX_EN,
+ DMUB_PHY_FSM_FAST_LP,
+};
/**
* Data passed from driver to FW in a DMUB_CMD__PSR_COPY_SETTINGS command.
@@ -1553,10 +1643,14 @@ struct dmub_cmd_psr_copy_settings_data {
* DSC enable status in driver
*/
uint8_t dsc_enable_status;
+ /*
+ * Use FSM state for PSR power up/down
+ */
+ uint8_t use_phy_fsm;
/**
- * Explicit padding to 3 byte boundary.
+ * Explicit padding to 2 byte boundary.
*/
- uint8_t pad3[3];
+ uint8_t pad3[2];
};
/**
@@ -1619,9 +1713,16 @@ struct dmub_rb_cmd_psr_enable_data {
*/
uint8_t panel_inst;
/**
- * Explicit padding to 4 byte boundary.
+ * Phy state to enter.
+ * Values to use are defined in dmub_phy_fsm_state
*/
- uint8_t pad[2];
+ uint8_t phy_fsm_state;
+ /**
+ * Phy rate for DP - RBR/HBR/HBR2/HBR3.
+ * Set this using enum phy_link_rate.
+ * This does not support HDMI/DP2 for now.
+ */
+ uint8_t phy_rate;
};
/**
@@ -2366,6 +2467,9 @@ struct dmub_cmd_panel_cntl_data {
uint32_t bl_pwm_ref_div1; /* in/out */
uint8_t is_backlight_on : 1; /* in/out */
uint8_t is_powered_on : 1; /* in/out */
+ uint8_t padding[3];
+ uint32_t bl_pwm_ref_div2; /* in/out */
+ uint8_t reserved[4];
};
/**
@@ -2481,6 +2585,38 @@ struct dmub_rb_cmd_edid_cea {
};
/**
+ * struct dmub_cmd_cable_id_input - Defines the input of DMUB_CMD_GET_USBC_CABLE_ID command.
+ */
+struct dmub_cmd_cable_id_input {
+ uint8_t phy_inst; /**< phy inst for cable id data */
+};
+
+/**
+ * struct dmub_cmd_cable_id_input - Defines the output of DMUB_CMD_GET_USBC_CABLE_ID command.
+ */
+struct dmub_cmd_cable_id_output {
+ uint8_t UHBR10_20_CAPABILITY :2; /**< b'01 for UHBR10 support, b'10 for both UHBR10 and UHBR20 support */
+ uint8_t UHBR13_5_CAPABILITY :1; /**< b'1 for UHBR13.5 support */
+ uint8_t CABLE_TYPE :3; /**< b'01 for passive cable, b'10 for active LRD cable, b'11 for active retimer cable */
+ uint8_t RESERVED :2; /**< reserved means not defined */
+};
+
+/**
+ * Definition of a DMUB_CMD_GET_USBC_CABLE_ID command
+ */
+struct dmub_rb_cmd_get_usbc_cable_id {
+ struct dmub_cmd_header header; /**< Command header */
+ /**
+ * Data passed from driver to FW in a DMUB_CMD_GET_USBC_CABLE_ID command.
+ */
+ union dmub_cmd_cable_id_data {
+ struct dmub_cmd_cable_id_input input; /**< Input */
+ struct dmub_cmd_cable_id_output output; /**< Output */
+ uint8_t output_raw; /**< Raw data output */
+ } data;
+};
+
+/**
* union dmub_rb_cmd - DMUB inbox command.
*/
union dmub_rb_cmd {
@@ -2645,6 +2781,15 @@ union dmub_rb_cmd {
* Definition of a DMUB_CMD__EDID_CEA command.
*/
struct dmub_rb_cmd_edid_cea edid_cea;
+ /**
+ * Definition of a DMUB_CMD_GET_USBC_CABLE_ID command.
+ */
+ struct dmub_rb_cmd_get_usbc_cable_id cable_id;
+
+ /**
+ * Definition of a DMUB_CMD__QUERY_HPD_STATE command.
+ */
+ struct dmub_rb_cmd_query_hpd_state query_hpd;
};
/**
@@ -2913,13 +3058,15 @@ static inline void dmub_rb_flush_pending(const struct dmub_rb *rb)
uint32_t wptr = rb->wrpt;
while (rptr != wptr) {
- uint64_t volatile *data = (uint64_t volatile *)((uint8_t *)(rb->base_address) + rptr);
- //uint64_t volatile *p = (uint64_t volatile *)data;
- uint64_t temp;
+ uint64_t *data = (uint64_t *)((uint8_t *)(rb->base_address) + rptr);
uint8_t i;
+ /* Don't remove this.
+ * The contents need to actually be read from the ring buffer
+ * for this function to be effective.
+ */
for (i = 0; i < DMUB_RB_CMD_SIZE / sizeof(uint64_t); i++)
- temp = *data++;
+ (void)READ_ONCE(*data++);
rptr += DMUB_RB_CMD_SIZE;
if (rptr >= rb->capacity)
diff --git a/drivers/gpu/drm/amd/display/dmub/src/Makefile b/drivers/gpu/drm/amd/display/dmub/src/Makefile
index 0495bcdd3463..856c7f48de7a 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/Makefile
+++ b/drivers/gpu/drm/amd/display/dmub/src/Makefile
@@ -22,7 +22,7 @@
DMUB = dmub_srv.o dmub_srv_stat.o dmub_reg.o dmub_dcn20.o dmub_dcn21.o
DMUB += dmub_dcn30.o dmub_dcn301.o dmub_dcn302.o dmub_dcn303.o
-DMUB += dmub_dcn31.o
+DMUB += dmub_dcn31.o dmub_dcn315.o dmub_dcn316.o
AMD_DAL_DMUB = $(addprefix $(AMDDALPATH)/dmub/src/,$(DMUB))
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
index fa0569174aec..c7bd7e216710 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.c
@@ -84,7 +84,7 @@ void dmub_dcn31_reset(struct dmub_srv *dmub)
{
union dmub_gpint_data_register cmd;
const uint32_t timeout = 100;
- uint32_t in_reset, scratch, i;
+ uint32_t in_reset, scratch, i, pwait_mode;
REG_GET(DMCUB_CNTL2, DMCUB_SOFT_RESET, &in_reset);
@@ -115,6 +115,13 @@ void dmub_dcn31_reset(struct dmub_srv *dmub)
udelay(1);
}
+ for (i = 0; i < timeout; ++i) {
+ REG_GET(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS, &pwait_mode);
+ if (pwait_mode & (1 << 0))
+ break;
+
+ udelay(1);
+ }
/* Force reset in case we timed out, DMCUB is likely hung. */
}
@@ -125,6 +132,8 @@ void dmub_dcn31_reset(struct dmub_srv *dmub)
REG_WRITE(DMCUB_INBOX1_WPTR, 0);
REG_WRITE(DMCUB_OUTBOX1_RPTR, 0);
REG_WRITE(DMCUB_OUTBOX1_WPTR, 0);
+ REG_WRITE(DMCUB_OUTBOX0_RPTR, 0);
+ REG_WRITE(DMCUB_OUTBOX0_WPTR, 0);
REG_WRITE(DMCUB_SCRATCH0, 0);
/* Clear the GPINT command manually so we don't send anything during boot. */
@@ -340,6 +349,7 @@ void dmub_dcn31_enable_dmub_boot_options(struct dmub_srv *dmub, const struct dmu
boot_options.bits.z10_disable = params->disable_z10;
boot_options.bits.dpia_supported = params->dpia_supported;
boot_options.bits.enable_dpia = params->disable_dpia ? 0 : 1;
+ boot_options.bits.usb4_cm_version = params->usb4_cm_version;
boot_options.bits.power_optimization = params->power_optimization;
boot_options.bits.sel_mux_phy_c_d_phy_f_g = (dmub->asic == DMUB_ASIC_DCN31B) ? 1 : 0;
@@ -441,7 +451,7 @@ void dmub_dcn31_get_diagnostic_data(struct dmub_srv *dmub, struct dmub_diagnosti
bool dmub_dcn31_should_detect(struct dmub_srv *dmub)
{
uint32_t fw_boot_status = REG_READ(DMCUB_SCRATCH0);
- bool should_detect = fw_boot_status & DMUB_FW_BOOT_STATUS_BIT_DETECTION_REQUIRED;
+ bool should_detect = (fw_boot_status & DMUB_FW_BOOT_STATUS_BIT_DETECTION_REQUIRED) != 0;
return should_detect;
}
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
index 59ddc81b5a0e..f6db6f89d45d 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn31.h
@@ -151,7 +151,8 @@ struct dmub_srv;
DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET) \
DMUB_SF(DMCUB_INBOX0_WPTR, DMCUB_INBOX0_WPTR) \
DMUB_SF(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT_IH_INT_EN) \
- DMUB_SF(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK)
+ DMUB_SF(DMCUB_INTERRUPT_ACK, DMCUB_GPINT_IH_INT_ACK) \
+ DMUB_SF(DMCUB_CNTL, DMCUB_PWAIT_MODE_STATUS)
struct dmub_srv_dcn31_reg_offset {
#define DMUB_SR(reg) uint32_t reg;
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn315.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn315.c
new file mode 100644
index 000000000000..4dbb15c898aa
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn315.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "../dmub_srv.h"
+#include "dmub_reg.h"
+#include "dmub_dcn315.h"
+
+#include "dcn/dcn_3_1_5_offset.h"
+#include "dcn/dcn_3_1_5_sh_mask.h"
+
+#define DCN_BASE__INST0_SEG0 0x00000012
+#define DCN_BASE__INST0_SEG1 0x000000C0
+#define DCN_BASE__INST0_SEG2 0x000034C0
+#define DCN_BASE__INST0_SEG3 0x00009000
+#define DCN_BASE__INST0_SEG4 0x02403C00
+#define DCN_BASE__INST0_SEG5 0
+
+#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg
+#define CTX dmub
+#define REGS dmub->regs_dcn31
+#define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name)
+
+/* Registers. */
+
+const struct dmub_srv_dcn31_regs dmub_srv_dcn315_regs = {
+#define DMUB_SR(reg) REG_OFFSET_EXP(reg),
+ {
+ DMUB_DCN31_REGS()
+ DMCUB_INTERNAL_REGS()
+ },
+#undef DMUB_SR
+
+#define DMUB_SF(reg, field) FD_MASK(reg, field),
+ { DMUB_DCN315_FIELDS() },
+#undef DMUB_SF
+
+#define DMUB_SF(reg, field) FD_SHIFT(reg, field),
+ { DMUB_DCN315_FIELDS() },
+#undef DMUB_SF
+};
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn315.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn315.h
new file mode 100644
index 000000000000..0049ae96aa7e
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn315.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef _DMUB_DCN315_H_
+#define _DMUB_DCN315_H_
+
+#include "dmub_dcn31.h"
+
+#define DMUB_DCN315_FIELDS() \
+ DMUB_SF(DMCUB_CNTL, DMCUB_ENABLE) \
+ DMUB_SF(DMCUB_CNTL, DMCUB_TRACEPORT_EN) \
+ DMUB_SF(DMCUB_CNTL2, DMCUB_SOFT_RESET) \
+ DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET) \
+ DMUB_SF(DMCUB_SEC_CNTL, DMCUB_MEM_UNIT_ID) \
+ DMUB_SF(DMCUB_SEC_CNTL, DMCUB_SEC_RESET_STATUS) \
+ DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION3_CW0_TOP_ADDRESS, DMCUB_REGION3_CW0_ENABLE) \
+ DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION3_CW1_TOP_ADDRESS, DMCUB_REGION3_CW1_ENABLE) \
+ DMUB_SF(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION3_CW2_TOP_ADDRESS, DMCUB_REGION3_CW2_ENABLE) \
+ DMUB_SF(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION3_CW3_TOP_ADDRESS, DMCUB_REGION3_CW3_ENABLE) \
+ DMUB_SF(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION3_CW4_TOP_ADDRESS, DMCUB_REGION3_CW4_ENABLE) \
+ DMUB_SF(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION3_CW5_TOP_ADDRESS, DMCUB_REGION3_CW5_ENABLE) \
+ DMUB_SF(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION3_CW6_TOP_ADDRESS, DMCUB_REGION3_CW6_ENABLE) \
+ DMUB_SF(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION3_CW7_TOP_ADDRESS, DMCUB_REGION3_CW7_ENABLE) \
+ DMUB_SF(DMCUB_REGION4_TOP_ADDRESS, DMCUB_REGION4_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION4_TOP_ADDRESS, DMCUB_REGION4_ENABLE) \
+ DMUB_SF(DMCUB_REGION5_TOP_ADDRESS, DMCUB_REGION5_TOP_ADDRESS) \
+ DMUB_SF(DMCUB_REGION5_TOP_ADDRESS, DMCUB_REGION5_ENABLE) \
+ DMUB_SF(CC_DC_PIPE_DIS, DC_DMCUB_ENABLE) \
+ DMUB_SF(MMHUBBUB_SOFT_RESET, DMUIF_SOFT_RESET) \
+ DMUB_SF(DCN_VM_FB_LOCATION_BASE, FB_BASE) \
+ DMUB_SF(DCN_VM_FB_OFFSET, FB_OFFSET) \
+ DMUB_SF(DMCUB_INBOX0_WPTR, DMCUB_INBOX0_WPTR) \
+ DMUB_SF(DMCUB_INTERRUPT_ENABLE, DMCUB_GPINT2_INT_EN) \
+ DMUB_SF(DMCUB_INTERRUPT_ACK, DMCUB_GPINT2_INT_ACK)
+
+extern const struct dmub_srv_dcn31_regs dmub_srv_dcn315_regs;
+
+#endif /* _DMUB_DCN315_H_ */
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn316.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn316.c
new file mode 100644
index 000000000000..c43d1e3819e0
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn316.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 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 "../dmub_srv.h"
+#include "dmub_reg.h"
+#include "dmub_dcn316.h"
+
+#include "dcn/dcn_3_1_6_offset.h"
+#include "dcn/dcn_3_1_6_sh_mask.h"
+
+#define DCN_BASE__INST0_SEG0 0x00000012
+#define DCN_BASE__INST0_SEG1 0x000000C0
+#define DCN_BASE__INST0_SEG2 0x000034C0
+#define DCN_BASE__INST0_SEG3 0x00009000
+#define DCN_BASE__INST0_SEG4 0x02403C00
+#define DCN_BASE__INST0_SEG5 0
+
+#define BASE_INNER(seg) DCN_BASE__INST0_SEG##seg
+#define CTX dmub
+#define REGS dmub->regs_dcn31
+#define REG_OFFSET_EXP(reg_name) (BASE(reg##reg_name##_BASE_IDX) + reg##reg_name)
+
+/* Registers. */
+
+const struct dmub_srv_dcn31_regs dmub_srv_dcn316_regs = {
+#define DMUB_SR(reg) REG_OFFSET_EXP(reg),
+ {
+ DMUB_DCN31_REGS()
+ DMCUB_INTERNAL_REGS()
+ },
+#undef DMUB_SR
+
+#define DMUB_SF(reg, field) FD_MASK(reg, field),
+ { DMUB_DCN31_FIELDS() },
+#undef DMUB_SF
+
+#define DMUB_SF(reg, field) FD_SHIFT(reg, field),
+ { DMUB_DCN31_FIELDS() },
+#undef DMUB_SF
+};
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn316.h b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn316.h
new file mode 100644
index 000000000000..9e7d109129ea
--- /dev/null
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_dcn316.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2021 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: AMD
+ *
+ */
+
+#ifndef _DMUB_DCN316_H_
+#define _DMUB_DCN316_H_
+
+#include "dmub_dcn31.h"
+
+extern const struct dmub_srv_dcn31_regs dmub_srv_dcn316_regs;
+
+#endif /* _DMUB_DCN316_H_ */
diff --git a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
index 9280f2abd973..66db5e538c7f 100644
--- a/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dmub/src/dmub_srv.c
@@ -32,6 +32,8 @@
#include "dmub_dcn302.h"
#include "dmub_dcn303.h"
#include "dmub_dcn31.h"
+#include "dmub_dcn315.h"
+#include "dmub_dcn316.h"
#include "os_types.h"
/*
* Note: the DMUB service is standalone. No additional headers should be
@@ -220,7 +222,14 @@ static bool dmub_srv_hw_setup(struct dmub_srv *dmub, enum dmub_asic asic)
case DMUB_ASIC_DCN31:
case DMUB_ASIC_DCN31B:
- dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
+ case DMUB_ASIC_DCN315:
+ case DMUB_ASIC_DCN316:
+ if (asic == DMUB_ASIC_DCN315)
+ dmub->regs_dcn31 = &dmub_srv_dcn315_regs;
+ else if (asic == DMUB_ASIC_DCN316)
+ dmub->regs_dcn31 = &dmub_srv_dcn316_regs;
+ else
+ dmub->regs_dcn31 = &dmub_srv_dcn31_regs;
funcs->reset = dmub_dcn31_reset;
funcs->reset_release = dmub_dcn31_reset_release;
funcs->backdoor_load = dmub_dcn31_backdoor_load;
diff --git a/drivers/gpu/drm/amd/display/include/bios_parser_types.h b/drivers/gpu/drm/amd/display/include/bios_parser_types.h
index b8ffb216ebc4..cf4027cc3f4c 100644
--- a/drivers/gpu/drm/amd/display/include/bios_parser_types.h
+++ b/drivers/gpu/drm/amd/display/include/bios_parser_types.h
@@ -152,10 +152,8 @@ struct bp_transmitter_control {
enum signal_type signal;
enum dc_color_depth color_depth; /* not used for DCE6.0 */
enum hpd_source_id hpd_sel; /* ucHPDSel, used for DCe6.0 */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum tx_ffe_id txffe_sel; /* used for DCN3 */
enum engine_id hpo_engine_id; /* used for DCN3 */
-#endif
struct graphics_object_id connector_obj_id;
/* symClock; in 10kHz, pixel clock, in HDMI deep color mode, it should
* be pixel clock * deep_color_ratio (in KHz)
diff --git a/drivers/gpu/drm/amd/display/include/dal_asic_id.h b/drivers/gpu/drm/amd/display/include/dal_asic_id.h
index e4a2dfacab4c..310f8779db67 100644
--- a/drivers/gpu/drm/amd/display/include/dal_asic_id.h
+++ b/drivers/gpu/drm/amd/display/include/dal_asic_id.h
@@ -212,6 +212,7 @@ enum {
#define ASICREV_IS_GREEN_SARDINE(eChipRev) ((eChipRev >= GREEN_SARDINE_A0) && (eChipRev < 0xFF))
#endif
#define DEVICE_ID_NV_13FE 0x13FE // CYAN_SKILLFISH
+#define DEVICE_ID_NV_143F 0x143F
#define FAMILY_VGH 144
#define DEVICE_ID_VGH_163F 0x163F
#define VANGOGH_A0 0x01
@@ -226,7 +227,6 @@ enum {
#endif
#define FAMILY_YELLOW_CARP 146
-
#define YELLOW_CARP_A0 0x01
#define YELLOW_CARP_B0 0x20
#define YELLOW_CARP_UNKNOWN 0xFF
@@ -235,6 +235,17 @@ enum {
#define ASICREV_IS_YELLOW_CARP(eChipRev) ((eChipRev >= YELLOW_CARP_A0) && (eChipRev < YELLOW_CARP_UNKNOWN))
#endif
+#define AMDGPU_FAMILY_GC_10_3_6 149
+#define GC_10_3_6_A0 0x01
+#define GC_10_3_6_UNKNOWN 0xFF
+
+#define ASICREV_IS_GC_10_3_6(eChipRev) ((eChipRev >= GC_10_3_6_A0) && (eChipRev < GC_10_3_6_UNKNOWN))
+
+#define AMDGPU_FAMILY_GC_10_3_7 151
+#define GC_10_3_7_A0 0x01
+#define GC_10_3_7_UNKNOWN 0xFF
+
+#define ASICREV_IS_GC_10_3_7(eChipRev) ((eChipRev >= GC_10_3_7_A0) && (eChipRev < GC_10_3_7_UNKNOWN))
/*
* ASIC chip ID
diff --git a/drivers/gpu/drm/amd/display/include/dal_types.h b/drivers/gpu/drm/amd/display/include/dal_types.h
index 012b7c61798c..bf9085fc5105 100644
--- a/drivers/gpu/drm/amd/display/include/dal_types.h
+++ b/drivers/gpu/drm/amd/display/include/dal_types.h
@@ -57,6 +57,8 @@ enum dce_version {
DCN_VERSION_3_02,
DCN_VERSION_3_03,
DCN_VERSION_3_1,
+ DCN_VERSION_3_15,
+ DCN_VERSION_3_16,
DCN_VERSION_MAX
};
diff --git a/drivers/gpu/drm/amd/display/include/ddc_service_types.h b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
index a2b80514d83e..20a3d4e23f66 100644
--- a/drivers/gpu/drm/amd/display/include/ddc_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/ddc_service_types.h
@@ -34,8 +34,13 @@
#define DP_BRANCH_DEVICE_ID_90CC24 0x90CC24
#define DP_BRANCH_DEVICE_ID_00E04C 0x00E04C
#define DP_BRANCH_DEVICE_ID_006037 0x006037
+#define DP_BRANCH_DEVICE_ID_001CF8 0x001CF8
+#define DP_BRANCH_HW_REV_10 0x10
+#define DP_BRANCH_HW_REV_20 0x20
#define DP_DEVICE_ID_38EC11 0x38EC11
+#define DP_FORCE_PSRSU_CAPABILITY 0x40F
+
enum ddc_result {
DDC_RESULT_UNKNOWN = 0,
DDC_RESULT_SUCESSFULL,
@@ -61,6 +66,7 @@ enum ddc_service_type {
struct display_sink_capability {
/* dongle type (DP converter, CV smart dongle) */
enum display_dongle_type dongle_type;
+ bool is_dongle_type_one;
/**********************************************************
capabilities going INTO SINK DEVICE (stream capabilities)
@@ -121,4 +127,9 @@ struct av_sync_data {
static const uint8_t DP_SINK_DEVICE_STR_ID_1[] = {7, 1, 8, 7, 3, 0};
static const uint8_t DP_SINK_DEVICE_STR_ID_2[] = {7, 1, 8, 7, 5, 0};
+static const u8 DP_SINK_BRANCH_DEV_NAME_7580[] = "7580\x80u";
+
+/*MST Dock*/
+static const uint8_t SYNAPTICS_DEVICE_ID[] = "SYNA";
+
#endif /* __DAL_DDC_SERVICE_TYPES_H__ */
diff --git a/drivers/gpu/drm/amd/display/include/dpcd_defs.h b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
index ffd0df1701e6..b2df07f9e91c 100644
--- a/drivers/gpu/drm/amd/display/include/dpcd_defs.h
+++ b/drivers/gpu/drm/amd/display/include/dpcd_defs.h
@@ -26,7 +26,7 @@
#ifndef __DAL_DPCD_DEFS_H__
#define __DAL_DPCD_DEFS_H__
-#include <drm/drm_dp_helper.h>
+#include <drm/display/drm_dp_helper.h>
#ifndef DP_SINK_HW_REVISION_START // can remove this once the define gets into linux drm_dp_helper.h
#define DP_SINK_HW_REVISION_START 0x409
#endif
@@ -144,14 +144,10 @@ enum dpcd_training_patterns {
DPCD_TRAINING_PATTERN_1,
DPCD_TRAINING_PATTERN_2,
DPCD_TRAINING_PATTERN_3,
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DPCD_TRAINING_PATTERN_4 = 7,
DPCD_128b_132b_TPS1 = 1,
DPCD_128b_132b_TPS2 = 2,
DPCD_128b_132b_TPS2_CDS = 3,
-#else
- DPCD_TRAINING_PATTERN_4 = 7
-#endif
};
/* This enum is for use with PsrSinkPsrStatus.bits.sinkSelfRefreshStatus
diff --git a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
index dd974c428d23..bc96d0211360 100644
--- a/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
+++ b/drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h
@@ -419,28 +419,6 @@ struct integrated_info {
struct edp_info edp2_info;
};
-/**
-* Power source ids.
-*/
-enum power_source {
- POWER_SOURCE_AC = 0,
- POWER_SOURCE_DC,
- POWER_SOURCE_LIMITED_POWER,
- POWER_SOURCE_LIMITED_POWER_2,
- POWER_SOURCE_MAX
-};
-
-struct bios_event_info {
- uint32_t thermal_state;
- uint32_t backlight_level;
- enum power_source powerSource;
- bool has_thermal_state_changed;
- bool has_power_source_changed;
- bool has_forced_mode_changed;
- bool forced_mode;
- bool backlight_changed;
-};
-
/*
* DFS-bypass flag
*/
diff --git a/drivers/gpu/drm/amd/display/include/grph_object_defs.h b/drivers/gpu/drm/amd/display/include/grph_object_defs.h
index 84b299ff500a..05ba188a7c3b 100644
--- a/drivers/gpu/drm/amd/display/include/grph_object_defs.h
+++ b/drivers/gpu/drm/amd/display/include/grph_object_defs.h
@@ -140,7 +140,6 @@ enum sync_source {
SYNC_SOURCE_DUAL_GPU_PIN
};
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum tx_ffe_id {
TX_FFE0 = 0,
TX_FFE1,
@@ -150,7 +149,6 @@ enum tx_ffe_id {
TX_FFE_PreShoot_Only,
TX_FFE_No_FFE,
};
-#endif
/* connector sizes in millimeters - from BiosParserTypes.hpp */
#define CONNECTOR_SIZE_DVI 40
diff --git a/drivers/gpu/drm/amd/display/include/grph_object_id.h b/drivers/gpu/drm/amd/display/include/grph_object_id.h
index 01775417cf4b..c6bbd262f1ac 100644
--- a/drivers/gpu/drm/amd/display/include/grph_object_id.h
+++ b/drivers/gpu/drm/amd/display/include/grph_object_id.h
@@ -162,6 +162,7 @@ enum connector_id {
CONNECTOR_ID_MXM = 21,
CONNECTOR_ID_WIRELESS = 22,
CONNECTOR_ID_MIRACAST = 23,
+ CONNECTOR_ID_USBC = 24,
CONNECTOR_ID_VIRTUAL = 100
};
@@ -184,14 +185,12 @@ enum engine_id {
ENGINE_ID_DACA,
ENGINE_ID_DACB,
ENGINE_ID_VCE, /* wireless display pseudo-encoder */
-#if defined(CONFIG_DRM_AMD_DC_DCN)
ENGINE_ID_HPO_0,
ENGINE_ID_HPO_1,
ENGINE_ID_HPO_DP_0,
ENGINE_ID_HPO_DP_1,
ENGINE_ID_HPO_DP_2,
ENGINE_ID_HPO_DP_3,
-#endif
ENGINE_ID_VIRTUAL,
ENGINE_ID_COUNT,
diff --git a/drivers/gpu/drm/amd/display/include/link_service_types.h b/drivers/gpu/drm/amd/display/include/link_service_types.h
index 424bccd36434..447a56286dd0 100644
--- a/drivers/gpu/drm/amd/display/include/link_service_types.h
+++ b/drivers/gpu/drm/amd/display/include/link_service_types.h
@@ -74,12 +74,10 @@ enum link_training_result {
LINK_TRAINING_LINK_LOSS,
/* Abort link training (because sink unplugged) */
LINK_TRAINING_ABORT,
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DP_128b_132b_LT_FAILED,
DP_128b_132b_MAX_LOOP_COUNT_REACHED,
DP_128b_132b_CHANNEL_EQ_DONE_TIMEOUT,
DP_128b_132b_CDS_DONE_TIMEOUT,
-#endif
};
enum lttpr_mode {
@@ -99,23 +97,19 @@ struct link_training_settings {
enum dc_pre_emphasis *pre_emphasis;
enum dc_post_cursor2 *post_cursor2;
bool should_set_fec_ready;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
/* TODO - factor lane_settings out because it changes during LT */
union dc_dp_ffe_preset *ffe_preset;
-#endif
uint16_t cr_pattern_time;
uint16_t eq_pattern_time;
uint16_t cds_pattern_time;
enum dc_dp_training_pattern pattern_for_cr;
enum dc_dp_training_pattern pattern_for_eq;
-#if defined(CONFIG_DRM_AMD_DC_DCN)
enum dc_dp_training_pattern pattern_for_cds;
uint32_t eq_wait_time_limit;
uint8_t eq_loop_count_limit;
uint32_t cds_wait_time_limit;
-#endif
bool enhanced_framing;
enum lttpr_mode lttpr_mode;
@@ -161,7 +155,6 @@ enum dp_test_pattern {
DP_TEST_PATTERN_CP2520_2,
DP_TEST_PATTERN_HBR2_COMPLIANCE_EYE = DP_TEST_PATTERN_CP2520_2,
DP_TEST_PATTERN_CP2520_3,
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DP_TEST_PATTERN_128b_132b_TPS1,
DP_TEST_PATTERN_128b_132b_TPS2,
DP_TEST_PATTERN_PRBS9,
@@ -171,20 +164,15 @@ enum dp_test_pattern {
DP_TEST_PATTERN_PRBS31,
DP_TEST_PATTERN_264BIT_CUSTOM,
DP_TEST_PATTERN_SQUARE_PULSE,
-#endif
/* Link Training Patterns */
DP_TEST_PATTERN_TRAINING_PATTERN1,
DP_TEST_PATTERN_TRAINING_PATTERN2,
DP_TEST_PATTERN_TRAINING_PATTERN3,
DP_TEST_PATTERN_TRAINING_PATTERN4,
-#if defined(CONFIG_DRM_AMD_DC_DCN)
DP_TEST_PATTERN_128b_132b_TPS1_TRAINING_MODE,
DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE,
DP_TEST_PATTERN_PHY_PATTERN_END = DP_TEST_PATTERN_128b_132b_TPS2_TRAINING_MODE,
-#else
- DP_TEST_PATTERN_PHY_PATTERN_END = DP_TEST_PATTERN_TRAINING_PATTERN4,
-#endif
/* link test patterns*/
DP_TEST_PATTERN_COLOR_SQUARES,
diff --git a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
index bd1d1dc93629..03fa63d56fa6 100644
--- a/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
+++ b/drivers/gpu/drm/amd/display/modules/freesync/freesync.c
@@ -46,6 +46,10 @@
/* Number of consecutive frames to check before entering/exiting fixed refresh */
#define FIXED_REFRESH_ENTER_FRAME_COUNT 5
#define FIXED_REFRESH_EXIT_FRAME_COUNT 10
+/* Flip interval workaround constants */
+#define VSYNCS_BETWEEN_FLIP_THRESHOLD 2
+#define FREESYNC_CONSEC_FLIP_AFTER_VSYNC 5
+#define FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US 500
struct core_freesync {
struct mod_freesync public;
@@ -466,6 +470,41 @@ static void apply_fixed_refresh(struct core_freesync *core_freesync,
}
}
+static void determine_flip_interval_workaround_req(struct mod_vrr_params *in_vrr,
+ unsigned int curr_time_stamp_in_us)
+{
+ in_vrr->flip_interval.vsync_to_flip_in_us = curr_time_stamp_in_us -
+ in_vrr->flip_interval.v_update_timestamp_in_us;
+
+ /* Determine conditions for stopping workaround */
+ if (in_vrr->flip_interval.flip_interval_workaround_active &&
+ in_vrr->flip_interval.vsyncs_between_flip < VSYNCS_BETWEEN_FLIP_THRESHOLD &&
+ in_vrr->flip_interval.vsync_to_flip_in_us > FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) {
+ in_vrr->flip_interval.flip_interval_detect_counter = 0;
+ in_vrr->flip_interval.program_flip_interval_workaround = true;
+ in_vrr->flip_interval.flip_interval_workaround_active = false;
+ } else {
+ /* Determine conditions for starting workaround */
+ if (in_vrr->flip_interval.vsyncs_between_flip >= VSYNCS_BETWEEN_FLIP_THRESHOLD &&
+ in_vrr->flip_interval.vsync_to_flip_in_us < FREESYNC_VSYNC_TO_FLIP_DELTA_IN_US) {
+ /* Increase flip interval counter we have 2 vsyncs between flips and
+ * vsync to flip interval is less than 500us
+ */
+ in_vrr->flip_interval.flip_interval_detect_counter++;
+ if (in_vrr->flip_interval.flip_interval_detect_counter > FREESYNC_CONSEC_FLIP_AFTER_VSYNC) {
+ /* Start workaround if we detect 5 consecutive instances of the above case */
+ in_vrr->flip_interval.program_flip_interval_workaround = true;
+ in_vrr->flip_interval.flip_interval_workaround_active = true;
+ }
+ } else {
+ /* Reset the flip interval counter if we condition is no longer met */
+ in_vrr->flip_interval.flip_interval_detect_counter = 0;
+ }
+ }
+
+ in_vrr->flip_interval.vsyncs_between_flip = 0;
+}
+
static bool vrr_settings_require_update(struct core_freesync *core_freesync,
struct mod_freesync_config *in_config,
unsigned int min_refresh_in_uhz,
@@ -1179,6 +1218,9 @@ void mod_freesync_handle_preflip(struct mod_freesync *mod_freesync,
in_out_vrr);
}
+ determine_flip_interval_workaround_req(in_out_vrr,
+ curr_time_stamp_in_us);
+
}
}
@@ -1187,6 +1229,8 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
struct mod_vrr_params *in_out_vrr)
{
struct core_freesync *core_freesync = NULL;
+ unsigned int cur_timestamp_in_us;
+ unsigned long long cur_tick;
if ((mod_freesync == NULL) || (stream == NULL) || (in_out_vrr == NULL))
return;
@@ -1196,6 +1240,36 @@ void mod_freesync_handle_v_update(struct mod_freesync *mod_freesync,
if (in_out_vrr->supported == false)
return;
+ cur_tick = dm_get_timestamp(core_freesync->dc->ctx);
+ cur_timestamp_in_us = (unsigned int)
+ div_u64(dm_get_elapse_time_in_ns(core_freesync->dc->ctx, cur_tick, 0), 1000);
+
+ in_out_vrr->flip_interval.vsyncs_between_flip++;
+ in_out_vrr->flip_interval.v_update_timestamp_in_us = cur_timestamp_in_us;
+
+ if (in_out_vrr->state == VRR_STATE_ACTIVE_VARIABLE &&
+ (in_out_vrr->flip_interval.flip_interval_workaround_active ||
+ (!in_out_vrr->flip_interval.flip_interval_workaround_active &&
+ in_out_vrr->flip_interval.program_flip_interval_workaround))) {
+ // set freesync vmin vmax to nominal for workaround
+ in_out_vrr->adjust.v_total_min =
+ mod_freesync_calc_v_total_from_refresh(
+ stream, in_out_vrr->max_refresh_in_uhz);
+ in_out_vrr->adjust.v_total_max =
+ in_out_vrr->adjust.v_total_min;
+ in_out_vrr->flip_interval.program_flip_interval_workaround = false;
+ in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = true;
+ return;
+ }
+
+ if (in_out_vrr->state != VRR_STATE_ACTIVE_VARIABLE &&
+ in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup) {
+ in_out_vrr->flip_interval.do_flip_interval_workaround_cleanup = false;
+ in_out_vrr->flip_interval.flip_interval_detect_counter = 0;
+ in_out_vrr->flip_interval.vsyncs_between_flip = 0;
+ in_out_vrr->flip_interval.vsync_to_flip_in_us = 0;
+ }
+
/* Below the Range Logic */
/* Only execute if in fullscreen mode */
@@ -1302,7 +1376,7 @@ unsigned long long mod_freesync_calc_field_rate_from_timing(
bool mod_freesync_is_valid_range(uint32_t min_refresh_cap_in_uhz,
uint32_t max_refresh_cap_in_uhz,
- uint32_t nominal_field_rate_in_uhz)
+ uint32_t nominal_field_rate_in_uhz)
{
/* Typically nominal refresh calculated can have some fractional part.
diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c
index 3e81850a7ffe..5e01c6e24cbc 100644
--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c
+++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.c
@@ -251,6 +251,33 @@ out:
return status;
}
+static enum mod_hdcp_status update_display_adjustments(struct mod_hdcp *hdcp,
+ struct mod_hdcp_display *display,
+ struct mod_hdcp_display_adjustment *adj)
+{
+ enum mod_hdcp_status status = MOD_HDCP_STATUS_NOT_IMPLEMENTED;
+
+ if (is_in_authenticated_states(hdcp) &&
+ is_dp_mst_hdcp(hdcp) &&
+ display->adjust.disable == true &&
+ adj->disable == false) {
+ display->adjust.disable = false;
+ if (is_hdcp1(hdcp))
+ status = mod_hdcp_hdcp1_enable_dp_stream_encryption(hdcp);
+ else if (is_hdcp2(hdcp))
+ status = mod_hdcp_hdcp2_enable_dp_stream_encryption(hdcp);
+
+ if (status != MOD_HDCP_STATUS_SUCCESS)
+ display->adjust.disable = true;
+ }
+
+ if (status == MOD_HDCP_STATUS_SUCCESS &&
+ memcmp(adj, &display->adjust,
+ sizeof(struct mod_hdcp_display_adjustment)) != 0)
+ status = MOD_HDCP_STATUS_NOT_IMPLEMENTED;
+
+ return status;
+}
/*
* Implementation of functions in mod_hdcp.h
*/
@@ -391,7 +418,7 @@ out:
return status;
}
-enum mod_hdcp_status mod_hdcp_update_authentication(struct mod_hdcp *hdcp,
+enum mod_hdcp_status mod_hdcp_update_display(struct mod_hdcp *hdcp,
uint8_t index,
struct mod_hdcp_link_adjustment *link_adjust,
struct mod_hdcp_display_adjustment *display_adjust,
@@ -419,6 +446,15 @@ enum mod_hdcp_status mod_hdcp_update_authentication(struct mod_hdcp *hdcp,
goto out;
}
+ if (memcmp(link_adjust, &hdcp->connection.link.adjust,
+ sizeof(struct mod_hdcp_link_adjustment)) == 0 &&
+ memcmp(display_adjust, &display->adjust,
+ sizeof(struct mod_hdcp_display_adjustment)) != 0) {
+ status = update_display_adjustments(hdcp, display, display_adjust);
+ if (status != MOD_HDCP_STATUS_NOT_IMPLEMENTED)
+ goto out;
+ }
+
/* stop current authentication */
status = reset_authentication(hdcp, output);
if (status != MOD_HDCP_STATUS_SUCCESS)
diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h
index 399fbca8947b..55c7d873175f 100644
--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h
+++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp.h
@@ -29,8 +29,8 @@
#include "mod_hdcp.h"
#include "hdcp_log.h"
-#include <drm/drm_hdcp.h>
-#include <drm/drm_dp_helper.h>
+#include <drm/display/drm_dp_helper.h>
+#include <drm/display/drm_hdcp_helper.h>
enum mod_hdcp_trans_input_result {
UNKNOWN = 0,
@@ -445,6 +445,14 @@ static inline uint8_t is_in_hdcp2_dp_states(struct mod_hdcp *hdcp)
current_state(hdcp) <= HDCP2_DP_STATE_END);
}
+static inline uint8_t is_in_authenticated_states(struct mod_hdcp *hdcp)
+{
+ return (current_state(hdcp) == D1_A4_AUTHENTICATED ||
+ current_state(hdcp) == H1_A45_AUTHENTICATED ||
+ current_state(hdcp) == D2_A5_AUTHENTICATED ||
+ current_state(hdcp) == H2_A5_AUTHENTICATED);
+}
+
static inline uint8_t is_hdcp1(struct mod_hdcp *hdcp)
{
return (is_in_hdcp1_states(hdcp) || is_in_hdcp1_dp_states(hdcp));
diff --git a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c
index 6ec918af3bff..1ddb4f5eac8e 100644
--- a/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c
+++ b/drivers/gpu/drm/amd/display/modules/hdcp/hdcp1_execution.c
@@ -497,9 +497,9 @@ enum mod_hdcp_status mod_hdcp_hdcp1_execution(struct mod_hdcp *hdcp,
return status;
}
-extern enum mod_hdcp_status mod_hdcp_hdcp1_dp_execution(struct mod_hdcp *hdcp,
- struct mod_hdcp_event_context *event_ctx,
- struct mod_hdcp_transition_input_hdcp1 *input)
+enum mod_hdcp_status mod_hdcp_hdcp1_dp_execution(struct mod_hdcp *hdcp,
+ struct mod_hdcp_event_context *event_ctx,
+ struct mod_hdcp_transition_input_hdcp1 *input)
{
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
index 75a158a2514c..cf6bc9446244 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_freesync.h
@@ -105,6 +105,16 @@ struct mod_vrr_params_fixed_refresh {
uint32_t frame_counter;
};
+struct mod_vrr_params_flip_interval {
+ bool flip_interval_workaround_active;
+ bool program_flip_interval_workaround;
+ bool do_flip_interval_workaround_cleanup;
+ uint32_t flip_interval_detect_counter;
+ uint32_t vsyncs_between_flip;
+ uint32_t vsync_to_flip_in_us;
+ uint32_t v_update_timestamp_in_us;
+};
+
struct mod_vrr_params {
bool supported;
bool send_info_frame;
@@ -121,6 +131,8 @@ struct mod_vrr_params {
struct mod_vrr_params_fixed_refresh fixed;
struct mod_vrr_params_btr btr;
+
+ struct mod_vrr_params_flip_interval flip_interval;
};
struct mod_freesync *mod_freesync_create(struct dc *dc);
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h
index f7420c3f5672..3348bb97ef81 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_hdcp.h
@@ -294,7 +294,7 @@ enum mod_hdcp_status mod_hdcp_remove_display(struct mod_hdcp *hdcp,
uint8_t index, struct mod_hdcp_output *output);
/* called per display to apply new authentication adjustment */
-enum mod_hdcp_status mod_hdcp_update_authentication(struct mod_hdcp *hdcp,
+enum mod_hdcp_status mod_hdcp_update_display(struct mod_hdcp *hdcp,
uint8_t index,
struct mod_hdcp_link_adjustment *link_adjust,
struct mod_hdcp_display_adjustment *display_adjust,
diff --git a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
index 1ab813b4fd14..1d8b746b02f2 100644
--- a/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
+++ b/drivers/gpu/drm/amd/display/modules/inc/mod_info_packet.h
@@ -34,7 +34,8 @@ struct dc_info_packet;
struct mod_vrr_params;
void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
- struct dc_info_packet *info_packet);
+ struct dc_info_packet *info_packet,
+ enum dc_color_space cs);
void mod_build_hf_vsif_infopacket(const struct dc_stream_state *stream,
struct dc_info_packet *info_packet);
diff --git a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
index 57f198de5e2c..79bc207415bc 100644
--- a/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
+++ b/drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c
@@ -100,7 +100,8 @@ enum vsc_packet_revision {
//PB7 = MD0
#define MASK_VTEM_MD0__VRR_EN 0x01
#define MASK_VTEM_MD0__M_CONST 0x02
-#define MASK_VTEM_MD0__RESERVED2 0x0C
+#define MASK_VTEM_MD0__QMS_EN 0x04
+#define MASK_VTEM_MD0__RESERVED2 0x08
#define MASK_VTEM_MD0__FVA_FACTOR_M1 0xF0
//MD1
@@ -109,7 +110,7 @@ enum vsc_packet_revision {
//MD2
#define MASK_VTEM_MD2__BASE_REFRESH_RATE_98 0x03
#define MASK_VTEM_MD2__RB 0x04
-#define MASK_VTEM_MD2__RESERVED3 0xF8
+#define MASK_VTEM_MD2__NEXT_TFR 0xF8
//MD3
#define MASK_VTEM_MD3__BASE_REFRESH_RATE_07 0xFF
@@ -130,7 +131,8 @@ enum ColorimetryYCCDP {
};
void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
- struct dc_info_packet *info_packet)
+ struct dc_info_packet *info_packet,
+ enum dc_color_space cs)
{
unsigned int vsc_packet_revision = vsc_packet_undefined;
unsigned int i;
@@ -331,13 +333,13 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
/* Set Colorimetry format based on pixel encoding */
switch (stream->timing.pixel_encoding) {
case PIXEL_ENCODING_RGB:
- if ((stream->output_color_space == COLOR_SPACE_SRGB) ||
- (stream->output_color_space == COLOR_SPACE_SRGB_LIMITED))
+ if ((cs == COLOR_SPACE_SRGB) ||
+ (cs == COLOR_SPACE_SRGB_LIMITED))
colorimetryFormat = ColorimetryRGB_DP_sRGB;
- else if (stream->output_color_space == COLOR_SPACE_ADOBERGB)
+ else if (cs == COLOR_SPACE_ADOBERGB)
colorimetryFormat = ColorimetryRGB_DP_AdobeRGB;
- else if ((stream->output_color_space == COLOR_SPACE_2020_RGB_FULLRANGE) ||
- (stream->output_color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE))
+ else if ((cs == COLOR_SPACE_2020_RGB_FULLRANGE) ||
+ (cs == COLOR_SPACE_2020_RGB_LIMITEDRANGE))
colorimetryFormat = ColorimetryRGB_DP_ITU_R_BT2020RGB;
break;
@@ -347,13 +349,13 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
/* Note: xvYCC probably not supported correctly here on DP since colorspace translation
* loses distinction between BT601 vs xvYCC601 in translation
*/
- if (stream->output_color_space == COLOR_SPACE_YCBCR601)
+ if (cs == COLOR_SPACE_YCBCR601)
colorimetryFormat = ColorimetryYCC_DP_ITU601;
- else if (stream->output_color_space == COLOR_SPACE_YCBCR709)
+ else if (cs == COLOR_SPACE_YCBCR709)
colorimetryFormat = ColorimetryYCC_DP_ITU709;
- else if (stream->output_color_space == COLOR_SPACE_ADOBERGB)
+ else if (cs == COLOR_SPACE_ADOBERGB)
colorimetryFormat = ColorimetryYCC_DP_AdobeYCC;
- else if (stream->output_color_space == COLOR_SPACE_2020_YCBCR)
+ else if (cs == COLOR_SPACE_2020_YCBCR)
colorimetryFormat = ColorimetryYCC_DP_ITU2020YCbCr;
break;
@@ -391,8 +393,8 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,
}
/* all YCbCr are always limited range */
- if ((stream->output_color_space == COLOR_SPACE_SRGB_LIMITED) ||
- (stream->output_color_space == COLOR_SPACE_2020_RGB_LIMITEDRANGE) ||
+ if ((cs == COLOR_SPACE_SRGB_LIMITED) ||
+ (cs == COLOR_SPACE_2020_RGB_LIMITEDRANGE) ||
(pixelEncoding != 0x0)) {
info_packet->sb[17] |= 0x80; /* DB17 bit 7 set to 1 for CEA timing. */
}
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
index 2b00f334e93d..97928d4c3b9a 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.c
@@ -784,3 +784,41 @@ bool dmcu_load_iram(struct dmcu *dmcu,
return result;
}
+/*
+ * is_psr_su_specific_panel() - check if sink is AMD vendor-specific PSR-SU
+ * supported eDP device.
+ *
+ * @link: dc link pointer
+ *
+ * Return: true if AMDGPU vendor specific PSR-SU eDP panel
+ */
+bool is_psr_su_specific_panel(struct dc_link *link)
+{
+ if (link->dpcd_caps.edp_rev >= DP_EDP_14) {
+ if (link->dpcd_caps.psr_info.psr_version >= DP_PSR2_WITH_Y_COORD_ET_SUPPORTED)
+ return true;
+ /*
+ * Some panels will report PSR capabilities over additional DPCD bits.
+ * Such panels are approved despite reporting only PSR v3, as long as
+ * the additional bits are reported.
+ */
+ if (link->dpcd_caps.psr_info.psr_version < DP_PSR2_WITH_Y_COORD_IS_SUPPORTED)
+ return false;
+
+ if (link->dpcd_caps.sink_dev_id == DP_BRANCH_DEVICE_ID_001CF8) {
+ /*
+ * FIXME:
+ * This is the temporary workaround to disable PSRSU when system turned on
+ * DSC function on the sepcific sink. Once the PSRSU + DSC is fixed, this
+ * condition should be removed.
+ */
+ if (link->dpcd_caps.dsc_caps.dsc_basic_caps.fields.dsc_support.DSC_SUPPORT)
+ return false;
+
+ if (link->dpcd_caps.psr_info.force_psrsu_cap == 0x1)
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
index 2a9f8e2d8080..1a634d8c78c5 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
+++ b/drivers/gpu/drm/amd/display/modules/power/power_helpers.h
@@ -52,4 +52,5 @@ bool dmub_init_abm_config(struct resource_pool *res_pool,
struct dmcu_iram_parameters params,
unsigned int inst);
+bool is_psr_su_specific_panel(struct dc_link *link);
#endif /* MODULES_POWER_POWER_HELPERS_H_ */